diff --git a/.gitignore b/.gitignore index 197d0f5e9..a6f721188 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ node_modules/ utPLSQL_latest_release/ utPLSQL-cli/ development/env.sh +development/*.jar *.log # exclusions based on artifacts created via actions documented in CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0e82a4ce4..ffb8bba69 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -89,14 +89,18 @@ export CONNECTION_STR=127.0.0.1:1521/xe # Adjust the connect string export ORACLE_PWD=oracle # Adjust your local SYS password ``` +### Download Oracle JDBC drivers + +Download `ojdbc8-xxx.jar` and `orai18n-xxx.jar` from [Oracle](https://www.oracle.com/technetwork/database/features/jdbc/jdbc-ucp-122-3110062.html). +Place them in `development` directory of the project. + + ### Download utPLSQL release sources and utplsq-cli The below script is fetching latest release version from utPLSQL repository. Latest release version is used for self-testing. ```bash development/refresh_sources.sh ``` -> **Important notice:** -> You'll have to provide the ojdbc.jar in the folder utPLSQL-cli/lib manually due to Oracle licensing restrictions. ### Setup local database for utPLSQL development diff --git a/development/refresh_sources.sh b/development/refresh_sources.sh index e051787a1..9474c3553 100755 --- a/development/refresh_sources.sh +++ b/development/refresh_sources.sh @@ -16,3 +16,4 @@ curl -Lk -o utPLSQL-cli.zip https://github.com/utPLSQL/utPLSQL-cli/releases/down # unzip utPLSQL-cli and remove the zip file unzip utPLSQL-cli.zip && chmod u+x utPLSQL-cli/bin/utplsql && rm utPLSQL-cli.zip +cp development/*.jar utPLSQL-cli/lib/ diff --git a/development/releasing.md b/development/releasing.md index added5a92..7c8d779ef 100644 --- a/development/releasing.md +++ b/development/releasing.md @@ -9,7 +9,8 @@ To create a release: - wait for th build to complete successfully - merge the release branch to master and wait for master build to complete successfully - create a release from the master branch using [github releases page](https://github.com/utPLSQL/utPLSQL/releases) and populate release description using information found on the issues and pull requests since previous release. - To find issues closed after certain date use [advanced filters](https://help.github.com/articles/searching-issues-and-pull-requests/#search-by-open-or-closed-state) + To find issues closed after certain date use [advanced filters](https://help.github.com/articles/searching-issues-and-pull-requests/#search-by-open-or-closed-state). + Example: [`is:issue closed:>2018-07-22`](https://github.com/utPLSQL/utPLSQL/issues?utf8=%E2%9C%93&q=is%3Aissue+closed%3A%3E2018-07-22+) The following will happen: - build executed on branch `release/vX.Y.Z-[something]` updates files `sonar-project.properties`, `VERSION` with project version derived from the release branch name diff --git a/docs/index.md b/docs/index.md index 693c8076b..b92a78688 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,6 +10,7 @@ The framework follows industry standards and best patterns of modern Unit Testin - [Expectations](userguide/expectations.md) - [Advanced data comparison](userguide/advanced_data_comparison.md) - [Running unit tests](userguide/running-unit-tests.md) + - [Querying for test suites](userguide/querying_suites.md) - [Testing best pracitces](userguide/best-practices.md) - [Upgrade utPLSQL](userguide/upgrade.md) - Reporting diff --git a/docs/userguide/querying_suites.md b/docs/userguide/querying_suites.md new file mode 100644 index 000000000..1b1c64185 --- /dev/null +++ b/docs/userguide/querying_suites.md @@ -0,0 +1,83 @@ +# Qyerying for test suites + + +## Obtaining information about suites + +utPLSQL framework provides ability to read inforamtion about unit test suites that exist in a schema. + +Pipelined table function `ut_runner.get_suites_info(a_owner, a_package_name)` allows you to retrieve information about: + +- all suites that exist in a given user/schema +- individual test suite pacakage + +Querying the data from function provides the follwing details: + +- `object_owner` - the owner of test suite packages +- `object_name` - the name of test suite package +- `item_name` - the name of suite/test +- `item_description` - the description of suite/suite item +- `item_type` - the type of item (UT_SUITE/UT_SUITE_CONTEXT/UT_TEST/UT_LOGICAL_SUITE) +- `item_line_no` - line_number where annotation identifying the item exists +- `path` - suitepath of the item +- `disabled_flag` - (0/1) indicator if item is disabled by --%disabled annotation + +To get list of all test suites in current schema +```sql +select * from table(ut_runner.get_suites_info()) where item_type = 'UT_SUITE'; +``` + +To get list of all tests for test suite `TEST_STUFF` in current user schema +```sql +select * from table(ut_runner.get_suites_info(USER, 'TEST_STUFF')) where item_type = 'UT_TEST'; +``` + +To get a full information about suite `TEST_STUFF` including suite description, all contexts and tests in a suite +```sql +select * from table(ut_runner.get_suites_info(USER, 'TEST_STUFF')) where item_type = 'UT_TEST'; +``` + +## Checking if schema contains tests + +Function `ut_runner.has_suites(a_owner)` returns boolean value indicating if given schema contains test suites. + +Example: +```sql +begin + if ut_runner.has_suites(USER) then + dbms_output.put_line( 'User '||USER||' owns test suites' ); + else + dbms_output.put_line( 'User '||USER||' does not own test suites' ); + end if; +end; +``` + +## Checking if package is a test suite + +Function `ut_runner.is_suite(a_owner, a_package_name) ` returns boolean value indicating if given package is a test suites. + +Example: +```sql +begin + if ut_runner.is_suite(USER,'TEST_STUFF') then + dbms_output.put_line( 'Package '||USER||'.TEST_STUFF is a test suite' ); + else + dbms_output.put_line( 'Package '||USER||'.TEST_STUFF is not a test suite' ); + end if; +end; +``` + +## Checking if procedure is a test within a suite + +Function `ut_runner.is_test(a_owner, a_package_name, a_procedure_name) ` returns boolean value indicating if given package is a test suites. + +Example: +```sql +begin + if ut_runner.is_test(USER,'TEST_STUFF','A_TEST_TO_CHECK_STUFF') then + dbms_output.put_line( 'Procedure '||USER||'.TEST_STUFF.A_TEST_TO_CHECK_STUFF is a test' ); + else + dbms_output.put_line( 'Procedure '||USER||'.TEST_STUFF.A_TEST_TO_CHECK_STUFF is not a test' ); + end if; +end; +``` + diff --git a/docs/userguide/running-unit-tests.md b/docs/userguide/running-unit-tests.md index 54116cf65..f680a2e38 100644 --- a/docs/userguide/running-unit-tests.md +++ b/docs/userguide/running-unit-tests.md @@ -1,12 +1,12 @@ # Running tests -The utPLSQL framework provides two main entry points to run unit tests from within the database: +utPLSQL framework provides two main entry points to run unit tests from within the database: - `ut.run` procedures and functions - `ut_runner.run` procedures These two entry points differ in purpose and behavior. -Most of the time you will want to use `ut.run` as `ut_runner` is designed for API integration and does not output the results to the screen directly. +Most of the time you will want to use `ut.run` as `ut_runner.run` is designed for API integration and does not display the results to the screen. # Running from CI servers and command line diff --git a/examples/RunDeveloperExamples.sql b/examples/RunDeveloperExamples.sql index ec4301e88..d34914b58 100644 --- a/examples/RunDeveloperExamples.sql +++ b/examples/RunDeveloperExamples.sql @@ -6,8 +6,6 @@ set linesize 1000 exec ut_ansiconsole_helper.color_enabled(true); --developer examples -prompt RunExampleComplexSuiteWithCustomReporter -@@developer_examples/RunExampleComplexSuiteWithCustomReporter.sql prompt RunExampleTestSuiteWithCustomReporter @@developer_examples/RunExampleTestSuiteWithCustomReporter.sql prompt RunExampleTestAnnotationsParsingTimeHugePackage diff --git a/examples/developer_examples/RunExampleComplexSuiteWithCustomReporter.sql b/examples/developer_examples/RunExampleComplexSuiteWithCustomReporter.sql deleted file mode 100644 index 1b9e94bfb..000000000 --- a/examples/developer_examples/RunExampleComplexSuiteWithCustomReporter.sql +++ /dev/null @@ -1,56 +0,0 @@ ---Shows how to create a test suite with the default reporter which is dbms_output ---No tables are used for this. ---Suite Management packages are when developed will make this easier. ---Clear Screen -Set Serveroutput On Size Unlimited format truncated -set echo off ---install the example unit test packages -@@ut_exampletest.pks -@@ut_exampletest.pkb -@@ut_exampletest2.pks -@@ut_exampletest2.pkb -@@ut_custom_reporter.tps -@@ut_custom_reporter.tpb - -declare - l_parent_suite ut_logical_suite; - l_suite ut_suite; - l_test ut_test; - l_reporter ut_output_reporter_base; - l_run ut_run; -begin - ut_event_manager.initialize(); - l_parent_suite := ut_logical_suite( a_object_owner=>null, a_object_name => null, a_name => 'complex_test_suite', a_path => null); - - l_suite := ut_suite(user, 'ut_exampletest'); - l_test := ut_test(user, 'ut_exampletest','ut_exAmpletest'); - l_test.description := 'Example test1'; - l_test.before_test_list := ut_executables(ut_executable(user, 'ut_exampletest','Setup',ut_utils.gc_before_test)); - l_test.after_test_list := ut_executables(ut_executable(user, 'ut_exampletest','tEardown',ut_utils.gc_after_test)); - - l_suite.add_item(l_test); - l_parent_suite.add_item(l_suite); - - - l_suite := ut_suite(user, 'ut_exampletest2'); - l_test := ut_test(user, 'UT_EXAMPLETEST2','UT_EXAMPLETEST'); - l_test.before_test_list := ut_executables(ut_executable(user, 'UT_EXAMPLETEST2','SETUP',ut_utils.gc_before_test)); - l_test.after_test_list := ut_executables(ut_executable(user, 'UT_EXAMPLETEST2','TEARDOWN',ut_utils.gc_after_test)); - - l_suite.add_item(l_test); - l_parent_suite.add_item(l_suite); - - -- provide a reporter to process results - l_reporter := ut_custom_reporter(a_tab_size => 2); - ut_event_manager.add_listener(l_reporter); - l_run := ut_run(ut_suite_items(l_parent_suite)); - l_run.do_execute(); - ut_event_manager.trigger_event(ut_utils.gc_finalize, l_run); - l_reporter.lines_to_dbms_output(); -end; -/ - -drop type ut_custom_reporter; -drop package ut_exampletest; -drop package ut_exampletest2; -exec dbms_session.reset_package; diff --git a/examples/developer_examples/RunExampleTestSuite.sql b/examples/developer_examples/RunExampleTestSuite.sql index a0a470e46..950450cd5 100644 --- a/examples/developer_examples/RunExampleTestSuite.sql +++ b/examples/developer_examples/RunExampleTestSuite.sql @@ -15,19 +15,21 @@ declare l_test ut_test; l_expectation ut_expectation_result; begin - l_suite := ut_suite(user, 'ut_exampletest'); + l_suite := ut_suite(user, 'ut_exampletest',a_line_no=>1); l_suite.description := 'Test Suite Name'; - l_test := ut_test(user, 'ut_exampletest','ut_exAmpletest'); + l_test := ut_test(user, 'ut_exampletest','ut_exAmpletest',a_line_no=>3); l_test.description := 'Example test1'; l_test.before_test_list := ut_executables(ut_executable(user, 'ut_exampletest','Setup',ut_utils.gc_before_test)); l_test.after_test_list := ut_executables(ut_executable(user, 'ut_exampletest','tEardown',ut_utils.gc_after_test)); - l_suite.add_item(l_test); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := l_test; - l_test := ut_test(user, 'UT_EXAMPLETEST2','ut_exAmpletest'); + l_test := ut_test(user, 'UT_EXAMPLETEST2','ut_exAmpletest',a_line_no=>6); l_test.description := 'Another example test'; l_test.before_test_list := ut_executables(ut_executable(user, 'UT_EXAMPLETEST2','SETUP',ut_utils.gc_before_test)); l_test.after_test_list := ut_executables(ut_executable(user, 'UT_EXAMPLETEST2','TEARDOWN',ut_utils.gc_after_test)); - l_suite.add_item(l_test); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := l_test; l_suite.do_execute(); diff --git a/examples/developer_examples/RunExampleTestSuiteWithCompositeReporter.sql b/examples/developer_examples/RunExampleTestSuiteWithCompositeReporter.sql index 4f9172510..f247e06db 100644 --- a/examples/developer_examples/RunExampleTestSuiteWithCompositeReporter.sql +++ b/examples/developer_examples/RunExampleTestSuiteWithCompositeReporter.sql @@ -12,7 +12,7 @@ set echo off PROMPT Runs test report using composite reporter declare - suite ut_logical_suite; + l_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_run ut_run; @@ -21,14 +21,16 @@ begin ut_event_manager.add_listener(l_doc_reporter); ut_event_manager.add_listener(l_tc_reporter); - suite := ut_suite(user, 'ut_exampletest'); - suite.description := 'Test Suite Name'; + l_suite := ut_suite(user, 'ut_exampletest',a_line_no=>1); + l_suite.description := 'Test Suite Name'; - suite.add_item(ut_test(user,'ut_exampletest','ut_exAmpletest')); - suite.add_item(ut_test(user, 'UT_EXAMPLETEST2','UT_EXAMPLETEST')); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut_test(user,'ut_exampletest','ut_exAmpletest',a_line_no=>3); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut_test(user, 'UT_EXAMPLETEST2','UT_EXAMPLETEST',a_line_no=>6); -- provide a reporter to process results - l_run := ut_run(ut_suite_items(suite)); + l_run := ut_run(ut_suite_items(l_suite)); l_run.do_execute(); ut_event_manager.trigger_event(ut_utils.gc_finalize, l_run); diff --git a/examples/developer_examples/RunExampleTestSuiteWithCustomReporter.sql b/examples/developer_examples/RunExampleTestSuiteWithCustomReporter.sql index 59fe15662..2cae9db53 100644 --- a/examples/developer_examples/RunExampleTestSuiteWithCustomReporter.sql +++ b/examples/developer_examples/RunExampleTestSuiteWithCustomReporter.sql @@ -22,19 +22,21 @@ begin ut_event_manager.initialize(); -- Install ut_custom_reporter first from example folder - l_suite := ut_suite(user, 'ut_exampletest'); + l_suite := ut_suite(user, 'ut_exampletest',a_line_no=>1); - l_test := ut_test(user, 'ut_exampletest','ut_exAmpletest'); + l_test := ut_test(user, 'ut_exampletest','ut_exAmpletest',a_line_no=>3); l_test.description := 'Example test1'; l_test.before_test_list := ut_executables(ut_executable(user, 'ut_exampletest','Setup',ut_utils.gc_before_test)); l_test.after_test_list := ut_executables(ut_executable(user, 'ut_exampletest','tEardown',ut_utils.gc_after_test)); - l_suite.add_item(l_test); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := l_test; - l_test := ut_test(user, 'UT_EXAMPLETEST2','ut_exAmpletest'); + l_test := ut_test(user, 'UT_EXAMPLETEST2','ut_exAmpletest',a_line_no=>6); l_test.description := 'Another example test'; l_test.before_test_list := ut_executables(ut_executable(user, 'ut_exampletest','SETUP',ut_utils.gc_before_test)); l_test.after_test_list := ut_executables(ut_executable(user, 'ut_exampletest','TEARDOWN',ut_utils.gc_after_test)); - l_suite.add_item(l_test); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := l_test; -- provide a reporter to process results tabbing each hierarcy level by tab_size l_reporter := ut_custom_reporter(a_tab_size => 2); diff --git a/mkdocs.yml b/mkdocs.yml index 7bffe0c71..f9a2687a8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -18,6 +18,7 @@ nav: - Expectations: userguide/expectations.md - Advanced data comparison: userguide/advanced_data_comparison.md - Running unit tests: userguide/running-unit-tests.md + - Querying for test suites: userguide/querying_suites.md - Testing best pracitces: userguide/best-practices.md - Upgrade utPLSQL: userguide/upgrade.md - Reporting: diff --git a/old_tests/RunAll.sql b/old_tests/RunAll.sql index f785aabc1..282a01ff7 100644 --- a/old_tests/RunAll.sql +++ b/old_tests/RunAll.sql @@ -50,41 +50,14 @@ exec ut_coverage.set_develop_mode(true); @@lib/RunTest.sql ut_reporters/ut_html_reporter.UserOverrideSchemaCoverage.sql @@lib/RunTest.sql ut_suite_manager/ut_suite_manager.AllowsDescriptionsWithComma.sql -@@lib/RunTest.sql ut_suite_manager/ut_suite_manager.emptySuitePath.sql @@lib/RunTest.sql ut_suite_manager/ut_suite_manager.get_schema_ut_packages.IncludesPackagesWithSutePath.sql @@lib/RunTest.sql ut_suite_manager/ut_suite_manager.IncludesInvalidPackageBodiesInTheRun.sql -@@lib/RunTest.sql ut_suite_manager/ut_suite_manager.CacheInvalidaesOnPackageDrop.sql @@lib/RunTest.sql ut_suite_manager/ut_suite_manager.PackageWithDollarSign.sql @@lib/RunTest.sql ut_suite_manager/ut_suite_manager.PackageWithHash.sql @@lib/RunTest.sql ut_suite_manager/ut_suite_manager.TestWithDollarSign.sql @@lib/RunTest.sql ut_suite_manager/ut_suite_manager.TestWithHashSign.sql -@@lib/RunTest.sql ut_test/ut_test.OwnerNameInvalid.sql -@@lib/RunTest.sql ut_test/ut_test.OwnerNameNull.sql -@@lib/RunTest.sql ut_test/ut_test.PackageInInvalidState.sql -@@lib/RunTest.sql ut_test/ut_test.PackageNameInvalid.sql -@@lib/RunTest.sql ut_test/ut_test.PackageNameNull.sql -@@lib/RunTest.sql ut_test/ut_test.ProcedureNameInvalid.sql -@@lib/RunTest.sql ut_test/ut_test.ProcedureNameNull.sql -@@lib/RunTest.sql ut_test/ut_test.SetupExecutedBeforeTest.sql -@@lib/RunTest.sql ut_test/ut_test.SetupProcedureNameInvalid.sql -@@lib/RunTest.sql ut_test/ut_test.SetupProcedureNameNull.sql -@@lib/RunTest.sql ut_test/ut_test.TeardownExecutedAfterTest.sql -@@lib/RunTest.sql ut_test/ut_test.TeardownProcedureNameInvalid.sql -@@lib/RunTest.sql ut_test/ut_test.TeardownProcedureNameNull.sql -@@lib/RunTest.sql ut_test/ut_test.IgnoreTollbackToSavepointException.sql -@@lib/RunTest.sql ut_test/ut_test.AfterEachExecuted.sql -@@lib/RunTest.sql ut_test/ut_test.AfterEachProcedureNameInvalid.sql -@@lib/RunTest.sql ut_test/ut_test.AfterEachProcedureNameNull.sql -@@lib/RunTest.sql ut_test/ut_test.BeforeEachExecuted.sql -@@lib/RunTest.sql ut_test/ut_test.BeforeEachProcedureNameInvalid.sql -@@lib/RunTest.sql ut_test/ut_test.BeforeEachProcedureNameNull.sql -@@lib/RunTest.sql ut_test/ut_test.TestOutputGathering.sql -@@lib/RunTest.sql ut_test/ut_test.TestOutputGatheringWhenEmpty.sql -@@lib/RunTest.sql ut_test/ut_test.ReportWarningOnRollbackFailed.sql -@@lib/RunTest.sql ut_test/ut_test.ApplicationInfoOnExecution.sql - @@ut_utils/ut_utils.clob_to_table.sql @@ut_utils/ut_utils.table_to_clob.sql @@lib/RunTest.sql ut_utils/ut_utils.append_to_clob.worksWithMultiByteChars.sql @@ -110,309 +83,309 @@ drop type utplsql_test_reporter; drop package test_reporters; drop package ut3$user#.html_coverage_test; -set timing on -prompt Generating coverage data to reporter outputs - -var html_reporter_id varchar2(32); -var sonar_reporter_id varchar2(32); -var coveralls_reporter_id varchar2(32); -declare - l_reporter ut_reporter_base; - l_project_file_list ut_varchar2_list; - l_test_run ut_run; -begin - l_project_file_list := ut_varchar2_list( - 'source/api', - 'source/core', - 'source/create_synonyms_and_grants_for_public.sql', - 'source/create_synonyms_and_grants_for_user.sql', - 'source/create_utplsql_owner.sql', - 'source/expectations', - 'source/install.log', - 'source/install.sql', - 'source/install_headless.sql', - 'source/license.txt', - 'source/readme.md', - 'source/reporters', - 'source/uninstall.log', - 'source/uninstall.sql', - 'source/api/be_between.syn', - 'source/api/be_empty.syn', - 'source/api/be_false.syn', - 'source/api/be_greater_or_equal.syn', - 'source/api/be_greater_than.syn', - 'source/api/be_less_or_equal.syn', - 'source/api/be_less_than.syn', - 'source/api/be_like.syn', - 'source/api/be_not_null.syn', - 'source/api/be_null.syn', - 'source/api/be_true.syn', - 'source/api/equal.syn', - 'source/api/match.syn', - 'source/api/ut.pkb', - 'source/api/ut.pks', - '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', - 'source/core/annotations/ut_annotation_parser.pkb', - 'source/core/annotations/ut_annotation_parser.pks', - 'source/core/annotations/ut_annotation_cache_manager.pkb', - 'source/core/annotations/ut_annotation_cache_manager.pks', - 'source/core/ut_expectation_processor.pkb', - 'source/core/ut_expectation_processor.pks', - 'source/core/ut_file_mapper.pkb', - 'source/core/ut_file_mapper.pks', - 'source/core/ut_metadata.pkb', - 'source/core/ut_metadata.pks', - 'source/core/ut_suite_manager.pkb', - 'source/core/ut_suite_manager.pks', - 'source/core/ut_utils.pkb', - 'source/core/ut_utils.pks', - 'source/core/coverage/proftab.sql', - 'source/core/coverage/ut_coverage.pkb', - 'source/core/coverage/ut_coverage.pks', - 'source/core/coverage/ut_coverage_helper.pkb', - 'source/core/coverage/ut_coverage_helper.pks', - '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', - 'source/core/types/ut_event_listener.tpb', - 'source/core/types/ut_event_listener.tps', - 'source/core/types/ut_event_listener_base.tps', - 'source/core/types/ut_executable.tpb', - 'source/core/types/ut_executable.tps', - 'source/core/types/ut_expectation_result.tpb', - 'source/core/types/ut_expectation_result.tps', - 'source/core/types/ut_expectation_results.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', - 'source/core/types/ut_logical_suite.tps', - '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', - 'source/core/types/ut_results_counter.tpb', - 'source/core/types/ut_results_counter.tps', - 'source/core/types/ut_run.tpb', - 'source/core/types/ut_run.tps', - 'source/core/types/ut_suite.tpb', - 'source/core/types/ut_suite.tps', - 'source/core/types/ut_suite_item.tpb', - 'source/core/types/ut_suite_item.tps', - 'source/core/types/ut_suite_items.tps', - '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', - 'source/expectations/ut_expectation.tps', - 'source/expectations/ut_expectation_anydata.tpb', - 'source/expectations/ut_expectation_anydata.tps', - 'source/expectations/ut_expectation_blob.tpb', - 'source/expectations/ut_expectation_blob.tps', - 'source/expectations/ut_expectation_boolean.tpb', - 'source/expectations/ut_expectation_boolean.tps', - 'source/expectations/ut_expectation_clob.tpb', - 'source/expectations/ut_expectation_clob.tps', - 'source/expectations/ut_expectation_date.tpb', - 'source/expectations/ut_expectation_date.tps', - 'source/expectations/ut_expectation_dsinterval.tpb', - 'source/expectations/ut_expectation_dsinterval.tps', - 'source/expectations/ut_expectation_number.tpb', - 'source/expectations/ut_expectation_number.tps', - 'source/expectations/ut_expectation_refcursor.tpb', - 'source/expectations/ut_expectation_refcursor.tps', - 'source/expectations/ut_expectation_timestamp.tpb', - 'source/expectations/ut_expectation_timestamp.tps', - 'source/expectations/ut_expectation_timestamp_ltz.tpb', - 'source/expectations/ut_expectation_timestamp_ltz.tps', - 'source/expectations/ut_expectation_timestamp_tz.tpb', - 'source/expectations/ut_expectation_timestamp_tz.tps', - 'source/expectations/ut_expectation_varchar2.tpb', - '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', - 'source/expectations/data_values/ut_data_value_blob.tpb', - 'source/expectations/data_values/ut_data_value_blob.tps', - 'source/expectations/data_values/ut_data_value_boolean.tpb', - 'source/expectations/data_values/ut_data_value_boolean.tps', - 'source/expectations/data_values/ut_data_value_clob.tpb', - 'source/expectations/data_values/ut_data_value_clob.tps', - 'source/expectations/data_values/ut_data_value_collection.tpb', - 'source/expectations/data_values/ut_data_value_collection.tps', - 'source/expectations/data_values/ut_data_value_date.tpb', - 'source/expectations/data_values/ut_data_value_date.tps', - 'source/expectations/data_values/ut_data_value_dsinterval.tpb', - 'source/expectations/data_values/ut_data_value_dsinterval.tps', - 'source/expectations/data_values/ut_data_value_number.tpb', - 'source/expectations/data_values/ut_data_value_number.tps', - 'source/expectations/data_values/ut_data_value_object.tpb', - 'source/expectations/data_values/ut_data_value_object.tps', - 'source/expectations/data_values/ut_data_value_refcursor.tpb', - 'source/expectations/data_values/ut_data_value_refcursor.tps', - 'source/expectations/data_values/ut_data_value_timestamp.tpb', - 'source/expectations/data_values/ut_data_value_timestamp.tps', - 'source/expectations/data_values/ut_data_value_timestamp_ltz.tpb', - 'source/expectations/data_values/ut_data_value_timestamp_ltz.tps', - 'source/expectations/data_values/ut_data_value_timestamp_tz.tpb', - 'source/expectations/data_values/ut_data_value_timestamp_tz.tps', - 'source/expectations/data_values/ut_data_value_varchar2.tpb', - 'source/expectations/data_values/ut_data_value_varchar2.tps', - 'source/expectations/data_values/ut_data_value_yminterval.tpb', - 'source/expectations/data_values/ut_data_value_yminterval.tps', - 'source/expectations/matchers/ut_be_between.tpb', - 'source/expectations/matchers/ut_be_between.tps', - 'source/expectations/matchers/ut_be_empty.tpb', - 'source/expectations/matchers/ut_be_empty.tps', - 'source/expectations/matchers/ut_be_false.tpb', - 'source/expectations/matchers/ut_be_false.tps', - 'source/expectations/matchers/ut_be_greater_or_equal.tpb', - 'source/expectations/matchers/ut_be_greater_or_equal.tps', - 'source/expectations/matchers/ut_be_greater_than.tpb', - 'source/expectations/matchers/ut_be_greater_than.tps', - 'source/expectations/matchers/ut_be_less_or_equal.tpb', - 'source/expectations/matchers/ut_be_less_or_equal.tps', - 'source/expectations/matchers/ut_be_less_than.tpb', - 'source/expectations/matchers/ut_be_less_than.tps', - 'source/expectations/matchers/ut_be_like.tpb', - 'source/expectations/matchers/ut_be_like.tps', - 'source/expectations/matchers/ut_be_not_null.tpb', - 'source/expectations/matchers/ut_be_not_null.tps', - 'source/expectations/matchers/ut_be_null.tpb', - 'source/expectations/matchers/ut_be_null.tps', - 'source/expectations/matchers/ut_be_true.tpb', - 'source/expectations/matchers/ut_be_true.tps', - 'source/expectations/matchers/ut_equal.tpb', - 'source/expectations/matchers/ut_equal.tps', - 'source/expectations/matchers/ut_match.tpb', - 'source/expectations/matchers/ut_match.tps', - 'source/expectations/matchers/ut_matcher.tpb', - 'source/expectations/matchers/ut_matcher.tps', - 'source/expectations/matchers/ut_comparison_matcher.tpb', - 'source/expectations/matchers/ut_comparison_matcher.tps', - 'source/reporters/ut_ansiconsole_helper.pkb', - 'source/reporters/ut_ansiconsole_helper.pks', - 'source/reporters/ut_coverage_html_reporter.tpb', - 'source/reporters/ut_coverage_html_reporter.tps', - 'source/reporters/ut_coverage_report_html_helper.pkb', - 'source/reporters/ut_coverage_report_html_helper.pks', - 'source/reporters/ut_coveralls_reporter.tpb', - 'source/reporters/ut_coveralls_reporter.tps', - 'source/reporters/ut_coverage_sonar_reporter.tpb', - 'source/reporters/ut_coverage_sonar_reporter.tps', - 'source/reporters/ut_documentation_reporter.tpb', - 'source/reporters/ut_documentation_reporter.tps', - 'source/reporters/ut_sonar_test_reporter.tpb', - 'source/reporters/ut_sonar_test_reporter.tps', - 'source/reporters/ut_teamcity_reporter.tpb', - 'source/reporters/ut_teamcity_reporter.tps', - 'source/reporters/ut_teamcity_reporter_helper.pkb', - 'source/reporters/ut_teamcity_reporter_helper.pks'); - - l_test_run := ut_run(a_items => ut_suite_items(), a_project_file_mappings => ut_file_mapper.build_file_mappings( user,l_project_file_list)); - - --run for the first time to gather coverage and timings on reporters too - l_reporter := ut_coverage_html_reporter(a_project_name => 'utPLSQL v3'); - l_reporter.after_calling_run(l_test_run); - l_reporter.on_finalize(l_test_run); - - l_reporter := ut_coverage_sonar_reporter(); - l_reporter.after_calling_run(l_test_run); - l_reporter.on_finalize(l_test_run); - - l_reporter := ut_coveralls_reporter(); - l_reporter.after_calling_run(l_test_run); - l_reporter.on_finalize(l_test_run); - - ut_coverage.set_develop_mode(false); - ut_coverage.coverage_stop(); - - --run for the second time to get the coverage report - l_reporter := ut_coverage_html_reporter(a_project_name => 'utPLSQL v3'); - l_reporter.after_calling_run(l_test_run); - l_reporter.on_finalize(l_test_run); - :html_reporter_id := l_reporter.get_reporter_id; - - l_reporter := ut_coverage_sonar_reporter(); - l_reporter.after_calling_run(l_test_run); - l_reporter.on_finalize(l_test_run); - :sonar_reporter_id := l_reporter.get_reporter_id; - - l_reporter := ut_coveralls_reporter(); - l_reporter.after_calling_run(l_test_run); - l_reporter.on_finalize(l_test_run); - :coveralls_reporter_id := l_reporter.get_reporter_id; -end; -/ - -set timing off -prompt Spooling outcomes to coverage.xml -set termout off -set feedback off -set arraysize 50 -spool coverage.xml -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 -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 -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 timing on +-- prompt Generating coverage data to reporter outputs +-- +-- var html_reporter_id varchar2(32); +-- var sonar_reporter_id varchar2(32); +-- var coveralls_reporter_id varchar2(32); +-- declare +-- l_reporter ut_reporter_base; +-- l_project_file_list ut_varchar2_list; +-- l_test_run ut_run; +-- begin +-- l_project_file_list := ut_varchar2_list( +-- 'source/api', +-- 'source/core', +-- 'source/create_synonyms_and_grants_for_public.sql', +-- 'source/create_synonyms_and_grants_for_user.sql', +-- 'source/create_utplsql_owner.sql', +-- 'source/expectations', +-- 'source/install.log', +-- 'source/install.sql', +-- 'source/install_headless.sql', +-- 'source/license.txt', +-- 'source/readme.md', +-- 'source/reporters', +-- 'source/uninstall.log', +-- 'source/uninstall.sql', +-- 'source/api/be_between.syn', +-- 'source/api/be_empty.syn', +-- 'source/api/be_false.syn', +-- 'source/api/be_greater_or_equal.syn', +-- 'source/api/be_greater_than.syn', +-- 'source/api/be_less_or_equal.syn', +-- 'source/api/be_less_than.syn', +-- 'source/api/be_like.syn', +-- 'source/api/be_not_null.syn', +-- 'source/api/be_null.syn', +-- 'source/api/be_true.syn', +-- 'source/api/equal.syn', +-- 'source/api/match.syn', +-- 'source/api/ut.pkb', +-- 'source/api/ut.pks', +-- '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', +-- 'source/core/annotations/ut_annotation_parser.pkb', +-- 'source/core/annotations/ut_annotation_parser.pks', +-- 'source/core/annotations/ut_annotation_cache_manager.pkb', +-- 'source/core/annotations/ut_annotation_cache_manager.pks', +-- 'source/core/ut_expectation_processor.pkb', +-- 'source/core/ut_expectation_processor.pks', +-- 'source/core/ut_file_mapper.pkb', +-- 'source/core/ut_file_mapper.pks', +-- 'source/core/ut_metadata.pkb', +-- 'source/core/ut_metadata.pks', +-- 'source/core/ut_suite_manager.pkb', +-- 'source/core/ut_suite_manager.pks', +-- 'source/core/ut_utils.pkb', +-- 'source/core/ut_utils.pks', +-- 'source/core/coverage/proftab.sql', +-- 'source/core/coverage/ut_coverage.pkb', +-- 'source/core/coverage/ut_coverage.pks', +-- 'source/core/coverage/ut_coverage_helper.pkb', +-- 'source/core/coverage/ut_coverage_helper.pks', +-- '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', +-- 'source/core/types/ut_event_listener.tpb', +-- 'source/core/types/ut_event_listener.tps', +-- 'source/core/types/ut_event_listener_base.tps', +-- 'source/core/types/ut_executable.tpb', +-- 'source/core/types/ut_executable.tps', +-- 'source/core/types/ut_expectation_result.tpb', +-- 'source/core/types/ut_expectation_result.tps', +-- 'source/core/types/ut_expectation_results.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', +-- 'source/core/types/ut_logical_suite.tps', +-- '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', +-- 'source/core/types/ut_results_counter.tpb', +-- 'source/core/types/ut_results_counter.tps', +-- 'source/core/types/ut_run.tpb', +-- 'source/core/types/ut_run.tps', +-- 'source/core/types/ut_suite.tpb', +-- 'source/core/types/ut_suite.tps', +-- 'source/core/types/ut_suite_item.tpb', +-- 'source/core/types/ut_suite_item.tps', +-- 'source/core/types/ut_suite_items.tps', +-- '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', +-- 'source/expectations/ut_expectation.tps', +-- 'source/expectations/ut_expectation_anydata.tpb', +-- 'source/expectations/ut_expectation_anydata.tps', +-- 'source/expectations/ut_expectation_blob.tpb', +-- 'source/expectations/ut_expectation_blob.tps', +-- 'source/expectations/ut_expectation_boolean.tpb', +-- 'source/expectations/ut_expectation_boolean.tps', +-- 'source/expectations/ut_expectation_clob.tpb', +-- 'source/expectations/ut_expectation_clob.tps', +-- 'source/expectations/ut_expectation_date.tpb', +-- 'source/expectations/ut_expectation_date.tps', +-- 'source/expectations/ut_expectation_dsinterval.tpb', +-- 'source/expectations/ut_expectation_dsinterval.tps', +-- 'source/expectations/ut_expectation_number.tpb', +-- 'source/expectations/ut_expectation_number.tps', +-- 'source/expectations/ut_expectation_refcursor.tpb', +-- 'source/expectations/ut_expectation_refcursor.tps', +-- 'source/expectations/ut_expectation_timestamp.tpb', +-- 'source/expectations/ut_expectation_timestamp.tps', +-- 'source/expectations/ut_expectation_timestamp_ltz.tpb', +-- 'source/expectations/ut_expectation_timestamp_ltz.tps', +-- 'source/expectations/ut_expectation_timestamp_tz.tpb', +-- 'source/expectations/ut_expectation_timestamp_tz.tps', +-- 'source/expectations/ut_expectation_varchar2.tpb', +-- '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', +-- 'source/expectations/data_values/ut_data_value_blob.tpb', +-- 'source/expectations/data_values/ut_data_value_blob.tps', +-- 'source/expectations/data_values/ut_data_value_boolean.tpb', +-- 'source/expectations/data_values/ut_data_value_boolean.tps', +-- 'source/expectations/data_values/ut_data_value_clob.tpb', +-- 'source/expectations/data_values/ut_data_value_clob.tps', +-- 'source/expectations/data_values/ut_data_value_collection.tpb', +-- 'source/expectations/data_values/ut_data_value_collection.tps', +-- 'source/expectations/data_values/ut_data_value_date.tpb', +-- 'source/expectations/data_values/ut_data_value_date.tps', +-- 'source/expectations/data_values/ut_data_value_dsinterval.tpb', +-- 'source/expectations/data_values/ut_data_value_dsinterval.tps', +-- 'source/expectations/data_values/ut_data_value_number.tpb', +-- 'source/expectations/data_values/ut_data_value_number.tps', +-- 'source/expectations/data_values/ut_data_value_object.tpb', +-- 'source/expectations/data_values/ut_data_value_object.tps', +-- 'source/expectations/data_values/ut_data_value_refcursor.tpb', +-- 'source/expectations/data_values/ut_data_value_refcursor.tps', +-- 'source/expectations/data_values/ut_data_value_timestamp.tpb', +-- 'source/expectations/data_values/ut_data_value_timestamp.tps', +-- 'source/expectations/data_values/ut_data_value_timestamp_ltz.tpb', +-- 'source/expectations/data_values/ut_data_value_timestamp_ltz.tps', +-- 'source/expectations/data_values/ut_data_value_timestamp_tz.tpb', +-- 'source/expectations/data_values/ut_data_value_timestamp_tz.tps', +-- 'source/expectations/data_values/ut_data_value_varchar2.tpb', +-- 'source/expectations/data_values/ut_data_value_varchar2.tps', +-- 'source/expectations/data_values/ut_data_value_yminterval.tpb', +-- 'source/expectations/data_values/ut_data_value_yminterval.tps', +-- 'source/expectations/matchers/ut_be_between.tpb', +-- 'source/expectations/matchers/ut_be_between.tps', +-- 'source/expectations/matchers/ut_be_empty.tpb', +-- 'source/expectations/matchers/ut_be_empty.tps', +-- 'source/expectations/matchers/ut_be_false.tpb', +-- 'source/expectations/matchers/ut_be_false.tps', +-- 'source/expectations/matchers/ut_be_greater_or_equal.tpb', +-- 'source/expectations/matchers/ut_be_greater_or_equal.tps', +-- 'source/expectations/matchers/ut_be_greater_than.tpb', +-- 'source/expectations/matchers/ut_be_greater_than.tps', +-- 'source/expectations/matchers/ut_be_less_or_equal.tpb', +-- 'source/expectations/matchers/ut_be_less_or_equal.tps', +-- 'source/expectations/matchers/ut_be_less_than.tpb', +-- 'source/expectations/matchers/ut_be_less_than.tps', +-- 'source/expectations/matchers/ut_be_like.tpb', +-- 'source/expectations/matchers/ut_be_like.tps', +-- 'source/expectations/matchers/ut_be_not_null.tpb', +-- 'source/expectations/matchers/ut_be_not_null.tps', +-- 'source/expectations/matchers/ut_be_null.tpb', +-- 'source/expectations/matchers/ut_be_null.tps', +-- 'source/expectations/matchers/ut_be_true.tpb', +-- 'source/expectations/matchers/ut_be_true.tps', +-- 'source/expectations/matchers/ut_equal.tpb', +-- 'source/expectations/matchers/ut_equal.tps', +-- 'source/expectations/matchers/ut_match.tpb', +-- 'source/expectations/matchers/ut_match.tps', +-- 'source/expectations/matchers/ut_matcher.tpb', +-- 'source/expectations/matchers/ut_matcher.tps', +-- 'source/expectations/matchers/ut_comparison_matcher.tpb', +-- 'source/expectations/matchers/ut_comparison_matcher.tps', +-- 'source/reporters/ut_ansiconsole_helper.pkb', +-- 'source/reporters/ut_ansiconsole_helper.pks', +-- 'source/reporters/ut_coverage_html_reporter.tpb', +-- 'source/reporters/ut_coverage_html_reporter.tps', +-- 'source/reporters/ut_coverage_report_html_helper.pkb', +-- 'source/reporters/ut_coverage_report_html_helper.pks', +-- 'source/reporters/ut_coveralls_reporter.tpb', +-- 'source/reporters/ut_coveralls_reporter.tps', +-- 'source/reporters/ut_coverage_sonar_reporter.tpb', +-- 'source/reporters/ut_coverage_sonar_reporter.tps', +-- 'source/reporters/ut_documentation_reporter.tpb', +-- 'source/reporters/ut_documentation_reporter.tps', +-- 'source/reporters/ut_sonar_test_reporter.tpb', +-- 'source/reporters/ut_sonar_test_reporter.tps', +-- 'source/reporters/ut_teamcity_reporter.tpb', +-- 'source/reporters/ut_teamcity_reporter.tps', +-- 'source/reporters/ut_teamcity_reporter_helper.pkb', +-- 'source/reporters/ut_teamcity_reporter_helper.pks'); +-- +-- l_test_run := ut_run(a_items => ut_suite_items(), a_project_file_mappings => ut_file_mapper.build_file_mappings( user,l_project_file_list)); +-- +-- --run for the first time to gather coverage and timings on reporters too +-- l_reporter := ut_coverage_html_reporter(a_project_name => 'utPLSQL v3'); +-- l_reporter.after_calling_run(l_test_run); +-- l_reporter.on_finalize(l_test_run); +-- +-- l_reporter := ut_coverage_sonar_reporter(); +-- l_reporter.after_calling_run(l_test_run); +-- l_reporter.on_finalize(l_test_run); +-- +-- l_reporter := ut_coveralls_reporter(); +-- l_reporter.after_calling_run(l_test_run); +-- l_reporter.on_finalize(l_test_run); +-- +-- ut_coverage.set_develop_mode(false); +-- ut_coverage.coverage_stop(); +-- +-- --run for the second time to get the coverage report +-- l_reporter := ut_coverage_html_reporter(a_project_name => 'utPLSQL v3'); +-- l_reporter.after_calling_run(l_test_run); +-- l_reporter.on_finalize(l_test_run); +-- :html_reporter_id := l_reporter.get_reporter_id; +-- +-- l_reporter := ut_coverage_sonar_reporter(); +-- l_reporter.after_calling_run(l_test_run); +-- l_reporter.on_finalize(l_test_run); +-- :sonar_reporter_id := l_reporter.get_reporter_id; +-- +-- l_reporter := ut_coveralls_reporter(); +-- l_reporter.after_calling_run(l_test_run); +-- l_reporter.on_finalize(l_test_run); +-- :coveralls_reporter_id := l_reporter.get_reporter_id; +-- end; +-- / +-- +-- set timing off +-- prompt Spooling outcomes to coverage.xml +-- set termout off +-- set feedback off +-- set arraysize 50 +-- spool coverage.xml +-- 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 +-- 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 +-- 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 diff --git a/old_tests/ut_reporters/ut_documentation_reporter.providesCorrectLineFromStacktrace.sql b/old_tests/ut_reporters/ut_documentation_reporter.providesCorrectLineFromStacktrace.sql index 66cf41b32..f155117fe 100644 --- a/old_tests/ut_reporters/ut_documentation_reporter.providesCorrectLineFromStacktrace.sql +++ b/old_tests/ut_reporters/ut_documentation_reporter.providesCorrectLineFromStacktrace.sql @@ -18,7 +18,7 @@ Finished % --act select * bulk collect into l_output_data - from table(ut.run('test_reporters',ut_documentation_reporter())); + from table(ut.run(':org.utplsql.utplsql.test.test_reporters',ut_documentation_reporter())); l_output := ut_utils.table_to_clob(l_output_data); diff --git a/old_tests/ut_suite_manager/ut_suite_manager.CacheInvalidaesOnPackageDrop.sql b/old_tests/ut_suite_manager/ut_suite_manager.CacheInvalidaesOnPackageDrop.sql deleted file mode 100644 index 6581a9eeb..000000000 --- a/old_tests/ut_suite_manager/ut_suite_manager.CacheInvalidaesOnPackageDrop.sql +++ /dev/null @@ -1,46 +0,0 @@ -set termout off -create or replace package tst_package_to_be_dropped as - --%suite - - --%test - procedure test1; -end; -/ - -create or replace package body tst_package_to_be_dropped as - procedure test1 is begin ut.expect(1).to_equal(1); end; - procedure test2 is begin ut.expect(1).to_equal(1); end; -end; -/ - -set termout on - -declare - l_test_report ut_varchar2_list; -begin - select * bulk collect into l_test_report from table(ut.run(USER||'.tst_package_to_be_dropped')); -end; -/ - -set termout off -drop package tst_package_to_be_dropped -/ -set termout on - -declare - l_test_report ut_varchar2_list; -begin - begin - select * bulk collect into l_test_report from table(ut.run(user || '.tst_package_to_be_dropped')); - exception - when others then - if sqlerrm like '%tst_package_to_be_dropped%not found%' then - :test_result := ut_utils.gc_success; - end if; - end; - if :test_result != ut_utils.gc_success or :test_result is null then - dbms_output.put_line('Failed: Expected exception with text like ''%tst_package_to_be_dropped%not found%'' but got:''' || - sqlerrm || ''''); - end if; -end; -/ diff --git a/old_tests/ut_suite_manager/ut_suite_manager.emptySuitePath.sql b/old_tests/ut_suite_manager/ut_suite_manager.emptySuitePath.sql deleted file mode 100644 index a957f7873..000000000 --- a/old_tests/ut_suite_manager/ut_suite_manager.emptySuitePath.sql +++ /dev/null @@ -1,41 +0,0 @@ -set termout off -create or replace package tst_empty_suite_path as - --%suite - --%suitepath - - --%test - procedure test1; -end; -/ - -create or replace package body tst_empty_suite_path as - procedure test1 is begin ut.expect(1).to_equal(1); end; -end; -/ - -set termout on - -declare - l_objects_to_run ut_suite_items; - l_suite ut_suite; -begin - - --act - l_objects_to_run := ut_suite_manager.configure_execution_by_path(ut_varchar2_list('tst_empty_suite_path')); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - - l_suite := treat(l_objects_to_run(1) as ut_suite); - - ut.expect(l_suite.name).to_equal('tst_empty_suite_path'); - - if ut_expectation_processor.get_status = ut_utils.gc_success then - :test_result := ut_utils.gc_success; - end if; - -end; -/ - -drop package tst_empty_suite_path -/ diff --git a/old_tests/ut_suite_manager/ut_suite_manager.get_schema_ut_packages.IncludesPackagesWithSutePath.sql b/old_tests/ut_suite_manager/ut_suite_manager.get_schema_ut_packages.IncludesPackagesWithSutePath.sql index 3023c28f0..0f446b7bf 100644 --- a/old_tests/ut_suite_manager/ut_suite_manager.get_schema_ut_packages.IncludesPackagesWithSutePath.sql +++ b/old_tests/ut_suite_manager/ut_suite_manager.get_schema_ut_packages.IncludesPackagesWithSutePath.sql @@ -6,8 +6,9 @@ end; set termout on declare - l_expected ut_object_names; - l_actual ut_object_names; + l_expected ut_object_names; + l_actual ut_object_names; + l_not_found ut_object_names := ut_object_names(); begin l_expected := ut_object_names( ut_object_name(user,'TEST_PACKAGE_1'), @@ -17,7 +18,13 @@ begin ut_object_name(user,'TEST_REPORTERS') ); l_actual := ut_suite_manager.get_schema_ut_packages(ut_varchar2_rows(user)); - if l_actual = l_expected then + for i in 1 .. l_expected.count loop + if l_expected(i) not member of l_actual then + l_not_found.extend; + l_not_found(l_not_found.last) := l_expected(i); + end if; + end loop; + if l_not_found is empty then :test_result := ut_utils.gc_success; else dbms_output.put_line('actual:'||xmltype(anydata.convertcollection(l_actual)).getclobval()); diff --git a/old_tests/ut_test/ut_test.AfterEachExecuted.sql b/old_tests/ut_test/ut_test.AfterEachExecuted.sql deleted file mode 100644 index e35564b7b..000000000 --- a/old_tests/ut_test/ut_test.AfterEachExecuted.sql +++ /dev/null @@ -1,19 +0,0 @@ -PROMPT Invoke aftereach procedure - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_passing_test' - ); -begin - simple_test.after_each_list := ut_executables(ut_executable(user, 'ut_example_tests', 'aftereach', ut_utils.gc_after_each)); ---Act - simple_test.do_execute(); ---Assert - if simple_test.result = ut_utils.gc_success and ut_example_tests.g_char2 = 'F' then - :test_result := ut_utils.gc_success; - end if; -end; -/ - diff --git a/old_tests/ut_test/ut_test.AfterEachProcedureNameInvalid.sql b/old_tests/ut_test/ut_test.AfterEachProcedureNameInvalid.sql deleted file mode 100644 index 4d12cd513..000000000 --- a/old_tests/ut_test/ut_test.AfterEachProcedureNameInvalid.sql +++ /dev/null @@ -1,20 +0,0 @@ -PROMPT Does not execute test and reports error when test aftereach procedure name for a test is invalid - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_exampletest' - ); -begin - simple_test.after_each_list := ut_executables(ut_executable(user, 'ut_example_tests', 'invalid setup name', ut_utils.gc_after_each)); - ut_example_tests.g_char := 'x'; - ut_example_tests.g_char2 := 'x'; ---Act - simple_test.do_execute(); ---Assert - if ut_example_tests.g_char2 = 'x' and simple_test.result = ut_utils.gc_error then - :test_result := ut_utils.gc_success; - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.AfterEachProcedureNameNull.sql b/old_tests/ut_test/ut_test.AfterEachProcedureNameNull.sql deleted file mode 100644 index 2700e1a10..000000000 --- a/old_tests/ut_test/ut_test.AfterEachProcedureNameNull.sql +++ /dev/null @@ -1,20 +0,0 @@ -PROMPT Does not invoke aftereach procedure when aftereach procedure name for a test is null - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_passing_test' - ); -begin - simple_test.after_each_list := ut_executables(ut_executable(user, 'ut_example_tests', '', ut_utils.gc_after_each)); ---Act - simple_test.do_execute(); ---Assert - if ut_example_tests.g_char2 = 'a' then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('expected: ut_example_tests.g_char = ''a'', got: '||ut_example_tests.g_char2 ); - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.ApplicationInfoOnExecution.sql b/old_tests/ut_test/ut_test.ApplicationInfoOnExecution.sql deleted file mode 100644 index 1ffa7fc11..000000000 --- a/old_tests/ut_test/ut_test.ApplicationInfoOnExecution.sql +++ /dev/null @@ -1,149 +0,0 @@ -create or replace package ut_output_tests -as - --%suite - - gv_before_all_client_info varchar2(200); - gv_before_each_client_info varchar2(200); - gv_before_test_client_info varchar2(200); - gv_after_test_client_info varchar2(200); - gv_after_each_client_info varchar2(200); - gv_after_all_client_info varchar2(200); - - --%test - --%beforetest(before_test) - --%aftertest(after_test) - procedure the_test; - - --%beforeall - procedure beforeall; - - --%beforeeach - procedure beforeeach; - - procedure before_test; - procedure after_test; - - --%aftereach - procedure aftereach; - - --%afterall - procedure afterall; - -end; -/ - -create or replace package body ut_output_tests -as - - procedure the_test - as - l_module_name varchar2(4000); - l_action_name varchar2(4000); - l_client_info varchar2(4000); - begin - --Generate empty output - dbms_output.put_line(''); - ut.expect(1,'Test 1 Should Pass').to_equal(1); - dbms_application_info.read_module(module_name => l_module_name, action_name => l_action_name); - dbms_application_info.read_client_info(l_client_info); - ut.expect(l_module_name).to_equal('utPLSQL'); - ut.expect(l_action_name).to_be_like('ut_output_tests'); - ut.expect(l_client_info).to_be_like('the_test'); - end; - - procedure beforeall is - begin - dbms_application_info.read_client_info(gv_before_all_client_info); - end; - - procedure beforeeach is - begin - dbms_application_info.read_client_info(gv_before_each_client_info); - end; - - procedure before_test is - begin - dbms_application_info.read_client_info(gv_before_test_client_info); - end; - procedure after_test is - begin - dbms_application_info.read_client_info(gv_after_test_client_info); - end; - - procedure aftereach is - begin - dbms_application_info.read_client_info(gv_after_each_client_info); - end; - - procedure afterall is - begin - dbms_application_info.read_client_info(gv_after_all_client_info); - end; - -end; -/ - -declare - l_output_data dbms_output.chararr; - l_num_lines integer := 100000; - l_output clob; - l_result boolean := true; - l_client_info varchar2(4000); -begin - --act - ut.run('ut_output_tests'); - - --assert - dbms_output.get_lines( l_output_data, l_num_lines); - dbms_lob.createtemporary(l_output,true); - for i in 1 .. l_num_lines loop - dbms_lob.append(l_output,l_output_data(i)); - end loop; - - execute immediate 'begin :i := ut_output_tests.gv_before_all_client_info; end;' using out l_client_info; - if not nvl(l_client_info = 'beforeall', false) then - dbms_output.put_line('Wrong before all text: '||l_client_info); - l_result := false; - end if; - execute immediate 'begin :i := ut_output_tests.gv_before_each_client_info; end;' using out l_client_info; - if not nvl(l_client_info = 'beforeeach', false) then - dbms_output.put_line('Wrong before each text: '||l_client_info); - l_result := false; - end if; - execute immediate 'begin :i := ut_output_tests.gv_before_test_client_info; end;' using out l_client_info; - if not nvl(l_client_info = 'before_test', false) then - dbms_output.put_line('Wrong before test text: '||l_client_info); - l_result := false; - end if; - execute immediate 'begin :i := ut_output_tests.gv_after_test_client_info; end;' using out l_client_info; - if not nvl(l_client_info = 'after_test', false) then - dbms_output.put_line('Wrong after test text: '||l_client_info); - l_result := false; - end if; - execute immediate 'begin :i := ut_output_tests.gv_after_each_client_info; end;' using out l_client_info; - if not nvl(l_client_info = 'aftereach', false) then - dbms_output.put_line('Wrong after each text: '||l_client_info); - l_result := false; - end if; - execute immediate 'begin :i := ut_output_tests.gv_after_all_client_info; end;' using out l_client_info; - if not nvl(l_client_info = 'afterall', false) then - dbms_output.put_line('Wrong after all text: '||l_client_info); - l_result := false; - end if; - - if not nvl(l_output like '%0 failed, 0 errored, 0 disabled, 0 warning(s)%',false) then - l_result := false; - for i in 1 .. l_num_lines loop - dbms_output.put_line(l_output_data(i)); - end loop; - dbms_output.put_line('Failed: Wrong output'); - end if; - if l_result then - :test_result := ut_utils.gc_success; - end if; -end; -/ - -drop package ut_output_tests -/ - diff --git a/old_tests/ut_test/ut_test.BeforeEachExecuted.sql b/old_tests/ut_test/ut_test.BeforeEachExecuted.sql deleted file mode 100644 index 5015d69fd..000000000 --- a/old_tests/ut_test/ut_test.BeforeEachExecuted.sql +++ /dev/null @@ -1,20 +0,0 @@ -PROMPT Invoke beforeeach procedure - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_passing_test' - ); -begin - simple_test.before_each_list := ut_executables(ut_executable(user, 'ut_example_tests', 'beforeeach', ut_utils.gc_before_each)); - ut_example_tests.g_number2 := null; ---Act - simple_test.do_execute(); ---Assert - if ut_example_tests.g_number2 = 1 then - :test_result := ut_utils.gc_success; - end if; -end; -/ - diff --git a/old_tests/ut_test/ut_test.BeforeEachProcedureNameInvalid.sql b/old_tests/ut_test/ut_test.BeforeEachProcedureNameInvalid.sql deleted file mode 100644 index f03b76f08..000000000 --- a/old_tests/ut_test/ut_test.BeforeEachProcedureNameInvalid.sql +++ /dev/null @@ -1,19 +0,0 @@ -PROMPT Does not execute test and reports error when test beforeeach procedure name for a test is invalid - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_exampletest' - ); -begin - simple_test.before_each_list := ut_executables(ut_executable(user, 'ut_example_tests', 'invalid setup name', ut_utils.gc_before_each)); - ut_example_tests.g_char2 := null; ---Act - simple_test.do_execute(); ---Assert - if simple_test.result = ut_utils.gc_error and ut_example_tests.g_char2 is null then - :test_result := ut_utils.gc_success; - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.BeforeEachProcedureNameNull.sql b/old_tests/ut_test/ut_test.BeforeEachProcedureNameNull.sql deleted file mode 100644 index e717b128f..000000000 --- a/old_tests/ut_test/ut_test.BeforeEachProcedureNameNull.sql +++ /dev/null @@ -1,21 +0,0 @@ -PROMPT Does not invoke setup procedure when beforeeach procedure name for a test is null - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_passing_test' - ); -begin - simple_test.before_each_list := ut_executables(ut_executable(user, 'ut_example_tests', '', ut_utils.gc_before_each)); - ut_example_tests.g_number2 := null; ---Act - simple_test.do_execute(); ---Assert - if ut_example_tests.g_number2 is null then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('expected: ut_example_tests.g_number is null, got: '||ut_example_tests.g_number2 ); - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.IgnoreTollbackToSavepointException.sql b/old_tests/ut_test/ut_test.IgnoreTollbackToSavepointException.sql deleted file mode 100644 index 94ad60c3d..000000000 --- a/old_tests/ut_test/ut_test.IgnoreTollbackToSavepointException.sql +++ /dev/null @@ -1,17 +0,0 @@ -PROMPT Checks that rollback exception does not make run to fail - ---Arrange -declare - simple_test ut_test := ut_test(a_object_name => 'ut_example_tests', a_name => 'ut_commit_test'); -begin - simple_test.rollback_type := ut_utils.gc_rollback_auto; ---Act - simple_test.do_execute(); ---Assert - if simple_test.result = ut_utils.gc_success then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('simple_test.result = '||ut_utils.test_result_to_char(simple_test.result)); - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.OwnerNameInvalid.sql b/old_tests/ut_test/ut_test.OwnerNameInvalid.sql deleted file mode 100644 index ba19e0767..000000000 --- a/old_tests/ut_test/ut_test.OwnerNameInvalid.sql +++ /dev/null @@ -1,17 +0,0 @@ -PROMPT Reports error when test owner name for a test is invalid - ---Arrange -declare - simple_test ut_test := ut_test( a_object_owner => 'invalid owner name', a_object_name => 'ut_example_tests', a_name => 'ut_passing_test'); -begin ---Act - simple_test.do_execute(); - ---Assert - if simple_test.result = ut_utils.gc_error then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('simple_test.result = '||ut_utils.test_result_to_char(simple_test.result)); - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.OwnerNameNull.sql b/old_tests/ut_test/ut_test.OwnerNameNull.sql deleted file mode 100644 index 68acf9144..000000000 --- a/old_tests/ut_test/ut_test.OwnerNameNull.sql +++ /dev/null @@ -1,14 +0,0 @@ -PROMPT Executes test in current schema when test owner name for a test is null - ---Arrange -declare - simple_test ut_test:= ut_test(a_object_owner => null, a_object_name => 'ut_example_tests', a_name => 'ut_passing_test'); -begin ---Act - simple_test.do_execute(); ---Assert - if ut_example_tests.g_char = 'a' then - :test_result := simple_test.result; - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.PackageInInvalidState.sql b/old_tests/ut_test/ut_test.PackageInInvalidState.sql deleted file mode 100644 index 31056dcfd..000000000 --- a/old_tests/ut_test/ut_test.PackageInInvalidState.sql +++ /dev/null @@ -1,27 +0,0 @@ -set termout off ---Arrange -create or replace package invalid_package is - v_variable non_existing_type; - procedure ut_exampletest; -end; -/ -set termout on - -declare - simple_test ut_test := ut_test(a_object_name => 'invalid_package', a_name => 'ut_exampletest'); -begin ---Act - simple_test.do_execute(); ---Assert - if simple_test.result = ut_utils.gc_error then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('simple_test.result = '||ut_utils.test_result_to_char(simple_test.result)); - end if; -end; -/ - -set termout off ---Cleanup -drop package invalid_package; -set termout off diff --git a/old_tests/ut_test/ut_test.PackageNameInvalid.sql b/old_tests/ut_test/ut_test.PackageNameInvalid.sql deleted file mode 100644 index 246af45db..000000000 --- a/old_tests/ut_test/ut_test.PackageNameInvalid.sql +++ /dev/null @@ -1,16 +0,0 @@ -PROMPT Reports error when unit test package name for a test is invalid - ---Arrange -declare - simple_test ut_test := ut_test(a_object_name => 'invalid test package name', a_name => 'ut_passing_test'); -begin ---Act - simple_test.do_execute(); ---Assert - if simple_test.result = ut_utils.gc_error then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('simple_test.result = '||ut_utils.test_result_to_char(simple_test.result)); - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.PackageNameNull.sql b/old_tests/ut_test/ut_test.PackageNameNull.sql deleted file mode 100644 index f4420b6b0..000000000 --- a/old_tests/ut_test/ut_test.PackageNameNull.sql +++ /dev/null @@ -1,16 +0,0 @@ -PROMPT Reports error when unit test package name for a test is null - ---Arrange -declare - simple_test ut_test := ut_test(a_object_name => null, a_name => 'ut_passing_test'); -begin ---Act - simple_test.do_execute(); ---Assert - if simple_test.result = ut_utils.gc_error then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('simple_test.result = '||ut_utils.test_result_to_char(simple_test.result)); - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.ProcedureNameInvalid.sql b/old_tests/ut_test/ut_test.ProcedureNameInvalid.sql deleted file mode 100644 index a66f0deff..000000000 --- a/old_tests/ut_test/ut_test.ProcedureNameInvalid.sql +++ /dev/null @@ -1,16 +0,0 @@ -PROMPT Reports error when test procedure name for a test is invalid - ---Arrange -declare - simple_test ut_test := ut_test(a_object_name => 'ut_example_tests' ,a_name => 'invalid procedure name'); -begin ---Act - simple_test.do_execute(); ---Assert - if simple_test.result = ut_utils.gc_error then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('simple_test.result = '||ut_utils.test_result_to_char(simple_test.result)); - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.ProcedureNameNull.sql b/old_tests/ut_test/ut_test.ProcedureNameNull.sql deleted file mode 100644 index 1e702ab2c..000000000 --- a/old_tests/ut_test/ut_test.ProcedureNameNull.sql +++ /dev/null @@ -1,16 +0,0 @@ -PROMPT Reports error when test procedure name for a test is null - ---Arrange -declare - simple_test ut_test := ut_test(a_object_name => 'ut_example_tests', a_name => null); -begin ---Act - simple_test.do_execute(); ---Assert - if simple_test.result = ut_utils.gc_error then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('simple_test.result = '||ut_utils.test_result_to_char(simple_test.result)); - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.ReportWarningOnRollbackFailed.sql b/old_tests/ut_test/ut_test.ReportWarningOnRollbackFailed.sql deleted file mode 100644 index 0e54d401c..000000000 --- a/old_tests/ut_test/ut_test.ReportWarningOnRollbackFailed.sql +++ /dev/null @@ -1,58 +0,0 @@ -create or replace package ut_output_test_rollback -as - --%suite - - --%test - procedure tt; - -end; -/ - -create or replace package body ut_output_test_rollback -as - - procedure tt is - begin - commit; - end; - -end; -/ - -declare - l_lines ut_varchar2_list; - l_results clob; -begin - --act - select * bulk collect into l_lines from table(ut.run('ut_output_test_rollback')); - - l_results := ut_utils.table_to_clob(l_lines); - - --assert - if l_results like q'[%Warnings: -% - 1) ut_output_test_rollback.tt - Unable to perform automatic rollback after test. An implicit or explicit commit/rollback occurred in procedures: - ut3.ut_output_test_rollback.tt - Use the "--%rollback(manual)" annotation or remove commit/rollback/ddl statements that are causing the issue. -% - 2) ut_output_test_rollback - Unable to perform automatic rollback after test suite. An implicit or explicit commit/rollback occurred in procedures: - ut3.ut_output_test_rollback.tt - Use the "--%rollback(manual)" annotation or remove commit/rollback/ddl statements that are causing the issue. -% -Finished in % seconds -1 tests, 0 failed, 0 errored, 0 disabled, 2 warning(s)%]' then - :test_result := ut_utils.gc_success; - else - for i in 1 .. l_lines.count loop - dbms_output.put_line(l_lines(i)); - end loop; - dbms_output.put_line('Failed: Wrong output'); - end if; -end; -/ - -drop package ut_output_test_rollback -/ - diff --git a/old_tests/ut_test/ut_test.SetupExecutedBeforeTest.sql b/old_tests/ut_test/ut_test.SetupExecutedBeforeTest.sql deleted file mode 100644 index e928443f3..000000000 --- a/old_tests/ut_test/ut_test.SetupExecutedBeforeTest.sql +++ /dev/null @@ -1,20 +0,0 @@ -PROMPT Invoke setup procedure before test when setup procedure name is defined - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_passing_test' - ); -begin - simple_test.before_test_list := ut_executables(ut_executable(user, 'ut_example_tests', 'setup', ut_utils.gc_before_test)); - ut_example_tests.g_number := null; ---Act - simple_test.do_execute(); ---Assert - if ut_example_tests.g_number = 1 then - :test_result := ut_utils.gc_success; - end if; -end; -/ - diff --git a/old_tests/ut_test/ut_test.SetupProcedureNameInvalid.sql b/old_tests/ut_test/ut_test.SetupProcedureNameInvalid.sql deleted file mode 100644 index 3f6fab022..000000000 --- a/old_tests/ut_test/ut_test.SetupProcedureNameInvalid.sql +++ /dev/null @@ -1,19 +0,0 @@ -PROMPT Does not execute test and reports error when test setup procedure name for a test is invalid - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_exampletest' - ); -begin - simple_test.before_test_list := ut_executables(ut_executable(user, 'ut_example_tests', 'invalid setup name', ut_utils.gc_before_test)); - ut_example_tests.g_char := null; ---Act - simple_test.do_execute(); ---Assert - if simple_test.result = ut_utils.gc_error and ut_example_tests.g_char is null then - :test_result := ut_utils.gc_success; - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.SetupProcedureNameNull.sql b/old_tests/ut_test/ut_test.SetupProcedureNameNull.sql deleted file mode 100644 index 0622a2295..000000000 --- a/old_tests/ut_test/ut_test.SetupProcedureNameNull.sql +++ /dev/null @@ -1,21 +0,0 @@ -PROMPT Does not invoke setup procedure when setup procedure name for a test is null - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_passing_test' - ); -begin - simple_test.before_test_list := ut_executables(ut_executable(user, 'ut_example_tests', null, ut_utils.gc_before_test)); - ut_example_tests.g_number := null; ---Act - simple_test.do_execute(); ---Assert - if ut_example_tests.g_number is null then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('expected: ut_example_tests.g_number is null, got: '||ut_example_tests.g_number ); - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.TeardownExecutedAfterTest.sql b/old_tests/ut_test/ut_test.TeardownExecutedAfterTest.sql deleted file mode 100644 index 55c0026c1..000000000 --- a/old_tests/ut_test/ut_test.TeardownExecutedAfterTest.sql +++ /dev/null @@ -1,19 +0,0 @@ -PROMPT Invoke teardown procedure after test when teardown procedure name is defined - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_passing_test' - ); -begin - simple_test.after_test_list := ut_executables(ut_executable(user, 'ut_example_tests', 'teardown', ut_utils.gc_after_test)); ---Act - simple_test.do_execute(); ---Assert - if simple_test.result = ut_utils.gc_success and ut_example_tests.g_char is null then - :test_result := ut_utils.gc_success; - end if; -end; -/ - diff --git a/old_tests/ut_test/ut_test.TeardownProcedureNameInvalid.sql b/old_tests/ut_test/ut_test.TeardownProcedureNameInvalid.sql deleted file mode 100644 index 86bdff66a..000000000 --- a/old_tests/ut_test/ut_test.TeardownProcedureNameInvalid.sql +++ /dev/null @@ -1,19 +0,0 @@ -PROMPT Does not execute test and reports error when test teardown procedure name for a test is invalid - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_exampletest' - ); -begin - simple_test.after_test_list := ut_executables(ut_executable(user, 'ut_example_tests', 'invalid setup name', ut_utils.gc_after_test)); - ut_example_tests.g_char := 'x'; ---Act - simple_test.do_execute(); ---Assert - if ut_example_tests.g_char = 'x' and simple_test.result = ut_utils.gc_error then - :test_result := ut_utils.gc_success; - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.TeardownProcedureNameNull.sql b/old_tests/ut_test/ut_test.TeardownProcedureNameNull.sql deleted file mode 100644 index a1837d20c..000000000 --- a/old_tests/ut_test/ut_test.TeardownProcedureNameNull.sql +++ /dev/null @@ -1,20 +0,0 @@ -PROMPT Does not invoke teardown procedure when teardown procedure name for a test is null - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_passing_test' - ); -begin - simple_test.after_test_list := ut_executables(ut_executable(user, 'ut_example_tests', null, ut_utils.gc_after_test)); ---Act - simple_test.do_execute(); ---Assert - if ut_example_tests.g_char = 'a' then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('expected: ut_example_tests.g_char = ''a'', got: '''||ut_example_tests.g_char||'''' ); - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.TestOutputGathering.sql b/old_tests/ut_test/ut_test.TestOutputGathering.sql deleted file mode 100644 index 14181a4b0..000000000 --- a/old_tests/ut_test/ut_test.TestOutputGathering.sql +++ /dev/null @@ -1,103 +0,0 @@ -create or replace package ut_output_tests -as - --%suite - - --%beforeeach - procedure beforeeach; - - --%aftereach - procedure aftereach; - - --%test - --%beforetest(beforetest) - --%aftertest(aftertest) - procedure ut_passing_test; - - procedure beforetest; - - procedure aftertest; - - --%beforeall - procedure beforeall; - --%afterall - procedure afterall; - -end; -/ - -create or replace package body ut_output_tests -as - - procedure beforetest as - begin - dbms_output.put_line(''); - end; - - procedure aftertest - as - begin - dbms_output.put_line(''); - end; - - procedure beforeeach as - begin - dbms_output.put_line(''); - end; - - procedure aftereach - as - begin - dbms_output.put_line(''); - end; - - procedure ut_passing_test - as - begin - dbms_output.put_line(''); - ut.expect(1,'Test 1 Should Pass').to_equal(1); - end; - - procedure beforeall is - begin - dbms_output.put_line(''); - end; - - procedure afterall is - begin - dbms_output.put_line(''); - end; - -end; -/ - -declare - l_output_data dbms_output.chararr; - l_num_lines integer := 100000; - l_output clob; -begin - --act - ut.run('ut_output_tests'); - - --assert - dbms_output.get_lines( l_output_data, l_num_lines); - dbms_lob.createtemporary(l_output,true); - for i in 1 .. l_num_lines loop - dbms_lob.append(l_output,l_output_data(i)); - end loop; - - if l_output like '%%%%%%%%1 tests, 0 failed, 0 errored%' then - :test_result := ut_utils.gc_success; - end if; - - if :test_result != ut_utils.gc_success or :test_result is null then - for i in 1 .. l_num_lines loop - dbms_output.put_line(l_output_data(i)); - end loop; - dbms_output.put_line('Failed: Wrong output'); - end if; -end; -/ - -drop package ut_output_tests -/ - diff --git a/old_tests/ut_test/ut_test.TestOutputGatheringWhenEmpty.sql b/old_tests/ut_test/ut_test.TestOutputGatheringWhenEmpty.sql deleted file mode 100644 index dcd82fbad..000000000 --- a/old_tests/ut_test/ut_test.TestOutputGatheringWhenEmpty.sql +++ /dev/null @@ -1,55 +0,0 @@ -create or replace package ut_output_tests -as - --%suite - - --%test - procedure ut_passing_test; - -end; -/ - -create or replace package body ut_output_tests -as - - procedure ut_passing_test - as - begin - --Generate empty output - dbms_output.put_line(''); - ut.expect(1,'Test 1 Should Pass').to_equal(1); - end; - -end; -/ - -declare - l_output_data dbms_output.chararr; - l_num_lines integer := 100000; - l_output clob; -begin - --act - ut.run('ut_output_tests'); - - --assert - dbms_output.get_lines( l_output_data, l_num_lines); - dbms_lob.createtemporary(l_output,true); - for i in 1 .. l_num_lines loop - dbms_lob.append(l_output,l_output_data(i)); - end loop; - - if l_output like '%0 failed, 0 errored, 0 disabled, 0 warning(s)%' then - :test_result := ut_utils.gc_success; - end if; - - if :test_result != ut_utils.gc_success or :test_result is null then - for i in 1 .. l_num_lines loop - dbms_output.put_line(l_output_data(i)); - end loop; - dbms_output.put_line('Failed: Wrong output'); - end if; -end; -/ - -drop package ut_output_tests -/ - diff --git a/sonar-project.properties b/sonar-project.properties index a1fabbede..e13de646b 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -9,7 +9,7 @@ sonar.projectVersion=v3.1.3-develop # If not set, SonarQube starts looking for source code from the directory containing # the sonar-project.properties file. sonar.sources=./source -sonar.coverageReportPaths=./old_tests/coverage.xml,coverage.xml +sonar.coverageReportPaths=coverage.xml sonar.tests=./test sonar.testExecutionReportPaths=./test_results.xml sonar.links.issue=https://github.com/utPLSQL/utPLSQL/issues diff --git a/source/api/ut_runner.pkb b/source/api/ut_runner.pkb index c04fa5112..816e9e302 100644 --- a/source/api/ut_runner.pkb +++ b/source/api/ut_runner.pkb @@ -128,7 +128,7 @@ create or replace package body ut_runner is l_include_object_names := to_ut_object_list(a_include_objects, l_coverage_schema_names); l_run := ut_run( - ut_suite_manager.configure_execution_by_path(l_paths), + null, l_paths, l_coverage_schema_names, l_exclude_object_names, @@ -137,6 +137,7 @@ create or replace package body ut_runner is set(a_test_file_mappings), a_client_character_set ); + ut_suite_manager.configure_execution_by_path(l_paths, l_run.items); l_run.do_execute(); finish_run(l_run); @@ -164,21 +165,12 @@ create or replace package body ut_runner is ut_annotation_manager.purge_cache(a_object_owner, a_object_type); end; - function get_unit_test_info(a_owner varchar2, a_package_name varchar2 := null) return tt_annotations pipelined is + function get_suites_info(a_owner varchar2 := null, a_package_name varchar2 := null) return ut_suite_items_info pipelined is l_cursor sys_refcursor; - l_filter varchar2(100); - l_ut_owner varchar2(250) := ut_utils.ut_owner; - l_results tt_annotations; + l_results ut_suite_items_info; c_bulk_limit constant integer := 10; begin - l_filter := case when a_package_name is null then 'is null' else '= o.object_name' end; - open l_cursor for - 'select o.object_owner, o.object_name, upper(a.subobject_name),' || - ' a.position, a.name, a.text' || - ' from table('||l_ut_owner||'.ut_annotation_manager.get_annotated_objects(:a_owner, ''PACKAGE'')) o,' || - ' table(o.annotations) a' || - ' where :a_package_name ' || l_filter - using a_owner, a_package_name; + l_cursor := ut_suite_manager.get_suites_info( nvl(a_owner,sys_context('userenv', 'current_schema')), a_package_name ); loop fetch l_cursor bulk collect into l_results limit c_bulk_limit; for i in 1 .. l_results.count loop @@ -190,6 +182,42 @@ create or replace package body ut_runner is return; end; + function is_test(a_owner varchar2, a_package_name varchar2, a_procedure_name varchar2) return boolean is + l_result boolean := false; + begin + if a_owner is not null and a_package_name is not null and a_procedure_name is not null then + + l_result := ut_suite_manager.suite_item_exists( a_owner, a_package_name, a_procedure_name ); + + end if; + + return l_result; + end; + + function is_suite(a_owner varchar2, a_package_name varchar2) return boolean is + l_result boolean := false; + begin + if a_owner is not null and a_package_name is not null then + + l_result := ut_suite_manager.suite_item_exists( a_owner, a_package_name ); + + end if; + + return l_result; + end; + + function has_suites(a_owner varchar2) return boolean is + l_result boolean := false; + begin + if a_owner is not null then + + l_result := ut_suite_manager.suite_item_exists( a_owner ); + + end if; + + return l_result; + end; + function get_reporters_list return tt_reporters_info pipelined is l_cursor sys_refcursor; l_owner varchar2(128) := upper(ut_utils.ut_owner()); diff --git a/source/api/ut_runner.pks b/source/api/ut_runner.pks index 45b8cb642..acef16c50 100644 --- a/source/api/ut_runner.pks +++ b/source/api/ut_runner.pks @@ -43,6 +43,7 @@ create or replace package ut_runner authid current_user is * @param a_include_objects list of database objects (in format 'owner.name') that coverage should be reported on * @param a_exclude_objects list of database objects (in format 'owner.name') that coverage should be skipped for * @param a_fail_on_errors true/false - should an exception be thrown when tests are completed with failures/errors + * @param a_client_character_set if provided, affects some of reporters by setting specific character set for XML/HTML reports * * @example * Parameter `a_paths` accepts values of the following formats: @@ -87,24 +88,40 @@ create or replace package ut_runner authid current_user is procedure purge_cache(a_object_owner varchar2 := null, a_object_type varchar2 := null); - type t_annotation_rec is record ( - package_owner varchar2(250), - package_name varchar2(250), - procedure_name varchar2(250), - annotation_pos number(5,0), - annotation_name varchar2(1000), - annotation_text varchar2(4000) - ); - type tt_annotations is table of t_annotation_rec; + /** + * Returns a pipelined collection containing information about unit test suites and the tests contained in them + * + * @param a_owner owner of unit tests to retrieve (optional), if NULL, current schema is used + * @param a_package_name name of unit test package to retrieve (optional), if NULL all unit test packages are returned + * @return ut_suite_items_info table of objects + */ + function get_suites_info(a_owner varchar2 := null, a_package_name varchar2 := null) return ut_suite_items_info pipelined; + /** - * Returns a pipelined collection containing information about unit tests package/packages for a given owner + * Returns true if given procedure is a test in a test suite, false otherwise + * + * @param a_owner owner of test package + * @param a_package_name name of test package + * @param a_procedure_name name of test procedure + */ + function is_test(a_owner varchar2, a_package_name varchar2, a_procedure_name varchar2) return boolean; + + /** + * Returns true if given package is a test suite, false otherwise + * + * @param a_owner owner of test package + * @param a_package_name name of test package + */ + function is_suite(a_owner varchar2, a_package_name varchar2) return boolean; + + /** + * Returns true if given schema contains test suites, false otherwise * - * @param a_owner owner of unit tests to retrieve - * @param a_package_name optional name of unit test package to retrieve, if NULLm all unit test packages are returned - * @return tt_annotations table of records + * @param a_owner owner of test package */ - function get_unit_test_info(a_owner varchar2, a_package_name varchar2 := null) return tt_annotations pipelined; + function has_suites(a_owner varchar2) return boolean; + type t_reporter_rec is record ( reporter_object_name varchar2(250), diff --git a/source/api/ut_suite_item_info.tps b/source/api/ut_suite_item_info.tps new file mode 100644 index 000000000..bf6fd6ecf --- /dev/null +++ b/source/api/ut_suite_item_info.tps @@ -0,0 +1,27 @@ +create or replace type ut_suite_item_info as object ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2018 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. + */ + object_owner varchar2( 250 ), -- the owner of test suite packages + object_name varchar2( 250 ), -- the name of test suite package + item_name varchar2( 250 ), -- the name of suite/test + item_description varchar2( 250 ), -- the description of suite/suite item + item_type varchar2( 250 ), -- the type of item (UT_SUITE/UT_SUITE_CONTEXT/UT_TEST) + item_line_no integer, -- line_number where annotation identifying the item exists + path varchar2( 4000 ),-- suitepath of the item + disabled_flag integer -- 0 (zero) if item is not disabled, 1 if item is disabled by --%disabled annotation +) +/ diff --git a/source/api/ut_suite_items_info.tps b/source/api/ut_suite_items_info.tps new file mode 100644 index 000000000..d84ed9092 --- /dev/null +++ b/source/api/ut_suite_items_info.tps @@ -0,0 +1,19 @@ +create or replace type ut_suite_items_info as + /* + utPLSQL - Version 3 + Copyright 2016 - 2018 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. + */ + table of ut_suite_item_info +/ diff --git a/source/core/annotations/ut_annotated_object.tps b/source/core/annotations/ut_annotated_object.tps index 4bf141a3f..1bfefed69 100644 --- a/source/core/annotations/ut_annotated_object.tps +++ b/source/core/annotations/ut_annotated_object.tps @@ -18,6 +18,7 @@ create type ut_annotated_object as object( object_owner varchar2(250), object_name varchar2(250), object_type varchar2(50), + parse_time timestamp, annotations ut_annotations ) / diff --git a/source/core/annotations/ut_annotation_cache_info.sql b/source/core/annotations/ut_annotation_cache_info.sql index 48f8a606c..fa7eabeec 100644 --- a/source/core/annotations/ut_annotation_cache_info.sql +++ b/source/core/annotations/ut_annotation_cache_info.sql @@ -16,7 +16,7 @@ create table ut_annotation_cache_info ( object_owner varchar2(250) not null, object_name varchar2(250) not null, object_type varchar2(250) not null, - parse_time date not null, + parse_time timestamp not null, constraint ut_annotation_cache_info_pk primary key(cache_id), constraint ut_annotation_cache_info_uk unique (object_owner, object_name, object_type) ) organization index; diff --git a/source/core/annotations/ut_annotation_cache_manager.pkb b/source/core/annotations/ut_annotation_cache_manager.pkb index a05914e37..5c40be5b7 100644 --- a/source/core/annotations/ut_annotation_cache_manager.pkb +++ b/source/core/annotations/ut_annotation_cache_manager.pkb @@ -18,18 +18,17 @@ create or replace package body ut_annotation_cache_manager as procedure update_cache(a_object ut_annotated_object) is l_cache_id integer; - l_current_schema varchar2(250) := ut_utils.ut_owner; pragma autonomous_transaction; begin update ut_annotation_cache_info i - set i.parse_time = sysdate + set i.parse_time = systimestamp where (i.object_owner, i.object_name, i.object_type) in ((a_object.object_owner, a_object.object_name, a_object.object_type)) returning cache_id into l_cache_id; if sql%rowcount = 0 then insert into ut_annotation_cache_info (cache_id, object_owner, object_name, object_type, parse_time) - values (ut_annotation_cache_seq.nextval, a_object.object_owner, a_object.object_name, a_object.object_type, sysdate) + values (ut_annotation_cache_seq.nextval, a_object.object_owner, a_object.object_name, a_object.object_type, systimestamp) returning cache_id into l_cache_id; end if; @@ -37,17 +36,10 @@ create or replace package body ut_annotation_cache_manager as where cache_id = l_cache_id; if a_object.annotations is not null and a_object.annotations.count > 0 then --- begin insert into ut_annotation_cache (cache_id, annotation_position, annotation_name, annotation_text, subobject_name) select l_cache_id, a.position, a.name, a.text, a.subobject_name from table(a_object.annotations) a; - --TODO - duplicate annotations found?? - should not happen, getting standalone annotations need to happen after procedure annotations were parsed --- exception --- when others then --- dbms_output.put_line(xmltype(anydata.convertCollection(a_object.annotations)).getclobval); --- raise; --- end; end if; commit; end; @@ -73,20 +65,35 @@ create or replace package body ut_annotation_cache_manager as on (o.object_name = i.object_name and o.object_type = i.object_type and o.object_owner = i.object_owner) - when matched then update set parse_time = sysdate + when matched then update set parse_time = systimestamp when not matched then insert (cache_id, object_owner, object_name, object_type, parse_time) - values (ut_annotation_cache_seq.nextval, o.object_owner, o.object_name, o.object_type, sysdate); + values (ut_annotation_cache_seq.nextval, o.object_owner, o.object_name, o.object_type, systimestamp); commit; end; - function get_annotations_for_objects(a_cached_objects ut_annotation_objs_cache_info) return sys_refcursor is + procedure remove_from_cache(a_objects ut_annotation_objs_cache_info) is + pragma autonomous_transaction; + begin + + delete from ut_annotation_cache_info i + where exists ( + select 1 from table (a_objects) o + where o.object_name = i.object_name + and o.object_type = i.object_type + and o.object_owner = i.object_owner + ); + + commit; + end; + + function get_annotations_for_objects(a_cached_objects ut_annotation_objs_cache_info, a_parse_time timestamp) return sys_refcursor is l_results sys_refcursor; begin - open l_results for + open l_results for q'[ select ut_annotated_object( - o.object_owner, o.object_name, o.object_type, + i.object_owner, i.object_name, i.object_type, i.parse_time, cast( collect( ut_annotation( @@ -95,11 +102,13 @@ create or replace package body ut_annotation_cache_manager as ) as ut_annotations ) ) - from table(a_cached_objects) o + from table(:a_cached_objects) o join ut_annotation_cache_info i on o.object_owner = i.object_owner and o.object_name = i.object_name and o.object_type = i.object_type join ut_annotation_cache c on i.cache_id = c.cache_id - group by o.object_owner, o.object_name, o.object_type; + where ]'|| case when a_parse_time is null then ':a_parse_date is null' else 'i.parse_time > :a_parse_time' end ||q'[ + group by i.object_owner, i.object_name, i.object_type, i.parse_time]' + using a_cached_objects, a_parse_time; return l_results; end; diff --git a/source/core/annotations/ut_annotation_cache_manager.pks b/source/core/annotations/ut_annotation_cache_manager.pks index d37212d69..1279c8cc3 100644 --- a/source/core/annotations/ut_annotation_cache_manager.pks +++ b/source/core/annotations/ut_annotation_cache_manager.pks @@ -32,15 +32,22 @@ create or replace package ut_annotation_cache_manager authid definer as * * @param a_cached_objects a `ut_annotation_objs_cache_info` list with information about objects to get from cache */ - function get_annotations_for_objects(a_cached_objects ut_annotation_objs_cache_info) return sys_refcursor; + function get_annotations_for_objects(a_cached_objects ut_annotation_objs_cache_info, a_parse_time timestamp) return sys_refcursor; /** * Removes cached information about annotations for objects on the list and updates parse_time in cache info table. * - * @param a_objects a `ut_annotation_objs_cache_info` list with information about objects to remove from cache + * @param a_objects a `ut_annotation_objs_cache_info` list with information about objects to remove annotations for */ procedure cleanup_cache(a_objects ut_annotation_objs_cache_info); + /** + * Removes information about objects on the list + * + * @param a_objects a `ut_annotation_objs_cache_info` list with information about objects to remove from cache + */ + procedure remove_from_cache(a_objects ut_annotation_objs_cache_info); + /** * Removes cached information about annotations for objects of specified type and specified owner * diff --git a/source/core/annotations/ut_annotation_cache_seq.sql b/source/core/annotations/ut_annotation_cache_seq.sql index 028225ddb..1cc97086e 100644 --- a/source/core/annotations/ut_annotation_cache_seq.sql +++ b/source/core/annotations/ut_annotation_cache_seq.sql @@ -12,5 +12,5 @@ create sequence ut_annotation_cache_seq See the License for the specific language governing permissions and limitations under the License. */ -cache 20; +cache 100; diff --git a/source/core/annotations/ut_annotation_manager.pkb b/source/core/annotations/ut_annotation_manager.pkb index e44e5dd10..6dbe1d3ec 100644 --- a/source/core/annotations/ut_annotation_manager.pkb +++ b/source/core/annotations/ut_annotation_manager.pkb @@ -19,45 +19,89 @@ create or replace package body ut_annotation_manager as ------------------------------ --private definitions - function get_annotation_objs_info_cur(a_object_owner varchar2, a_object_type varchar2) return sys_refcursor is - l_result sys_refcursor; + function get_missing_objects(a_object_owner varchar2, a_object_type varchar2) return ut_annotation_objs_cache_info is + l_rows sys_refcursor; l_ut_owner varchar2(250) := ut_utils.ut_owner; - l_objects_view varchar2(200) := ut_metadata.get_dba_view('dba_objects'); - l_cursor_text long; + l_objects_view varchar2(200) := ut_metadata.get_objects_view_name(); + l_cursor_text varchar2(32767); + l_result ut_annotation_objs_cache_info; + begin + l_cursor_text := + q'[select ]'||l_ut_owner||q'[.ut_annotation_obj_cache_info( + object_owner => i.object_owner, + object_name => i.object_name, + object_type => i.object_type, + needs_refresh => null + ) + from ]'||l_ut_owner||q'[.ut_annotation_cache_info i + where + not exists ( + select 1 from ]'||l_objects_view||q'[ o + where o.owner = i.object_owner + and o.object_name = i.object_name + and o.object_type = i.object_type + and o.owner = :a_object_owner + and o.object_type = :a_object_type + ) + and i.object_owner = :a_object_owner + and i.object_type = :a_object_type]'; + open l_rows for l_cursor_text using a_object_owner, a_object_type, a_object_owner, a_object_type; + fetch l_rows bulk collect into l_result limit 1000000; + close l_rows; + return l_result; + end; + + function get_annotation_objs_info(a_object_owner varchar2, a_object_type varchar2, a_parse_date timestamp := null) return ut_annotation_objs_cache_info is + l_rows sys_refcursor; + l_ut_owner varchar2(250) := ut_utils.ut_owner; + l_objects_view varchar2(200) := ut_metadata.get_objects_view_name(); + l_cursor_text varchar2(32767); + l_result ut_annotation_objs_cache_info; begin l_cursor_text := q'[select ]'||l_ut_owner||q'[.ut_annotation_obj_cache_info( object_owner => o.owner, object_name => o.object_name, object_type => o.object_type, - needs_refresh => case when o.last_ddl_time < i.parse_time then 'N' else 'Y' end + needs_refresh => case when o.last_ddl_time < cast(i.parse_time as date) then 'N' else 'Y' end ) from ]'||l_objects_view||q'[ o left join ]'||l_ut_owner||q'[.ut_annotation_cache_info i - on o.owner = i.object_owner and o.object_name = i.object_name and o.object_type = i.object_type - where o.owner = :a_object_owner - and o.object_type = :a_object_type]'; - open l_result for l_cursor_text using a_object_owner, a_object_type; + on o.owner = i.object_owner + and o.object_name = i.object_name + and o.object_type = i.object_type + where o.owner = ']'||a_object_owner||q'[' + and o.object_type = ']'||a_object_type||q'[' + and ]' + || case + when a_parse_date is null + then ':a_parse_date is null' + else 'o.last_ddl_time >= cast(:a_parse_date as date)' + end; + open l_rows for l_cursor_text using a_parse_date; + fetch l_rows bulk collect into l_result limit 1000000; + close l_rows; return l_result; end; function get_sources_to_annotate(a_object_owner varchar2, a_object_type varchar2) return sys_refcursor is l_result sys_refcursor; - l_sources_view varchar2(200) := ut_metadata.get_dba_view('dba_source'); + l_sources_view varchar2(200) := ut_metadata.get_source_view_name(); begin open l_result for q'[select s.name, s.text - from ]'||l_sources_view||q'[ s - where s.type = :a_object_type - and s.owner = :a_object_owner - and s.name - in (select x.name - from ]'||l_sources_view||q'[ x - where x.type = :a_object_type - and x.owner = :a_object_owner - and x.text like '%--%\%%' escape '\' - ) - order by name, line]' + from (select s.name, s.text, s.line, + max(case when s.text like '%--%\%%' escape '\' + and regexp_like(s.text,'--\s*%') + then 'Y' else 'N' end + ) + over(partition by s.name) is_annotated + from ]'||l_sources_view||q'[ s + where s.type = :a_object_type + and s.owner = :a_object_owner + ) s + where s.is_annotated = 'Y' + order by s.name, s.line]' using a_object_type, a_object_owner, a_object_type, a_object_owner; return l_result; @@ -65,37 +109,38 @@ create or replace package body ut_annotation_manager as function get_sources_to_annotate(a_object_owner varchar2, a_object_type varchar2, a_objects_to_refresh ut_annotation_objs_cache_info) return sys_refcursor is l_result sys_refcursor; - l_sources_view varchar2(200) := ut_metadata.get_dba_view('dba_source'); + l_sources_view varchar2(200) := ut_metadata.get_source_view_name(); l_card natural; begin l_card := ut_utils.scale_cardinality(cardinality(a_objects_to_refresh)); open l_result for - q'[select /*+ cardinality( r ]'||l_card||q'[ )*/ - s.name, s.text - from table(:a_objects_to_refresh) r - join ]'||l_sources_view||q'[ s - on s.name = r.object_name - where s.type = :a_object_type - and s.owner = :a_object_owner - and s.name - in (select /*+ cardinality( t ]'||l_card||q'[ )*/ - x.name - from table(:a_objects_to_refresh) t - join ]'||l_sources_view||q'[ x - on x.name = t.object_name - where x.type = :a_object_type - and x.owner = :a_object_owner - and x.text like '%--%\%%' escape '\' - ) - order by name, line]' - using a_objects_to_refresh, a_object_type, a_object_owner, a_objects_to_refresh, a_object_type, a_object_owner; + q'[select s.name, s.text + from (select /*+ cardinality( r ]'||l_card||q'[ )*/ + s.name, s.text, s.line, + max(case when s.text like '%--%\%%' escape '\' + and regexp_like(s.text,'--\s*%') + then 'Y' else 'N' end + ) + over(partition by s.name) is_annotated + from table(:a_objects_to_refresh) r + join ]'||l_sources_view||q'[ s + on s.name = r.object_name + and s.owner = r.object_owner + and s.type = r.object_type + where s.type = :a_object_type + and s.owner = :a_object_owner + ) s + where s.is_annotated = 'Y' + order by s.name, s.line]' + using a_objects_to_refresh, a_object_type, a_object_owner; return l_result; end; procedure build_annot_cache_for_sources( - a_object_owner varchar2, a_object_type varchar2, a_sources_cursor sys_refcursor, - a_schema_objects ut_annotation_objs_cache_info + a_object_owner varchar2, + a_object_type varchar2, + a_sources_cursor sys_refcursor ) is l_annotations ut_annotations; c_lines_fetch_limit constant integer := 1000; @@ -103,16 +148,16 @@ create or replace package body ut_annotation_manager as l_names dbms_preprocessor.source_lines_t; l_name varchar2(250); l_object_lines dbms_preprocessor.source_lines_t; + l_parse_time date := sysdate; pragma autonomous_transaction; begin - ut_annotation_cache_manager.cleanup_cache(a_schema_objects); loop fetch a_sources_cursor bulk collect into l_names, l_lines limit c_lines_fetch_limit; for i in 1 .. l_names.count loop if l_names(i) != l_name then l_annotations := ut_annotation_parser.parse_object_annotations(l_object_lines); ut_annotation_cache_manager.update_cache( - ut_annotated_object(a_object_owner, l_name, a_object_type, l_annotations) + ut_annotated_object(a_object_owner, l_name, a_object_type, l_parse_time, l_annotations) ); l_object_lines.delete; end if; @@ -126,7 +171,7 @@ create or replace package body ut_annotation_manager as if a_sources_cursor%rowcount > 0 then l_annotations := ut_annotation_parser.parse_object_annotations(l_object_lines); ut_annotation_cache_manager.update_cache( - ut_annotated_object(a_object_owner, l_name, a_object_type, l_annotations) + ut_annotated_object(a_object_owner, l_name, a_object_type, l_parse_time, l_annotations) ); l_object_lines.delete; end if; @@ -135,37 +180,33 @@ create or replace package body ut_annotation_manager as end; - procedure rebuild_annotation_cache( a_object_owner varchar2, a_object_type varchar2, a_info_rows ut_annotation_objs_cache_info) is - l_objects_in_cache_count integer; - l_objects_to_parse ut_annotation_objs_cache_info := ut_annotation_objs_cache_info(); + procedure rebuild_annotation_cache( + a_object_owner varchar2, + a_object_type varchar2, + a_info_rows ut_annotation_objs_cache_info + ) is + l_objects_to_parse ut_annotation_objs_cache_info; begin - --get list of objects in cache - select count( 1)into l_objects_in_cache_count from table(a_info_rows) x where x.needs_refresh = 'N'; + select value(x)bulk collect into l_objects_to_parse + from table(a_info_rows) x where x.needs_refresh = 'Y'; - --if cache is empty and there are objects to parse - if l_objects_in_cache_count = 0 and a_info_rows.count > 0 then + ut_annotation_cache_manager.cleanup_cache(l_objects_to_parse); + if sys_context('userenv','current_schema') = a_object_owner + or ut_metadata.user_has_execute_any_proc() + or ut_metadata.is_object_visible('dba_objects') + then + ut_annotation_cache_manager.remove_from_cache( + get_missing_objects(a_object_owner, a_object_type) + ); + end if; + + --if some source needs parsing and putting into cache + if l_objects_to_parse.count > 0 then build_annot_cache_for_sources( a_object_owner, a_object_type, - --all schema objects - get_sources_to_annotate(a_object_owner, a_object_type), - a_info_rows + get_sources_to_annotate(a_object_owner, a_object_type, l_objects_to_parse) ); - - --if not all in cache, get list of objects to rebuild cache for - elsif l_objects_in_cache_count < a_info_rows.count then - - select value(x)bulk collect into l_objects_to_parse from table(a_info_rows) x where x.needs_refresh = 'Y'; - - --if some source needs parsing and putting into cache - if l_objects_to_parse.count > 0 then - build_annot_cache_for_sources( - a_object_owner, a_object_type, - get_sources_to_annotate(a_object_owner, a_object_type, l_objects_to_parse), - l_objects_to_parse - ); - end if; - end if; end; @@ -173,30 +214,26 @@ create or replace package body ut_annotation_manager as --public definitions ------------------------------------------------------------ procedure rebuild_annotation_cache(a_object_owner varchar2, a_object_type varchar2) is - l_info_cursor sys_refcursor; - l_info_rows ut_annotation_objs_cache_info; begin - l_info_cursor := get_annotation_objs_info_cur(a_object_owner, a_object_type); - fetch l_info_cursor bulk collect into l_info_rows; - close l_info_cursor; - rebuild_annotation_cache(a_object_owner, a_object_type, l_info_rows); + rebuild_annotation_cache( + a_object_owner, + a_object_type, + get_annotation_objs_info(a_object_owner, a_object_type, null) + ); end; - function get_annotated_objects(a_object_owner varchar2, a_object_type varchar2) return ut_annotated_objects pipelined is - l_info_cursor sys_refcursor; + function get_annotated_objects(a_object_owner varchar2, a_object_type varchar2, a_parse_date timestamp := null) return ut_annotated_objects pipelined is l_info_rows ut_annotation_objs_cache_info; l_cursor sys_refcursor; l_results ut_annotated_objects; c_object_fetch_limit constant integer := 10; begin - - l_info_cursor := get_annotation_objs_info_cur(a_object_owner, a_object_type); - fetch l_info_cursor bulk collect into l_info_rows; - close l_info_cursor; + + l_info_rows := get_annotation_objs_info(a_object_owner, a_object_type, a_parse_date); rebuild_annotation_cache(a_object_owner, a_object_type, l_info_rows); --pipe annotations from cache - l_cursor := ut_annotation_cache_manager.get_annotations_for_objects(l_info_rows); + l_cursor := ut_annotation_cache_manager.get_annotations_for_objects(l_info_rows, a_parse_date); loop fetch l_cursor bulk collect into l_results limit c_object_fetch_limit; for i in 1 .. l_results.count loop @@ -205,7 +242,6 @@ create or replace package body ut_annotation_manager as exit when l_cursor%notfound; end loop; close l_cursor; - end; procedure purge_cache(a_object_owner varchar2, a_object_type varchar2) is diff --git a/source/core/annotations/ut_annotation_manager.pks b/source/core/annotations/ut_annotation_manager.pks index a2925c388..829142bd5 100644 --- a/source/core/annotations/ut_annotation_manager.pks +++ b/source/core/annotations/ut_annotation_manager.pks @@ -27,9 +27,10 @@ create or replace package ut_annotation_manager authid current_user as * * @param a_object_owner owner of objects to get annotations for * @param a_object_type type of objects to get annotations for + * @param a_parse_date date when object was last parsed * @return array containing annotated objects along with annotations for each object (nested) */ - function get_annotated_objects(a_object_owner varchar2, a_object_type varchar2) return ut_annotated_objects pipelined; + function get_annotated_objects(a_object_owner varchar2, a_object_type varchar2, a_parse_date timestamp := null) return ut_annotated_objects pipelined; /** * Rebuilds annotation cache for a specified schema and object type. diff --git a/source/core/annotations/ut_annotation_parser.pkb b/source/core/annotations/ut_annotation_parser.pkb index 2467c6262..aec9e7585 100644 --- a/source/core/annotations/ut_annotation_parser.pkb +++ b/source/core/annotations/ut_annotation_parser.pkb @@ -155,7 +155,7 @@ create or replace package body ut_annotation_parser as -- position index is shifted by 1 because gc_annot_comment_pattern contains ^ as first sign -- but after instr index already points to the char on that line l_comment_pos := l_comment_pos-1; - l_comment_line := regexp_count(substr(a_source,1,l_comment_pos),chr(10),1,'m')+1; + l_comment_line := length(substr(a_source,1,l_comment_pos))-length(replace(substr(a_source,1,l_comment_pos),chr(10)))+1; l_comments(l_comment_line) := trim(regexp_substr(srcstr => a_source ,pattern => gc_annot_comment_pattern ,occurrence => 1 diff --git a/source/core/coverage/ut_coverage.pkb b/source/core/coverage/ut_coverage.pkb index 64d625d84..6acca42bd 100644 --- a/source/core/coverage/ut_coverage.pkb +++ b/source/core/coverage/ut_coverage.pkb @@ -38,7 +38,7 @@ create or replace package body ut_coverage is function get_cov_sources_sql(a_coverage_options ut_coverage_options) return varchar2 is l_result varchar2(32767); l_full_name varchar2(100); - l_view_name varchar2(200) := ut_metadata.get_dba_view('dba_source'); + l_view_name varchar2(200) := ut_metadata.get_source_view_name(); begin if a_coverage_options.file_mappings is not null and a_coverage_options.file_mappings.count > 0 then l_full_name := 'f.file_name'; @@ -135,7 +135,7 @@ create or replace package body ut_coverage is l_cov_sources_crsr := get_cov_sources_cursor(a_coverage_options,a_sql); loop - fetch l_cov_sources_crsr bulk collect into l_cov_sources_data limit 1000; + fetch l_cov_sources_crsr bulk collect into l_cov_sources_data limit 10000; ut_coverage_helper.insert_into_tmp_table(l_cov_sources_data); diff --git a/source/core/output_buffers/ut_output_buffer_base.tps b/source/core/output_buffers/ut_output_buffer_base.tps index f1d71c502..6f69047d9 100644 --- a/source/core/output_buffers/ut_output_buffer_base.tps +++ b/source/core/output_buffers/ut_output_buffer_base.tps @@ -20,6 +20,7 @@ create or replace type ut_output_buffer_base authid definer as object( 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 procedure send_lines(self in ut_output_buffer_base, a_text_list ut_varchar2_rows), 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) diff --git a/source/core/output_buffers/ut_output_table_buffer.tpb b/source/core/output_buffers/ut_output_table_buffer.tpb index 0cc68b76b..e7045b9df 100644 --- a/source/core/output_buffers/ut_output_table_buffer.tpb +++ b/source/core/output_buffers/ut_output_table_buffer.tpb @@ -47,16 +47,15 @@ create or replace type body ut_output_table_buffer is 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; + self.send_lines( + ut_utils.convert_collection( + ut_utils.clob_to_table(a_text, ut_utils.gc_max_storage_varchar2_len) + ) + ); else insert into ut_output_buffer_tmp(output_id, message_id, text) values (self.output_id, ut_message_id_seq.nextval, a_text); @@ -65,6 +64,18 @@ create or replace type body ut_output_table_buffer is end if; end; + overriding member procedure send_lines(self in ut_output_table_buffer, a_text_list ut_varchar2_rows) is + pragma autonomous_transaction; + begin + 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(a_text_list) t + where t.column_value is not null; + + commit; + 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; diff --git a/source/core/output_buffers/ut_output_table_buffer.tps b/source/core/output_buffers/ut_output_table_buffer.tps index 96628de77..0e6f83770 100644 --- a/source/core/output_buffers/ut_output_table_buffer.tps +++ b/source/core/output_buffers/ut_output_table_buffer.tps @@ -20,6 +20,7 @@ create or replace type ut_output_table_buffer under ut_output_buffer_base ( 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 send_lines(self in ut_output_table_buffer, a_text_list ut_varchar2_rows), 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, diff --git a/source/core/types/ut_console_reporter_base.tpb b/source/core/types/ut_console_reporter_base.tpb index 70513223c..0245edde3 100644 --- a/source/core/types/ut_console_reporter_base.tpb +++ b/source/core/types/ut_console_reporter_base.tpb @@ -36,20 +36,10 @@ create or replace type body ut_console_reporter_base is self.print_text(ut_ansiconsole_helper.yellow(a_text)); end; - member procedure print_blue_text(self in out nocopy ut_console_reporter_base, a_text varchar2) is - begin - self.print_text(ut_ansiconsole_helper.red(a_text)); - end; - member procedure print_cyan_text(self in out nocopy ut_console_reporter_base, a_text varchar2) is begin self.print_text(ut_ansiconsole_helper.cyan(a_text)); end; - member procedure print_magenta_text(self in out nocopy ut_console_reporter_base, a_text varchar2) is - begin - self.print_text(ut_ansiconsole_helper.magenta(a_text)); - end; - end; / diff --git a/source/core/types/ut_console_reporter_base.tps b/source/core/types/ut_console_reporter_base.tps index b74b08033..3736e4d33 100644 --- a/source/core/types/ut_console_reporter_base.tps +++ b/source/core/types/ut_console_reporter_base.tps @@ -23,11 +23,7 @@ create or replace type ut_console_reporter_base under ut_output_reporter_base( member procedure print_yellow_text(self in out nocopy ut_console_reporter_base, a_text varchar2), - member procedure print_blue_text(self in out nocopy ut_console_reporter_base, a_text varchar2), - - member procedure print_cyan_text(self in out nocopy ut_console_reporter_base, a_text varchar2), - - member procedure print_magenta_text(self in out nocopy ut_console_reporter_base, a_text varchar2) + member procedure print_cyan_text(self in out nocopy ut_console_reporter_base, a_text varchar2) ) not final not instantiable / diff --git a/source/core/types/ut_executable.tps b/source/core/types/ut_executable.tps index 5fa4f3566..8186e4bae 100644 --- a/source/core/types/ut_executable.tps +++ b/source/core/types/ut_executable.tps @@ -25,6 +25,10 @@ create or replace type ut_executable under ut_event_item( error_backtrace varchar2(4000), error_stack varchar2(4000), serveroutput clob, + /** + * Used for ordering of executables, as Oracle doesn not guarantee ordering of items in a nested table. + */ + seq_no integer, constructor function ut_executable( self in out nocopy ut_executable, a_owner varchar2, a_package varchar2, a_procedure_name varchar2, a_executable_type varchar2) return self as result, member function form_name return varchar2, member procedure do_execute(self in out nocopy ut_executable, a_item in out nocopy ut_suite_item), diff --git a/source/core/types/ut_logical_suite.tpb b/source/core/types/ut_logical_suite.tpb index 0443bf105..306ef3b36 100644 --- a/source/core/types/ut_logical_suite.tpb +++ b/source/core/types/ut_logical_suite.tpb @@ -16,29 +16,6 @@ create or replace type body ut_logical_suite as limitations under the License. */ - constructor function ut_logical_suite( - self in out nocopy ut_logical_suite,a_object_owner varchar2, a_object_name varchar2, a_name varchar2, a_path varchar2 - ) return self as result is - begin - self.self_type := $$plsql_unit; - self.init(a_object_owner, a_object_name, a_name); - self.path := a_path; - self.disabled_flag := ut_utils.boolean_to_int(false); - self.items := ut_suite_items(); - return; - end; - - member function is_valid(self in out nocopy ut_logical_suite) return boolean is - begin - return true; - end; - - member procedure add_item(self in out nocopy ut_logical_suite, a_item ut_suite_item) is - begin - self.items.extend; - self.items(self.items.last) := a_item; - end; - overriding member procedure mark_as_skipped(self in out nocopy ut_logical_suite) is begin ut_event_manager.trigger_event(ut_utils.gc_before_suite, self); diff --git a/source/core/types/ut_logical_suite.tps b/source/core/types/ut_logical_suite.tps index 85bb80870..a9043c87e 100644 --- a/source/core/types/ut_logical_suite.tps +++ b/source/core/types/ut_logical_suite.tps @@ -21,11 +21,6 @@ create or replace type ut_logical_suite under ut_suite_item ( */ items ut_suite_items, - constructor function ut_logical_suite( - self in out nocopy ut_logical_suite, a_object_owner varchar2, a_object_name varchar2, a_name varchar2, a_path varchar2 - ) return self as result, - member function is_valid(self in out nocopy ut_logical_suite) return boolean, - member procedure add_item(self in out nocopy ut_logical_suite, a_item ut_suite_item), overriding member procedure mark_as_skipped(self in out nocopy ut_logical_suite), overriding member procedure set_rollback_type(self in out nocopy ut_logical_suite, a_rollback_type integer), overriding member function do_execute(self in out nocopy ut_logical_suite) return boolean, diff --git a/source/core/types/ut_output_reporter_base.tpb b/source/core/types/ut_output_reporter_base.tpb index 32e8b225b..3f62d6546 100644 --- a/source/core/types/ut_output_reporter_base.tpb +++ b/source/core/types/ut_output_reporter_base.tpb @@ -46,6 +46,11 @@ create or replace type body ut_output_reporter_base is self.output_buffer.send_line(a_text); end; + member procedure print_text_lines(self in out nocopy ut_output_reporter_base, a_text_lines ut_varchar2_rows) is + begin + self.output_buffer.send_lines(a_text_lines); + 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 diff --git a/source/core/types/ut_output_reporter_base.tps b/source/core/types/ut_output_reporter_base.tps index a0a9f63f6..e23ac9273 100644 --- a/source/core/types/ut_output_reporter_base.tps +++ b/source/core/types/ut_output_reporter_base.tps @@ -22,7 +22,7 @@ create or replace type ut_output_reporter_base under ut_reporter_base( 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_text_lines(self in out nocopy ut_output_reporter_base, a_text_lines ut_varchar2_rows), 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, diff --git a/source/core/types/ut_run.tpb b/source/core/types/ut_run.tpb index 0db9f38c0..a1ee19bd2 100644 --- a/source/core/types/ut_run.tpb +++ b/source/core/types/ut_run.tpb @@ -93,19 +93,7 @@ create or replace type body ut_run as overriding member procedure mark_as_errored(self in out nocopy ut_run, a_error_stack_trace varchar2) is begin - ut_utils.debug_log('ut_run.fail'); - - ut_event_manager.trigger_event(ut_utils.gc_before_run, self); - self.start_time := current_timestamp; - - for i in 1 .. self.items.count loop - self.items(i).mark_as_errored(a_error_stack_trace); - end loop; - - self.calc_execution_result(); - self.end_time := self.start_time; - - ut_event_manager.trigger_event(ut_utils.gc_after_run, self); + null; end; overriding member function get_error_stack_traces return ut_varchar2_list is diff --git a/source/core/types/ut_suite.tpb b/source/core/types/ut_suite.tpb index 9d9a60e8d..b92804fb0 100644 --- a/source/core/types/ut_suite.tpb +++ b/source/core/types/ut_suite.tpb @@ -17,11 +17,11 @@ create or replace type body ut_suite as */ constructor function ut_suite ( - self in out nocopy ut_suite, a_object_owner varchar2, a_object_name varchar2 + self in out nocopy ut_suite, a_object_owner varchar2, a_object_name varchar2, a_line_no integer ) return self as result is begin self.self_type := $$plsql_unit; - self.init(a_object_owner, a_object_name, a_object_name); + self.init(a_object_owner, a_object_name, a_object_name, a_line_no); self.items := ut_suite_items(); before_all_list := ut_executables(); after_all_list := ut_executables(); diff --git a/source/core/types/ut_suite.tps b/source/core/types/ut_suite.tps index f56d95c08..7057e4911 100644 --- a/source/core/types/ut_suite.tps +++ b/source/core/types/ut_suite.tps @@ -27,7 +27,7 @@ create or replace type ut_suite under ut_logical_suite ( */ after_all_list ut_executables, constructor function ut_suite ( - self in out nocopy ut_suite, a_object_owner varchar2, a_object_name varchar2 + self in out nocopy ut_suite, a_object_owner varchar2, a_object_name varchar2, a_line_no integer ) return self as result, overriding member function do_execute(self in out nocopy ut_suite) return boolean, overriding member function get_error_stack_traces(self ut_suite) return ut_varchar2_list, diff --git a/source/core/types/ut_suite_context.tpb b/source/core/types/ut_suite_context.tpb index a4add114b..c8255f374 100644 --- a/source/core/types/ut_suite_context.tpb +++ b/source/core/types/ut_suite_context.tpb @@ -17,11 +17,11 @@ create or replace type body ut_suite_context as */ constructor function ut_suite_context ( - self in out nocopy ut_suite_context, a_object_owner varchar2, a_object_name varchar2, a_context_name varchar2 := null + self in out nocopy ut_suite_context, a_object_owner varchar2, a_object_name varchar2, a_context_name varchar2 := null, a_line_no integer ) return self as result is begin self.self_type := $$plsql_unit; - self.init(a_object_owner, a_object_name, a_context_name); + self.init(a_object_owner, a_object_name, a_context_name, a_line_no); self.items := ut_suite_items(); before_all_list := ut_executables(); after_all_list := ut_executables(); diff --git a/source/core/types/ut_suite_context.tps b/source/core/types/ut_suite_context.tps index 345c12a65..ce4510c39 100644 --- a/source/core/types/ut_suite_context.tps +++ b/source/core/types/ut_suite_context.tps @@ -16,7 +16,7 @@ create or replace type ut_suite_context under ut_suite ( limitations under the License. */ constructor function ut_suite_context ( - self in out nocopy ut_suite_context, a_object_owner varchar2, a_object_name varchar2, a_context_name varchar2 := null + self in out nocopy ut_suite_context, a_object_owner varchar2, a_object_name varchar2, a_context_name varchar2 := null, a_line_no integer ) return self as result ) / diff --git a/source/core/types/ut_suite_item.tpb b/source/core/types/ut_suite_item.tpb index a3319a4d8..4788a9a3c 100644 --- a/source/core/types/ut_suite_item.tpb +++ b/source/core/types/ut_suite_item.tpb @@ -16,22 +16,18 @@ create or replace type body ut_suite_item as limitations under the License. */ - member procedure init(self in out nocopy ut_suite_item, a_object_owner varchar2, a_object_name varchar2, a_name varchar2) is + member procedure init(self in out nocopy ut_suite_item, a_object_owner varchar2, a_object_name varchar2, a_name varchar2, a_line_no integer) is begin self.object_owner := a_object_owner; self.object_name := lower(trim(a_object_name)); self.name := lower(trim(a_name)); self.results_count := ut_results_counter(); - self.warnings := ut_varchar2_list(); + self.warnings := ut_varchar2_rows(); + self.line_no := a_line_no; self.transaction_invalidators := ut_varchar2_list(); self.disabled_flag := ut_utils.boolean_to_int(false); end; - member procedure set_disabled_flag(self in out nocopy ut_suite_item, a_disabled_flag boolean) is - begin - self.disabled_flag := ut_utils.boolean_to_int(a_disabled_flag); - end; - member function get_disabled_flag return boolean is begin return ut_utils.int_to_boolean(self.disabled_flag); @@ -47,7 +43,7 @@ create or replace type body ut_suite_item as return nvl(self.rollback_type, ut_utils.gc_rollback_default); end; -final member procedure do_execute(self in out nocopy ut_suite_item) is + final member procedure do_execute(self in out nocopy ut_suite_item) is l_completed_without_errors boolean; begin l_completed_without_errors := self.do_execute(); diff --git a/source/core/types/ut_suite_item.tps b/source/core/types/ut_suite_item.tps index 52b6a2a19..e91b2afd0 100644 --- a/source/core/types/ut_suite_item.tps +++ b/source/core/types/ut_suite_item.tps @@ -19,15 +19,15 @@ create or replace type ut_suite_item force under ut_event_item ( /** * owner of the database object (package) */ - object_owner varchar2(4000 byte), + object_owner varchar2(250 byte), /** * name of the database object (package) */ - object_name varchar2(4000 byte), + object_name varchar2(250 byte), /** * Name of the object (suite, sub-suite, test) */ - name varchar2(4000 byte), + name varchar2(250 byte), /** * Description fo the suite item (as given by the annotation) */ @@ -45,15 +45,22 @@ create or replace type ut_suite_item force under ut_event_item ( * Indicates if the test is to be disabled by execution */ disabled_flag integer(1), + /** + * Line no where annotation identifying this item is placed in package + */ + line_no integer, + /** + * Time when the suite item was last parsed from package source + */ + parse_time timestamp, --execution result fields start_time timestamp with time zone, end_time timestamp with time zone, result integer(1), - warnings ut_varchar2_list, + warnings ut_varchar2_rows, results_count ut_results_counter, transaction_invalidators ut_varchar2_list, - member procedure init(self in out nocopy ut_suite_item, a_object_owner varchar2, a_object_name varchar2, a_name varchar2), - member procedure set_disabled_flag(self in out nocopy ut_suite_item, a_disabled_flag boolean), + member procedure init(self in out nocopy ut_suite_item, a_object_owner varchar2, a_object_name varchar2, a_name varchar2, a_line_no integer), member function get_disabled_flag return boolean, not instantiable member procedure mark_as_skipped(self in out nocopy ut_suite_item), member procedure set_rollback_type(self in out nocopy ut_suite_item, a_rollback_type integer), diff --git a/source/core/types/ut_test.tpb b/source/core/types/ut_test.tpb index f6495ecd6..ed9692e14 100644 --- a/source/core/types/ut_test.tpb +++ b/source/core/types/ut_test.tpb @@ -18,11 +18,11 @@ create or replace type body ut_test as constructor function ut_test( self in out nocopy ut_test, a_object_owner varchar2 := null, a_object_name varchar2, a_name varchar2, - a_expected_error_codes ut_integer_list := null + a_line_no integer, a_expected_error_codes ut_integer_list := null ) return self as result is begin self.self_type := $$plsql_unit; - self.init(a_object_owner, a_object_name, a_name); + self.init(a_object_owner, a_object_name, a_name, a_line_no); self.item := ut_executable_test(a_object_owner, a_object_name, a_name, ut_utils.gc_test_execute); self.before_each_list := ut_executables(); self.before_test_list := ut_executables(); @@ -97,7 +97,7 @@ create or replace type body ut_test as end; overriding member procedure calc_execution_result(self in out nocopy ut_test) is - l_warnings ut_varchar2_list; + l_warnings ut_varchar2_rows; begin if self.get_error_stack_traces().count = 0 then self.result := ut_expectation_processor.get_status(); @@ -107,7 +107,7 @@ create or replace type body ut_test as --expectation results need to be part of test results self.all_expectations := ut_expectation_processor.get_all_expectations(); self.failed_expectations := ut_expectation_processor.get_failed_expectations(); - l_warnings := coalesce( ut_expectation_processor.get_warnings(), ut_varchar2_list() ); + l_warnings := coalesce( ut_expectation_processor.get_warnings(), ut_varchar2_rows() ); self.warnings := self.warnings multiset union all l_warnings; self.results_count.increase_warning_count( cardinality(l_warnings) ); self.results_count.set_counter_values(self.result); diff --git a/source/core/types/ut_test.tps b/source/core/types/ut_test.tps index d26e220b9..752ef3ef7 100644 --- a/source/core/types/ut_test.tps +++ b/source/core/types/ut_test.tps @@ -57,7 +57,7 @@ create or replace type ut_test under ut_suite_item ( expected_error_codes ut_integer_list, constructor function ut_test( self in out nocopy ut_test, a_object_owner varchar2 := null, a_object_name varchar2, a_name varchar2, - a_expected_error_codes ut_integer_list := null + a_line_no integer, a_expected_error_codes ut_integer_list := null ) return self as result, overriding member procedure mark_as_skipped(self in out nocopy ut_test), overriding member function do_execute(self in out nocopy ut_test) return boolean, diff --git a/source/core/ut_expectation_processor.pkb b/source/core/ut_expectation_processor.pkb index 45dfb7dee..170846125 100644 --- a/source/core/ut_expectation_processor.pkb +++ b/source/core/ut_expectation_processor.pkb @@ -22,7 +22,7 @@ create or replace package body ut_expectation_processor as g_expectations_called ut_expectation_results := ut_expectation_results(); - g_warnings ut_varchar2_list := ut_varchar2_list(); + g_warnings ut_varchar2_rows := ut_varchar2_rows(); g_nulls_are_equal boolean_not_null := gc_default_nulls_are_equal; @@ -176,7 +176,7 @@ create or replace package body ut_expectation_processor as ); end; - function get_warnings return ut_varchar2_list is + function get_warnings return ut_varchar2_rows is begin return g_warnings; end; diff --git a/source/core/ut_expectation_processor.pks b/source/core/ut_expectation_processor.pks index f5d13ccb6..f58de2441 100644 --- a/source/core/ut_expectation_processor.pks +++ b/source/core/ut_expectation_processor.pks @@ -52,7 +52,7 @@ create or replace package ut_expectation_processor authid current_user as procedure add_depreciation_warning(a_deprecated_syntax varchar2, a_new_syntax varchar2); - function get_warnings return ut_varchar2_list; + function get_warnings return ut_varchar2_rows; function invalidation_exception_found return boolean; procedure set_invalidation_exception; diff --git a/source/core/ut_metadata.pkb b/source/core/ut_metadata.pkb index 30b0da64e..c905ebefe 100644 --- a/source/core/ut_metadata.pkb +++ b/source/core/ut_metadata.pkb @@ -22,12 +22,6 @@ create or replace package body ut_metadata as ------------------------------ --public definitions - procedure do_resolve(a_owner in out nocopy varchar2, a_object in out nocopy varchar2) is - l_procedure_name varchar2(200); - begin - do_resolve(a_owner, a_object, l_procedure_name ); - end do_resolve; - procedure do_resolve(a_owner in out nocopy varchar2, a_object in out nocopy varchar2, a_procedure_name in out nocopy varchar2) is l_name varchar2(200); l_context integer := 1; --plsql @@ -66,7 +60,7 @@ create or replace package body ut_metadata as l_schema varchar2(200); l_package_name varchar2(200); l_procedure_name varchar2(200); - l_view_name varchar2(200) := get_dba_view('dba_objects'); + l_view_name varchar2(200) := get_objects_view_name; begin l_schema := a_owner_name; @@ -116,8 +110,7 @@ create or replace package body ut_metadata as end; function get_source_definition_line(a_owner varchar2, a_object_name varchar2, a_line_no integer) return varchar2 is - l_cursor sys_refcursor; - l_view_name varchar2(128) := get_dba_view('dba_source'); + l_view_name varchar2(128) := get_source_view_name(); l_line all_source.text%type; c_key constant varchar2(500) := a_owner || '.' || a_object_name; begin @@ -148,15 +141,39 @@ create or replace package body ut_metadata as end; function get_dba_view(a_dba_view_name varchar2) return varchar2 is - l_invalid_object_name exception; l_result varchar2(128) := lower(a_dba_view_name); + begin + if not is_object_visible(a_dba_view_name) then + l_result := replace(l_result,'dba_','all_'); + end if; + return l_result; + end; + + function get_source_view_name return varchar2 is + begin + return get_dba_view('dba_source'); + end; + + + function get_objects_view_name return varchar2 is + begin + return get_dba_view('dba_objects'); + end; + + function user_has_execute_any_proc return boolean is + l_ut_owner varchar2(250) := ut_utils.ut_owner; + begin + return is_object_visible(l_ut_owner||'.ut_utils'); + end; + + function is_object_visible(a_object_name varchar2) return boolean is + l_invalid_object_name exception; pragma exception_init(l_invalid_object_name,-44002); begin - l_result := dbms_assert.sql_object_name(l_result); - return l_result; + return dbms_assert.sql_object_name(a_object_name) is not null; exception when l_invalid_object_name then - return replace(l_result,'dba_','all_'); + return false; end; function package_exists_in_cur_schema(a_object_name varchar2) return boolean is diff --git a/source/core/ut_metadata.pks b/source/core/ut_metadata.pks index 121524a0b..9a0ac2b00 100644 --- a/source/core/ut_metadata.pks +++ b/source/core/ut_metadata.pks @@ -39,12 +39,6 @@ create or replace package ut_metadata authid current_user as function procedure_exists(a_owner_name varchar2, a_package_name in varchar2, a_procedure_name in varchar2) return boolean; - /** - * Resolves [owner.]object using dbms_utility.name_resolve and returns resolved parts - * - */ - procedure do_resolve(a_owner in out nocopy varchar2, a_object in out nocopy varchar2); - /** * Resolves [owner.]object[.procedure] using dbms_utility.name_resolve and returns resolved parts * @@ -64,11 +58,33 @@ create or replace package ut_metadata authid current_user as procedure reset_source_definition_cache; /** - * Returns dba_... view name if it is accessible, otherwise it returns all_xxx view + * Returns dba_... view name if it is accessible, otherwise it returns all_... view * @param a_dba_view_name the name of dba view requested */ function get_dba_view(a_dba_view_name varchar2) return varchar2; + /** + * Returns dba_source if accessible otherwise returns all_source + */ + function get_source_view_name return varchar2; + + /** + * Returns dba_objects if accessible otherwise returns all_objects + */ + function get_objects_view_name return varchar2; + + /** + * Returns true if object is accessible to current user + * @param a_object_name fully qualified object name (with schema name) + */ + function is_object_visible(a_object_name varchar2) return boolean; + + /** + * Returns true if current user has execute any procedure privilege + * The check is performed by checking if user can execute ut_utils package + */ + function user_has_execute_any_proc return boolean; + /** * Returns true if given object is a package and it exists in current schema * @param a_object_name the name of the object to be checked diff --git a/source/core/ut_suite_builder.pkb b/source/core/ut_suite_builder.pkb index 8558b4331..d946b2a5d 100644 --- a/source/core/ut_suite_builder.pkb +++ b/source/core/ut_suite_builder.pkb @@ -58,22 +58,17 @@ create or replace package body ut_suite_builder is gc_endcontext ); - gc_placeholder constant varchar2(3) := '\\%'; - gc_integer_exception constant varchar2(1) := 'I'; gc_named_exception constant varchar2(1) := 'N'; type tt_executables is table of ut_executables index by t_annotation_position; - type tt_tests is table of ut_test index by t_annotation_position; - - type t_annotation is record( name t_annotation_name, text t_annotation_text, procedure_name t_object_name ); - + type tt_annotations_by_line is table of t_annotation index by t_annotation_position; --list of annotation texts for a given annotation indexed by annotation position: @@ -84,17 +79,18 @@ create or replace package body ut_suite_builder is -- procedure some_test ... -- when you'd like to have two beforetest procedures executed in a single test type tt_annotation_texts is table of t_annotation_text index by t_annotation_position; - + type tt_annotations_by_name is table of tt_annotation_texts index by t_annotation_name; type tt_annotations_by_proc is table of tt_annotations_by_name index by t_object_name; type t_annotations_info is record ( - owner t_object_name, - name t_object_name, - by_line tt_annotations_by_line, - by_proc tt_annotations_by_proc, - by_name tt_annotations_by_name + owner t_object_name, + name t_object_name, + parse_time timestamp, + by_line tt_annotations_by_line, + by_proc tt_annotations_by_proc, + by_name tt_annotations_by_name ); procedure delete_annotations_range( @@ -120,6 +116,15 @@ create or replace package body ut_suite_builder is a_annotations.by_line.delete(a_start_pos, a_end_pos); end; + + procedure add_items_to_list(a_list in out nocopy ut_suite_items, a_items ut_suite_items) is + begin + for i in 1 .. a_items.count loop + a_list.extend(); + a_list(a_list.last) := a_items(i); + end loop; + end; + ----------------------------------------------- -- Processing annotations ----------------------------------------------- @@ -207,7 +212,6 @@ create or replace package body ut_suite_builder is function get_exception_number (a_exception_var in varchar2) return integer is l_exc_no integer; l_exc_type varchar2(50); - l_sql varchar2(32767); function remap_no_data_found (a_number integer) return integer is begin return case a_number when 100 then -1403 else a_number end; @@ -249,7 +253,7 @@ create or replace package body ut_suite_builder is l_exception_number_list ut_integer_list := ut_integer_list(); c_regexp_for_exception_no constant varchar2(30) := '^-?[[:digit:]]{1,5}$'; begin - /*the a_expected_error_codes is converted to a ut_varchar2_list after that is trimmed and filtered to left only valid exception numbers*/ + --the a_expected_error_codes is converted to a ut_varchar2_list after that is trimmed and filtered to left only valid exception numbers l_throws_list := ut_utils.trim_list_elements(ut_utils.string_to_table(a_annotation_text, ',', 'Y')); for i in 1 .. l_throws_list.count @@ -301,32 +305,32 @@ create or replace package body ut_suite_builder is end loop; end; + procedure set_seq_no( + a_list in out nocopy ut_executables + ) is + begin + if a_list is not null then + for i in 1 .. a_list.count loop + a_list(i).seq_no := i; + end loop; + end if; + end; + function convert_list( a_list tt_executables ) return ut_executables is l_result ut_executables := ut_executables(); l_pos t_annotation_position := a_list.first; - begin - while l_pos is not null loop - l_result := l_result multiset union all a_list(l_pos); - l_pos := a_list.next(l_pos); - end loop; - return l_result; - end; - - function convert_list( - a_list tt_tests - ) return ut_suite_items is - l_result ut_suite_items := ut_suite_items(); - l_pos t_annotation_position := a_list.first; - begin - while l_pos is not null loop + begin + while l_pos is not null loop + for i in 1 .. a_list(l_pos).count loop l_result.extend; - l_result(l_result.last) := a_list(l_pos); - l_pos := a_list.next(l_pos); + l_result(l_result.last) := a_list(l_pos)(i); end loop; - return l_result; - end; + l_pos := a_list.next(l_pos); + end loop; + return l_result; + end; function add_executables( a_owner t_object_name, @@ -382,18 +386,15 @@ create or replace package body ut_suite_builder is a_for_annotation varchar2, a_procedure_name t_object_name := null ) is - l_annotation_name t_annotation_name; l_line_no binary_integer; begin - if a_annotations.exists(a_for_annotation) then - if a_annotations(a_for_annotation).count > 1 then - --start from second occurrence of annotation - l_line_no := a_annotations(a_for_annotation).next( a_annotations(a_for_annotation).first ); - while l_line_no is not null loop - add_annotation_ignored_warning( a_suite, a_for_annotation, 'Duplicate annotation %%%.', l_line_no, a_procedure_name ); - l_line_no := a_annotations(a_for_annotation).next( l_line_no ); - end loop; - end if; + if a_annotations.exists(a_for_annotation) and a_annotations(a_for_annotation).count > 1 then + --start from second occurrence of annotation + l_line_no := a_annotations(a_for_annotation).next( a_annotations(a_for_annotation).first ); + while l_line_no is not null loop + add_annotation_ignored_warning( a_suite, a_for_annotation, 'Duplicate annotation %%%.', l_line_no, a_procedure_name ); + l_line_no := a_annotations(a_for_annotation).next( l_line_no ); + end loop; end if; end; @@ -405,8 +406,7 @@ create or replace package body ut_suite_builder is a_invalid_annotations ut_varchar2_list ) is l_annotation_name t_annotation_name; - l_warning varchar2(32767); - l_line_no binary_integer; + l_line_no binary_integer; begin if a_proc_annotations.exists(a_for_annotation) then l_annotation_name := a_proc_annotations.first; @@ -428,39 +428,40 @@ create or replace package body ut_suite_builder is procedure add_test( a_suite in out nocopy ut_suite, - a_tests in out nocopy tt_tests, + a_suite_items in out nocopy ut_suite_items, a_procedure_name t_object_name, - a_proc_annotations tt_annotations_by_name + a_annotations t_annotations_info ) is l_test ut_test; l_annotation_texts tt_annotation_texts; - l_annotation_pos binary_integer; + l_proc_annotations tt_annotations_by_name := a_annotations.by_proc(a_procedure_name); begin - if not a_proc_annotations.exists(gc_test) then + if not l_proc_annotations.exists(gc_test) then return; end if; - warning_on_duplicate_annot(a_suite, a_proc_annotations, gc_test, a_procedure_name); - warning_on_duplicate_annot(a_suite, a_proc_annotations, gc_displayname, a_procedure_name); - warning_on_duplicate_annot(a_suite, a_proc_annotations, gc_rollback, a_procedure_name); + warning_on_duplicate_annot( a_suite, l_proc_annotations, gc_test, a_procedure_name); + warning_on_duplicate_annot( a_suite, l_proc_annotations, gc_displayname, a_procedure_name); + warning_on_duplicate_annot( a_suite, l_proc_annotations, gc_rollback, a_procedure_name); warning_bad_annot_combination( - a_suite, a_procedure_name, a_proc_annotations, gc_test, + a_suite, a_procedure_name, l_proc_annotations, gc_test, ut_varchar2_list(gc_beforeeach, gc_aftereach, gc_beforeall, gc_afterall) ); - - l_test := ut_test(a_suite.object_owner, a_suite.object_name, a_procedure_name); - if a_proc_annotations.exists(gc_displayname) then - l_annotation_texts := a_proc_annotations(gc_displayname); + l_test := ut_test(a_suite.object_owner, a_suite.object_name, a_procedure_name, l_proc_annotations( gc_test).first); + l_test.parse_time := a_annotations.parse_time; + + if l_proc_annotations.exists( gc_displayname) then + l_annotation_texts := l_proc_annotations( gc_displayname); --take the last definition if more than one was provided l_test.description := l_annotation_texts(l_annotation_texts.first); --TODO if more than one - warning else - l_test.description := a_proc_annotations(gc_test)(a_proc_annotations(gc_test).first); + l_test.description := l_proc_annotations(gc_test)(l_proc_annotations(gc_test).first); end if; l_test.path := a_suite.path ||'.'||a_procedure_name; - if a_proc_annotations.exists(gc_rollback) then - l_annotation_texts := a_proc_annotations(gc_rollback); + if l_proc_annotations.exists(gc_rollback) then + l_annotation_texts := l_proc_annotations(gc_rollback); l_test.rollback_type := get_rollback_type(l_annotation_texts(l_annotation_texts.first)); if l_test.rollback_type is null then add_annotation_ignored_warning( @@ -470,47 +471,52 @@ create or replace package body ut_suite_builder is end if; end if; - if a_proc_annotations.exists(gc_beforetest) then + if l_proc_annotations.exists( gc_beforetest) then l_test.before_test_list := convert_list( - add_executables( l_test.object_owner, l_test.object_name, a_proc_annotations( gc_beforetest ), gc_beforetest ) + add_executables( l_test.object_owner, l_test.object_name, l_proc_annotations( gc_beforetest ), gc_beforetest ) ); + set_seq_no(l_test.before_test_list); end if; - if a_proc_annotations.exists(gc_aftertest) then + if l_proc_annotations.exists( gc_aftertest) then l_test.after_test_list := convert_list( - add_executables( l_test.object_owner, l_test.object_name, a_proc_annotations( gc_aftertest ), gc_aftertest ) + add_executables( l_test.object_owner, l_test.object_name, l_proc_annotations( gc_aftertest ), gc_aftertest ) ); + set_seq_no(l_test.after_test_list); end if; - if a_proc_annotations.exists(gc_throws) then - add_to_throws_numbers_list(a_suite, l_test.expected_error_codes, a_procedure_name, a_proc_annotations(gc_throws)); + if l_proc_annotations.exists( gc_throws) then + add_to_throws_numbers_list(a_suite, l_test.expected_error_codes, a_procedure_name, l_proc_annotations( gc_throws)); end if; - l_test.disabled_flag := ut_utils.boolean_to_int(a_proc_annotations.exists(gc_disabled)); + l_test.disabled_flag := ut_utils.boolean_to_int( l_proc_annotations.exists( gc_disabled)); - a_tests(a_proc_annotations(gc_test).first) := l_test; + a_suite_items.extend; + a_suite_items( a_suite_items.last ) := l_test; end; - procedure update_before_after_each( - a_suite in out nocopy ut_logical_suite, + procedure propagate_before_after_each( + a_suite_items in out nocopy ut_suite_items, a_before_each_list tt_executables, a_after_each_list tt_executables ) is l_test ut_test; l_context ut_logical_suite; - begin - if a_suite.items is not null then - for i in 1 .. a_suite.items.count loop - if a_suite.items(i) is of (ut_test) then - l_test := treat( a_suite.items(i) as ut_test); - l_test.before_each_list := coalesce(convert_list(a_before_each_list),ut_executables()) multiset union all l_test.before_each_list; - l_test.after_each_list := l_test.after_each_list multiset union all coalesce(convert_list(a_after_each_list),ut_executables()); - a_suite.items(i) := l_test; - elsif a_suite.items(i) is of (ut_logical_suite) then - l_context := treat(a_suite.items(i) as ut_logical_suite); - update_before_after_each(l_context, a_before_each_list, a_after_each_list); - a_suite.items(i) := l_context; - end if; - end loop; - end if; - end; + begin + if a_suite_items is not null then + for i in 1 .. a_suite_items.count loop + if a_suite_items(i) is of (ut_test) then + l_test := treat( a_suite_items(i) as ut_test); + l_test.before_each_list := convert_list(a_before_each_list) multiset union all l_test.before_each_list; + set_seq_no(l_test.before_each_list); + l_test.after_each_list := l_test.after_each_list multiset union all convert_list(a_after_each_list); + set_seq_no(l_test.after_each_list); + a_suite_items(i) := l_test; + elsif a_suite_items(i) is of (ut_logical_suite) then + l_context := treat(a_suite_items(i) as ut_logical_suite); + propagate_before_after_each( l_context.items, a_before_each_list, a_after_each_list); + a_suite_items(i) := l_context; + end if; + end loop; + end if; + end; procedure process_before_after_annot( a_list in out nocopy tt_executables, @@ -518,7 +524,7 @@ create or replace package body ut_suite_builder is a_procedure_name t_object_name, a_proc_annotations tt_annotations_by_name, a_suite in out nocopy ut_suite - ) is + ) is begin if a_proc_annotations.exists(a_annotation_name) and not a_proc_annotations.exists(gc_test) then a_list( a_proc_annotations(a_annotation_name).first ) := ut_executables(ut_executable(a_suite.object_owner, a_suite.object_name, a_procedure_name, a_annotation_name)); @@ -527,27 +533,26 @@ create or replace package body ut_suite_builder is end if; end; - procedure add_annotated_procedures( - a_proc_annotations tt_annotations_by_proc, + procedure get_annotated_procedures( + a_proc_annotations t_annotations_info, a_suite in out nocopy ut_suite, + a_suite_items in out nocopy ut_suite_items, a_before_each_list in out nocopy tt_executables, a_after_each_list in out nocopy tt_executables, a_before_all_list in out nocopy tt_executables, a_after_all_list in out nocopy tt_executables ) is l_procedure_name t_object_name; - l_tests tt_tests; begin - l_procedure_name := a_proc_annotations.first; + l_procedure_name := a_proc_annotations.by_proc.first; while l_procedure_name is not null loop - add_test( a_suite, l_tests, l_procedure_name, a_proc_annotations(l_procedure_name) ); - process_before_after_annot(a_before_each_list, gc_beforeeach, l_procedure_name, a_proc_annotations(l_procedure_name), a_suite); - process_before_after_annot(a_after_each_list, gc_aftereach, l_procedure_name, a_proc_annotations(l_procedure_name), a_suite); - process_before_after_annot(a_before_all_list, gc_beforeall, l_procedure_name, a_proc_annotations(l_procedure_name), a_suite); - process_before_after_annot(a_after_all_list, gc_afterall, l_procedure_name, a_proc_annotations(l_procedure_name), a_suite); - l_procedure_name := a_proc_annotations.next( l_procedure_name ); + add_test( a_suite, a_suite_items, l_procedure_name, a_proc_annotations ); + process_before_after_annot(a_before_each_list, gc_beforeeach, l_procedure_name, a_proc_annotations.by_proc(l_procedure_name), a_suite); + process_before_after_annot(a_after_each_list, gc_aftereach, l_procedure_name, a_proc_annotations.by_proc(l_procedure_name), a_suite); + process_before_after_annot(a_before_all_list, gc_beforeall, l_procedure_name, a_proc_annotations.by_proc(l_procedure_name), a_suite); + process_before_after_annot(a_after_all_list, gc_afterall, l_procedure_name, a_proc_annotations.by_proc(l_procedure_name), a_suite); + l_procedure_name := a_proc_annotations.by_proc.next( l_procedure_name ); end loop; - a_suite.items := a_suite.items multiset union all convert_list(l_tests); end; procedure build_suitepath( @@ -578,15 +583,15 @@ create or replace package body ut_suite_builder is a_suite.path := lower(coalesce(a_suite.path, a_suite.object_name)); end; - procedure populate_suite_contents( + procedure add_suite_tests( a_suite in out nocopy ut_suite, - a_annotations t_annotations_info + a_annotations t_annotations_info, + a_suite_items in out nocopy ut_suite_items ) is l_before_each_list tt_executables; l_after_each_list tt_executables; l_before_all_list tt_executables; l_after_all_list tt_executables; - l_executables ut_executables; l_rollback_type ut_utils.t_rollback_type; l_annotation_text t_annotation_text; begin @@ -630,18 +635,65 @@ create or replace package body ut_suite_builder is a_suite.disabled_flag := ut_utils.boolean_to_int(a_annotations.by_name.exists(gc_disabled)); --process procedure annotations for suite - add_annotated_procedures(a_annotations.by_proc, a_suite, l_before_each_list, l_after_each_list, l_before_all_list, l_after_all_list); + get_annotated_procedures(a_annotations, a_suite, a_suite_items, l_before_each_list, l_after_each_list, l_before_all_list, l_after_all_list); a_suite.set_rollback_type(l_rollback_type); - update_before_after_each(a_suite, l_before_each_list, l_after_each_list); + propagate_before_after_each( a_suite_items, l_before_each_list, l_after_each_list); a_suite.before_all_list := convert_list(l_before_all_list); + set_seq_no(a_suite.before_all_list); a_suite.after_all_list := convert_list(l_after_all_list); + set_seq_no(a_suite.after_all_list); end; + function get_endcontext_position( + a_context_ann_pos t_annotation_position, + a_package_annotations in out nocopy tt_annotations_by_name + ) return t_annotation_position is + l_result t_annotation_position; + begin + if a_package_annotations.exists(gc_endcontext) then + l_result := a_package_annotations(gc_endcontext).first; + while l_result <= a_context_ann_pos loop + l_result := a_package_annotations(gc_endcontext).next(l_result); + end loop; + end if; + return l_result; + end; - procedure add_suite_contexts( + function get_annotations_in_context( + a_annotations t_annotations_info, + a_context_pos t_annotation_position, + a_end_context_pos t_annotation_position + ) return t_annotations_info is + l_result t_annotations_info; + l_position t_annotation_position; + l_procedure_name t_object_name; + l_annotation_name t_annotation_name; + l_annotation_text t_annotation_text; + begin + l_position := a_context_pos; + l_result.owner := a_annotations.owner; + l_result.name := a_annotations.name; + l_result.parse_time := a_annotations.parse_time; + while l_position is not null and l_position <= a_end_context_pos loop + l_result.by_line(l_position) := a_annotations.by_line(l_position); + l_procedure_name := l_result.by_line(l_position).procedure_name; + l_annotation_name := l_result.by_line(l_position).name; + l_annotation_text := l_result.by_line(l_position).text; + if l_procedure_name is not null then + l_result.by_proc(l_procedure_name)(l_annotation_name)(l_position) := l_annotation_text; + else + l_result.by_name(l_annotation_name)(l_position) := l_annotation_text; + end if; + l_position := a_annotations.by_line.next(l_position); + end loop; + return l_result; + end; + + procedure get_suite_contexts_items( a_suite in out nocopy ut_suite, - a_annotations in out nocopy t_annotations_info + a_annotations in out nocopy t_annotations_info, + a_suite_items out nocopy ut_suite_items ) is l_context_pos t_annotation_position; l_end_context_pos t_annotation_position; @@ -649,52 +701,11 @@ create or replace package body ut_suite_builder is l_ctx_annotations t_annotations_info; l_context ut_suite_context; l_context_no binary_integer := 1; - - function get_endcontext_position( - a_context_ann_pos t_annotation_position, - a_package_annotations in out nocopy tt_annotations_by_name - ) return t_annotation_position is - l_result t_annotation_position; - begin - if a_package_annotations.exists(gc_endcontext) then - l_result := a_package_annotations(gc_endcontext).first; - while l_result <= a_context_ann_pos loop - l_result := a_package_annotations(gc_endcontext).next(l_result); - end loop; - end if; - return l_result; - end; - - function get_annotations_in_context( - a_annotations t_annotations_info, - a_context_pos t_annotation_position, - a_end_context_pos t_annotation_position - ) return t_annotations_info is - l_result t_annotations_info; - l_position t_annotation_position; - l_procedure_name t_object_name; - l_annotation_name t_annotation_name; - l_annotation_text t_annotation_text; - begin - l_position := a_context_pos; - l_result.owner := a_annotations.owner; - l_result.name := a_annotations.name; - while l_position is not null and l_position <= a_end_context_pos loop - l_result.by_line(l_position) := a_annotations.by_line(l_position); - l_procedure_name := l_result.by_line(l_position).procedure_name; - l_annotation_name := l_result.by_line(l_position).name; - l_annotation_text := l_result.by_line(l_position).text; - if l_procedure_name is not null then - l_result.by_proc(l_procedure_name)(l_annotation_name)(l_position) := l_annotation_text; - else - l_result.by_name(l_annotation_name)(l_position) := l_annotation_text; - end if; - l_position := a_annotations.by_line.next(l_position); - end loop; - return l_result; - end; - + l_context_items ut_suite_items; + type tt_context_names is table of boolean index by t_object_name; + l_context_names tt_context_names; begin + a_suite_items := ut_suite_items(); if not a_annotations.by_name.exists(gc_context) then return; end if; @@ -703,10 +714,10 @@ create or replace package body ut_suite_builder is while l_context_pos is not null loop l_end_context_pos := get_endcontext_position(l_context_pos, a_annotations.by_name ); - if l_end_context_pos is null then - exit; - end if; + exit when l_end_context_pos is null; + + l_context_items := ut_suite_items(); --create a sub-set of annotations to process as sub-suite (context) l_ctx_annotations := get_annotations_in_context( a_annotations, l_context_pos, l_end_context_pos); @@ -714,18 +725,24 @@ create or replace package body ut_suite_builder is l_ctx_annotations.by_line( l_context_pos ).text , gc_context||'_'||l_context_no ); + if l_context_names.exists(l_context_name) then + add_annotation_ignored_warning( a_suite, 'context', 'Context name must be unique in a suite. Context and all of it''s content ignored.', l_context_pos ); + else + l_context_names(l_context_name) := true; - l_context := ut_suite_context(a_suite.object_owner, a_suite.object_name, l_context_name ); - - l_context.path := a_suite.path||'.'||l_context_name; - l_context.description := l_ctx_annotations.by_line( l_context_pos ).text; - - warning_on_duplicate_annot( l_context, l_ctx_annotations.by_name, gc_context ); + l_context := ut_suite_context(a_suite.object_owner, a_suite.object_name, l_context_name, l_context_pos ); - populate_suite_contents( l_context, l_ctx_annotations ); + l_context.path := a_suite.path||'.'||l_context_name; + l_context.description := l_ctx_annotations.by_line( l_context_pos ).text; + l_context.parse_time := a_annotations.parse_time; - a_suite.add_item(l_context); + warning_on_duplicate_annot( l_context, l_ctx_annotations.by_name, gc_context ); + add_suite_tests( l_context, l_ctx_annotations, l_context_items ); + add_items_to_list(a_suite_items, l_context_items); + a_suite_items.extend; + a_suite_items(a_suite_items.last) := l_context; + end if; -- remove annotations within context after processing them delete_annotations_range(a_annotations, l_context_pos, l_end_context_pos); @@ -784,140 +801,59 @@ create or replace package body ut_suite_builder is end loop; end; - function create_suite( - a_annotations t_annotations_info - ) return ut_logical_suite is - l_annotations t_annotations_info := a_annotations; - l_annotation_pos t_annotation_position; - l_suite ut_suite; + function convert_package_annotations(a_object ut_annotated_object) return t_annotations_info is + l_result t_annotations_info; + l_annotation t_annotation; + l_annotation_no binary_integer; + l_annotation_pos binary_integer; + begin + l_result.owner := a_object.object_owner; + l_result.name := lower(trim(a_object.object_name)); + l_result.parse_time := a_object.parse_time; + l_annotation_no := a_object.annotations.first; + while l_annotation_no is not null loop + l_annotation_pos := a_object.annotations(l_annotation_no).position; + l_annotation.name := a_object.annotations(l_annotation_no).name; + l_annotation.text := a_object.annotations(l_annotation_no).text; + l_annotation.procedure_name := lower(trim(a_object.annotations(l_annotation_no).subobject_name)); + l_result.by_line( l_annotation_pos) := l_annotation; + if l_annotation.procedure_name is null then + l_result.by_name( l_annotation.name)( l_annotation_pos) := l_annotation.text; + else + l_result.by_proc(l_annotation.procedure_name)(l_annotation.name)(l_annotation_pos) := l_annotation.text; + end if; + l_annotation_no := a_object.annotations.next(l_annotation_no); + end loop; + return l_result; + end; + + procedure create_suite_item_list( a_annotated_object ut_annotated_object, a_suite_items out nocopy ut_suite_items ) is + l_annotations t_annotations_info; + l_annotation_pos t_annotation_position; + l_suite ut_suite; begin - if l_annotations.by_name.exists( gc_suite) then + l_annotations := convert_package_annotations( a_annotated_object ); - --create an incomplete suite - l_suite := ut_suite(l_annotations.owner, l_annotations.name); - l_annotation_pos := l_annotations.by_name( gc_suite).first; + if l_annotations.by_name.exists(gc_suite) then + l_annotation_pos := l_annotations.by_name(gc_suite).first; + l_suite := ut_suite(l_annotations.owner, l_annotations.name, l_annotation_pos); l_suite.description := l_annotations.by_name( gc_suite)( l_annotation_pos); + l_suite.parse_time := l_annotations.parse_time; warning_on_unknown_annotations(l_suite, l_annotations.by_line); warning_on_duplicate_annot( l_suite, l_annotations.by_name, gc_suite ); build_suitepath( l_suite, l_annotations ); + get_suite_contexts_items( l_suite, l_annotations, a_suite_items ); + --create suite tests and add + add_suite_tests( l_suite, l_annotations, a_suite_items ); - add_suite_contexts( l_suite, l_annotations ); --by this time all contexts were consumed and l_annotations should not have any context/endcontext annotation in it. warning_on_incomplete_context( l_suite, l_annotations.by_name ); - populate_suite_contents( l_suite, l_annotations ); - + a_suite_items.extend; + a_suite_items( a_suite_items.last) := l_suite; end if; - return l_suite; - end; - - function build_suites_hierarchy(a_suites_by_path tt_schema_suites) return tt_schema_suites is - l_result tt_schema_suites; - l_suite_path varchar2(4000 char); - l_parent_path varchar2(4000 char); - l_name varchar2(4000 char); - l_suites_by_path tt_schema_suites; - begin - l_suites_by_path := a_suites_by_path; - --were iterating in reverse order of the index by path table - -- so the first paths will be the leafs of hierarchy and next will their parents - l_suite_path := l_suites_by_path.last; - ut_utils.debug_log('Input suites to process = '||l_suites_by_path.count); - - while l_suite_path is not null loop - l_parent_path := substr( l_suite_path, 1, instr(l_suite_path,'.',-1)-1); - ut_utils.debug_log('Processing l_suite_path = "'||l_suite_path||'", l_parent_path = "'||l_parent_path||'"'); - --no parent => I'm a root element - if l_parent_path is null then - ut_utils.debug_log(' suite "'||l_suite_path||'" is a root element - adding to return list.'); - l_result(l_suite_path) := l_suites_by_path(l_suite_path); - -- not a root suite - need to add it to a parent suite - else - --parent does not exist and needs to be added - if not l_suites_by_path.exists(l_parent_path) then - l_name := substr( l_parent_path, instr(l_parent_path,'.',-1)+1); - ut_utils.debug_log(' Parent suite "'||l_parent_path||'" not found in the list - Adding suite "'||l_name||'"'); - l_suites_by_path(l_parent_path) := - ut_logical_suite( - a_object_owner => l_suites_by_path(l_suite_path).object_owner, - a_object_name => l_name, a_name => l_name, a_path => l_parent_path - ); - else - ut_utils.debug_log(' Parent suite "'||l_parent_path||'" found in list of suites'); - end if; - ut_utils.debug_log(' adding suite "'||l_suite_path||'" to "'||l_parent_path||'" items'); - l_suites_by_path(l_parent_path).add_item( l_suites_by_path(l_suite_path) ); - end if; - l_suite_path := l_suites_by_path.prior(l_suite_path); - end loop; - ut_utils.debug_log(l_result.count||' root suites created.'); - return l_result; - end; - - function build_suites(a_annotated_objects sys_refcursor) return t_schema_suites_info is - l_suite ut_logical_suite; - l_annotated_objects ut_annotated_objects; - l_all_suites tt_schema_suites; - l_result t_schema_suites_info; - - function convert_package_annotations(a_object ut_annotated_object) return t_annotations_info is - l_result t_annotations_info; - l_annotation t_annotation; - l_annotation_no binary_integer; - l_annotation_pos binary_integer; - begin - l_result.owner := a_object.object_owner; - l_result.name := lower(trim(a_object.object_name)); - l_annotation_no := a_object.annotations.first; - while l_annotation_no is not null loop - l_annotation_pos := a_object.annotations(l_annotation_no).position; - l_annotation.name := a_object.annotations(l_annotation_no).name; - l_annotation.text := a_object.annotations(l_annotation_no).text; - l_annotation.procedure_name := lower(trim(a_object.annotations(l_annotation_no).subobject_name)); - l_result.by_line( l_annotation_pos) := l_annotation; - if l_annotation.procedure_name is null then - l_result.by_name( l_annotation.name)( l_annotation_pos) := l_annotation.text; - else - l_result.by_proc(l_annotation.procedure_name)(l_annotation.name)(l_annotation_pos) := l_annotation.text; - end if; - l_annotation_no := a_object.annotations.next(l_annotation_no); - end loop; - return l_result; - end; - - begin - fetch a_annotated_objects bulk collect into l_annotated_objects; - close a_annotated_objects; - - for i in 1 .. l_annotated_objects.count loop - l_suite := create_suite(convert_package_annotations(l_annotated_objects(i))); - if l_suite is not null then - l_all_suites(l_suite.path) := l_suite; - l_result.suite_paths(l_suite.object_name) := l_suite.path; - end if; - end loop; - - --build hierarchical structure of the suite - -- Restructure single-dimension list into hierarchy of suites by the value of %suitepath attribute value - l_result.schema_suites := build_suites_hierarchy(l_all_suites); - - return l_result; - end; - - function build_schema_suites(a_owner_name varchar2) return t_schema_suites_info is - l_annotations_cursor sys_refcursor; - begin - -- form the single-dimension list of suites constructed from parsed packages - open l_annotations_cursor for - q'[select value(x) - from table( - ]'||ut_utils.ut_owner||q'[.ut_annotation_manager.get_annotated_objects(:a_owner_name, 'PACKAGE') - )x ]' - using a_owner_name; - - return build_suites(l_annotations_cursor); end; end ut_suite_builder; diff --git a/source/core/ut_suite_builder.pks b/source/core/ut_suite_builder.pks index 2ae40f4d3..5e2624a30 100644 --- a/source/core/ut_suite_builder.pks +++ b/source/core/ut_suite_builder.pks @@ -20,34 +20,13 @@ create or replace package ut_suite_builder authid current_user is * Responsible for converting annotations into unit test suites */ - --table of ut_suites indexed by object name ( suite_paths('object_name') = ut_logical_suite - type tt_schema_suites is table of ut_logical_suite index by varchar2(4000 char); - - --table of suite paths indexed by object name ( suite_paths('object_name') = 'suitepath.to.object' - type t_object_suite_path is table of varchar2(4000) index by varchar2(4000 char); - - type t_schema_suites_info is record ( - schema_suites tt_schema_suites, - suite_paths t_object_suite_path - ); - /** - * Builds set of hierarchical suites for a given schema - * - * @param a_owner_name name of the schema to builds suites for - * @return list of suites organized into hierarchy - * + * Creates a list of suite items for an annotated object */ - function build_schema_suites(a_owner_name varchar2) return t_schema_suites_info; - - /** - * Builds set of hierarchical suites for given annotations - * - * @param a_annotated_objects cursor returning ut_annotated_object type - * @return list of suites organized into hierarchy - * - */ - function build_suites(a_annotated_objects sys_refcursor) return t_schema_suites_info; + procedure create_suite_item_list( + a_annotated_object ut_annotated_object, + a_suite_items out nocopy ut_suite_items + ); end ut_suite_builder; / diff --git a/source/core/ut_suite_cache.sql b/source/core/ut_suite_cache.sql new file mode 100644 index 000000000..adbdf1734 --- /dev/null +++ b/source/core/ut_suite_cache.sql @@ -0,0 +1,93 @@ +create or replace type ut_suite_contexts as table of ut_suite_context +/ +create or replace type ut_tests as table of ut_test +/ + +create table ut_suite_cache ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2018 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. + */ + id, + self_type, + path, + object_owner, + object_name, + name, + line_no, + parse_time, + description, + rollback_type, + disabled_flag, + warnings, + before_all_list, + after_all_list, + before_each_list, + before_test_list, + after_each_list, + after_test_list, + expected_error_codes, + item +) + nested table warnings store as ut_suite_cache_warnings + nested table before_all_list store as ut_suite_cache_before_all + nested table after_all_list store as ut_suite_cache_after_all + nested table before_each_list store as ut_suite_cache_before_each + nested table after_each_list store as ut_suite_cache_after_each + nested table before_test_list store as ut_suite_cache_before_test + nested table after_test_list store as ut_suite_cache_after_test + nested table expected_error_codes store as ut_suite_cache_trhows + as + select + cast(null as number(22)) id, + c.self_type, + c.path, + c.object_owner, + c.object_name, + c.name, + c.line_no, + c.parse_time, + c.description, + c.rollback_type, + c.disabled_flag, + c.warnings, + c.before_all_list, + c.after_all_list, + t.before_each_list, + t.before_test_list, + t.after_each_list, + t.after_test_list, + t.expected_error_codes, + t.item + from table(ut_suite_contexts(ut_suite_context(user,'package_name','ctx_name',1))) c + cross join table(ut_tests(ut_test(user,'package_name','test_name',1))) t + where rownum < 0 +/ + +alter table ut_suite_cache modify (object_owner not null, path not null, self_type not null, object_name not null, name not null, parse_time not null) +/ +alter table ut_suite_cache add constraint ut_suite_cache_pk primary key (id) +/ +alter table ut_suite_cache add constraint ut_suite_cache_uk1 unique (object_owner, path) +/ +alter table ut_suite_cache add constraint ut_suite_cache_uk2 unique (object_owner, object_name, line_no) +/ + +alter table ut_suite_cache add constraint ut_suite_cache_schema_fk foreign key (object_owner, object_name) +references ut_suite_cache_package(object_owner, object_name) on delete cascade +/ + +drop type ut_tests +/ + +drop type ut_suite_contexts +/ diff --git a/source/core/ut_suite_cache_manager.pkb b/source/core/ut_suite_cache_manager.pkb new file mode 100644 index 000000000..ce7f018e0 --- /dev/null +++ b/source/core/ut_suite_cache_manager.pkb @@ -0,0 +1,154 @@ +create or replace package body ut_suite_cache_manager is + /* + utPLSQL - Version 3 + Copyright 2016 - 2018 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. + */ + + function get_schema_parse_time(a_schema_name varchar2) return timestamp result_cache is + l_cache_parse_time timestamp; + begin + select min(t.parse_time) + into l_cache_parse_time + from ut_suite_cache_schema t + where object_owner = a_schema_name; + return l_cache_parse_time; + end; + + procedure save_object_cache( + a_object_owner varchar2, + a_object_name varchar2, + a_parse_time timestamp, + a_suite_items ut_suite_items + ) is + pragma autonomous_transaction; + l_cached_parse_time timestamp; + l_object_owner varchar2(250) := upper(a_object_owner); + l_object_name varchar2(250) := upper(a_object_name); + begin + if a_suite_items is not null and a_suite_items.count = 0 then + + delete from ut_suite_cache t + where t.object_owner = l_object_owner + and t.object_name = l_object_name; + + delete from ut_suite_cache_package t + where t.object_owner = l_object_owner + and t.object_name = l_object_name; + + else + + select min(parse_time) + into l_cached_parse_time + from ut_suite_cache_package t + where t.object_name = l_object_name + and t.object_owner = l_object_owner; + + if a_parse_time > l_cached_parse_time or l_cached_parse_time is null then + + update ut_suite_cache_schema t + set t.parse_time = a_parse_time + where object_owner = l_object_owner; + + if sql%rowcount = 0 then + insert into ut_suite_cache_schema + (object_owner, parse_time) + values (l_object_owner, a_parse_time); + end if; + + update ut_suite_cache_package t + set t.parse_time = a_parse_time + where t.object_owner = l_object_owner + and t.object_name = l_object_name; + + if sql%rowcount = 0 then + insert into ut_suite_cache_package + (object_owner, object_name, parse_time) + values (l_object_owner, l_object_name, a_parse_time ); + end if; + + delete from ut_suite_cache t + where t.object_owner = l_object_owner + and t.object_name = l_object_name; + + insert into ut_suite_cache t + ( + id, self_type, path, object_owner, object_name, name, + line_no, parse_time, description, + rollback_type, disabled_flag, warnings, + before_all_list, after_all_list, + before_each_list, after_each_list, + before_test_list, after_test_list, + expected_error_codes, item + ) + with suites as ( + select treat(value(x) as ut_suite) i + from table(a_suite_items) x + where x.self_type in( 'UT_SUITE', 'UT_SUITE_CONTEXT' ) ) + select ut_suite_cache_seq.nextval, s.i.self_type as self_type, s.i.path as path, + upper(s.i.object_owner) as object_owner, upper(s.i.object_name) as object_name, upper(s.i.name) as name, + s.i.line_no as line_no, s.i.parse_time as parse_time, s.i.description as description, + s.i.rollback_type as rollback_type, s.i.disabled_flag as disabled_flag, s.i.warnings as warnings, + s.i.before_all_list as before_all_list, s.i.after_all_list as after_all_list, + null before_each_list, null after_each_list, + null before_test_list, null after_test_list, + null expected_error_codes, null item + from suites s; + + insert into ut_suite_cache t + ( + id, self_type, path, object_owner, object_name, name, + line_no, parse_time, description, + rollback_type, disabled_flag, warnings, + before_all_list, after_all_list, + before_each_list, after_each_list, + before_test_list, after_test_list, + expected_error_codes, item + ) + with tests as ( + select treat(value(x) as ut_test) t + from table ( a_suite_items ) x + where x.self_type in ( 'UT_TEST' ) ) + select ut_suite_cache_seq.nextval, s.t.self_type as self_type, s.t.path as path, + upper(s.t.object_owner) as object_owner, upper(s.t.object_name) as object_name, upper(s.t.name) as name, + s.t.line_no as line_no, s.t.parse_time as parse_time, s.t.description as description, + s.t.rollback_type as rollback_type, s.t.disabled_flag as disabled_flag, s.t.warnings as warnings, + null before_all_list, null after_all_list, + s.t.before_each_list as before_each_list, s.t.after_each_list as after_each_list, + s.t.before_test_list as before_test_list, s.t.after_test_list as after_test_list, + s.t.expected_error_codes as expected_error_codes, s.t.item as item + from tests s; + + end if; + end if; + commit; + end; + + procedure remove_from_cache(a_schema_name varchar2, a_objects ut_varchar2_rows) is + pragma autonomous_transaction; + begin + delete from ut_suite_cache i + where i.object_owner = a_schema_name + and i.object_name in ( select column_value from table (a_objects) ); + + delete from ut_suite_cache_package i + where i.object_owner = a_schema_name + and i.object_name in ( select column_value from table (a_objects) ); + + commit; + end; + + +end ut_suite_cache_manager; +/ diff --git a/source/core/ut_suite_cache_manager.pks b/source/core/ut_suite_cache_manager.pks new file mode 100644 index 000000000..02c47988e --- /dev/null +++ b/source/core/ut_suite_cache_manager.pks @@ -0,0 +1,35 @@ +create or replace package ut_suite_cache_manager authid definer is + /* + utPLSQL - Version 3 + Copyright 2016 - 2018 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. + */ + + /** + * Responsible for storing and retrieving suite data from cache + */ + + procedure save_object_cache( + a_object_owner varchar2, + a_object_name varchar2, + a_parse_time timestamp, + a_suite_items ut_suite_items + ); + + function get_schema_parse_time(a_schema_name varchar2) return timestamp result_cache; + + procedure remove_from_cache(a_schema_name varchar2, a_objects ut_varchar2_rows); + +end ut_suite_cache_manager; +/ diff --git a/source/core/ut_suite_cache_package.sql b/source/core/ut_suite_cache_package.sql new file mode 100644 index 000000000..46f49e915 --- /dev/null +++ b/source/core/ut_suite_cache_package.sql @@ -0,0 +1,23 @@ +create table ut_suite_cache_package ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2018 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. + */ + object_owner varchar2(250) not null, + object_name varchar2(250) not null, + parse_time timestamp not null, + constraint ut_suite_cache_package_pk primary key(object_owner, object_name), + constraint ut_suite_cache_package_fk foreign key (object_owner) references ut_suite_cache_schema(object_owner) on delete cascade +) organization index +/ + + diff --git a/source/core/ut_suite_cache_schema.sql b/source/core/ut_suite_cache_schema.sql new file mode 100644 index 000000000..ba257dafd --- /dev/null +++ b/source/core/ut_suite_cache_schema.sql @@ -0,0 +1,20 @@ +create table ut_suite_cache_schema ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2018 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. + */ + object_owner varchar2(250) not null, + parse_time timestamp not null, + constraint ut_suite_cache_schema_pk primary key(object_owner) +) organization index +/ + diff --git a/source/core/ut_suite_cache_seq.sql b/source/core/ut_suite_cache_seq.sql new file mode 100644 index 000000000..0c9c835b8 --- /dev/null +++ b/source/core/ut_suite_cache_seq.sql @@ -0,0 +1,16 @@ +create sequence ut_suite_cache_seq + /* + utPLSQL - Version 3 + Copyright 2016 - 2018 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. + */ +cache 100; + diff --git a/source/core/ut_suite_manager.pkb b/source/core/ut_suite_manager.pkb index ca438813d..3c2c713eb 100644 --- a/source/core/ut_suite_manager.pkb +++ b/source/core/ut_suite_manager.pkb @@ -16,119 +16,22 @@ create or replace package body ut_suite_manager is limitations under the License. */ - subtype tt_schema_suites is ut_suite_builder.tt_schema_suites; - subtype t_object_suite_path is ut_suite_builder.t_object_suite_path; - subtype t_schema_suites_info is ut_suite_builder.t_schema_suites_info; - type t_schema_info is record (changed_at date, obj_cnt integer); - - type t_schema_cache is record( - schema_suites tt_schema_suites - ,changed_at date - ,obj_cnt integer - ,suite_paths t_object_suite_path + type t_path_item is record ( + object_name varchar2(250), + procedure_name varchar2(250), + suite_path varchar2(4000) ); - type tt_schema_suites_list is table of t_schema_cache index by varchar2(128 char); - - g_schema_suites tt_schema_suites_list; - + type t_path_items is table of t_path_item; + type t_schema_paths is table of t_path_items index by varchar2(250 char); - type t_schema_paths is table of ut_varchar2_list index by varchar2(4000 char); + subtype t_cached_suite is ut_suite_cache%rowtype; + type tt_cached_suites is table of t_cached_suite; + type t_cached_suites_cursor is ref cursor return t_cached_suite; + type t_item_levels is table of ut_suite_items index by binary_integer; ------------------ - function get_schema_info(a_owner_name varchar2) return t_schema_info is - l_info t_schema_info; - l_view_name varchar2(200) := ut_metadata.get_dba_view('dba_objects'); - begin - execute immediate q'[ - select nvl(max(t.last_ddl_time), date '4999-12-31'), count(*) - from ]'||l_view_name||q'[ t - where t.owner = :a_owner_name - and t.object_type in ('PACKAGE')]' - into l_info using a_owner_name; - return l_info; - end; - - procedure update_cache(a_owner_name varchar2, a_suites_info t_schema_suites_info, a_total_obj_cnt integer) is - begin - if a_suites_info.schema_suites.count > 0 then - g_schema_suites(a_owner_name).schema_suites := a_suites_info.schema_suites; - g_schema_suites(a_owner_name).changed_at := sysdate; - g_schema_suites(a_owner_name).obj_cnt := a_total_obj_cnt; - g_schema_suites(a_owner_name).suite_paths := a_suites_info.suite_paths; - elsif g_schema_suites.exists(a_owner_name) then - g_schema_suites.delete(a_owner_name); - end if; - end; - - function cache_valid(a_schema_name varchar2) return boolean is - l_info t_schema_info; - l_result boolean := true; - begin - if not g_schema_suites.exists(a_schema_name) then - l_result := false; - else - l_info := get_schema_info(a_schema_name); - if g_schema_suites(a_schema_name).changed_at <= l_info.changed_at or g_schema_suites(a_schema_name).obj_cnt != l_info.obj_cnt then - l_result := false; - else - l_result := true; - end if; - end if; - return l_result; - end; - - function get_schema_suites(a_schema_name in varchar2) return t_schema_suites_info is - l_result t_schema_suites_info; - begin - -- Currently cache invalidation on DDL is not implemented so schema is rescaned each time - if cache_valid(a_schema_name) then - l_result.schema_suites := g_schema_suites(a_schema_name).schema_suites; - l_result.suite_paths := g_schema_suites(a_schema_name).suite_paths; - else - ut_utils.debug_log('Rescanning schema ' || a_schema_name); - l_result := ut_suite_builder.build_schema_suites(a_schema_name); - update_cache(a_schema_name, l_result, get_schema_info(a_schema_name).obj_cnt ); - end if; - - return l_result; - end get_schema_suites; - - function get_schema_ut_packages(a_schema_names ut_varchar2_rows) return ut_object_names is - l_schema_ut_packages ut_object_names := ut_object_names(); - l_schema_suites tt_schema_suites; - l_iter varchar2(4000); - procedure populate_suite_ut_packages(a_suite ut_logical_suite, a_packages in out nocopy ut_object_names) is - l_sub_suite ut_logical_suite; - begin - if a_suite is of (ut_suite) then - a_packages.extend; - a_packages(a_packages.last) := ut_object_name(a_suite.object_owner, a_suite.object_name); - end if; - for i in 1 .. a_suite.items.count loop - if a_suite.items(i) is of (ut_logical_suite) then - l_sub_suite := treat(a_suite.items(i) as ut_logical_suite); - populate_suite_ut_packages(l_sub_suite, a_packages); - end if; - end loop; - end; - begin - if a_schema_names is not null then - for i in 1 .. a_schema_names.count loop - l_schema_suites := get_schema_suites(a_schema_names(i)).schema_suites; - l_iter := l_schema_suites.first; - while l_iter is not null loop - populate_suite_ut_packages(l_schema_suites(l_iter), l_schema_ut_packages); - l_iter := l_schema_suites.next(l_iter); - end loop; - end loop; - l_schema_ut_packages := set(l_schema_ut_packages); - end if; - - return l_schema_ut_packages; - end; - procedure validate_paths(a_paths in ut_varchar2_list) is l_path varchar2(32767); begin @@ -144,7 +47,7 @@ create or replace package body ut_suite_manager is end if; end; - function clean_paths(a_paths ut_varchar2_list) return ut_varchar2_list is + function trim_and_lower_paths( a_paths ut_varchar2_list) return ut_varchar2_list is l_paths_temp ut_varchar2_list := ut_varchar2_list(); begin l_paths_temp.extend(a_paths.count); @@ -160,7 +63,7 @@ create or replace package body ut_suite_manager is l_schema_names ut_varchar2_rows := ut_varchar2_rows(); c_current_schema constant all_tables.owner%type := sys_context('USERENV','CURRENT_SCHEMA'); begin - a_paths := set( clean_paths(a_paths) ); + a_paths := set( trim_and_lower_paths( a_paths) ); validate_paths(a_paths); @@ -205,175 +108,696 @@ create or replace package body ut_suite_manager is l_schema_names := resolve_schema_names(a_paths); end; - function get_schema_names(a_paths ut_varchar2_list) return ut_varchar2_rows is - l_paths ut_varchar2_list; + function group_paths_by_schema(a_paths ut_varchar2_list) return t_schema_paths is + c_package_path_regex constant varchar2(100) := '^([A-Za-z0-9$#_]+)(\.([A-Za-z0-9$#_]+))?(\.([A-Za-z0-9$#_]+))?$'; + l_schema varchar2(4000); + l_empty_result t_path_item; + l_result t_path_item; + l_results t_schema_paths; begin - l_paths := a_paths; - return resolve_schema_names(l_paths); + for i in 1 .. a_paths.count loop + l_result := l_empty_result; + if a_paths(i) like '%:%' then + l_schema := upper(regexp_substr(a_paths(i),'^[^.:]+')); + l_result.suite_path := ltrim(regexp_substr(a_paths(i),'[.:].*$'),':'); + else + l_schema := regexp_substr(a_paths(i), c_package_path_regex, subexpression => 1); + l_result.object_name := regexp_substr(a_paths(i), c_package_path_regex, subexpression => 3); + l_result.procedure_name := regexp_substr(a_paths(i), c_package_path_regex, subexpression => 5); + end if; + if l_results.exists(l_schema) then + l_results(l_schema).extend; + l_results(l_schema)(l_results(l_schema).last) := l_result; + else + l_results(l_schema) := t_path_items(l_result); + end if; + end loop; + return l_results; end; - procedure filter_suite_by_path(a_suite in out nocopy ut_suite_item, a_path varchar2) is - c_item_name constant varchar2(32767) := lower(regexp_substr(a_path, '[A-Za-z0-9$#_]+')); - c_child_filter_path constant varchar2(32767) := regexp_substr(a_path, '\.(.+)', subexpression => 1); - l_suite ut_logical_suite; - l_item ut_suite_item; - l_items ut_suite_items := ut_suite_items(); - - function find_item_in_suite(a_suite ut_logical_suite, a_item_name varchar2) return ut_suite_item is - l_item_index binary_integer; - begin - l_item_index := a_suite.items.first; - while l_item_index is not null loop - if lower(a_suite.items(l_item_index).name) = a_item_name then - return a_suite.items(l_item_index); - end if; - l_item_index := a_suite.items.next(l_item_index); + + function sort_by_seq_no( + a_list ut_executables + ) return ut_executables is + l_results ut_executables := ut_executables(); + begin + if a_list is not null then + l_results.extend(a_list.count); + for i in 1 .. a_list.count loop + l_results(a_list(i).seq_no) := a_list(i); end loop; - return null; - end; - - function find_item_in_suite_contexts(a_suite ut_logical_suite, a_item_name varchar2) return ut_suite_item is - l_item_index binary_integer; - l_context ut_suite_context; - l_item ut_suite_item; - begin - l_item_index := a_suite.items.first; - while l_item_index is not null loop - if a_suite.items(l_item_index) is of (ut_suite_context) then - l_item := find_item_in_suite( - treat(a_suite.items(l_item_index) as ut_suite_context) - , a_item_name - ); - end if; + end if; + return l_results; + end; - if l_item is not null then - l_context := treat(a_suite.items(l_item_index) as ut_suite_context); - l_context.items := ut_suite_items(l_item); - exit; + procedure reverse_list_order( + a_list in out nocopy ut_suite_items + ) is + l_start_idx pls_integer; + l_end_idx pls_integer; + l_item ut_suite_item; + begin + l_start_idx := a_list.first; + l_end_idx := a_list.last; + while l_start_idx < l_end_idx loop + l_item := a_list(l_start_idx); + a_list(l_start_idx) := a_list(l_end_idx); + a_list(l_end_idx) := l_item; + l_end_idx := a_list.prior(l_end_idx); + l_start_idx := a_list.next(l_start_idx); + end loop; + end; + + function get_logical_suite( + a_rows tt_cached_suites, + a_idx pls_integer, + a_level pls_integer, + a_prev_level pls_integer, + a_items_at_level t_item_levels + ) return ut_suite_item is + l_result ut_suite_item; + begin + case a_rows( a_idx ).self_type + when 'UT_SUITE' then + l_result := + case when a_prev_level > a_level then + ut_suite( + self_type => a_rows( a_idx ).self_type, + object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), + name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, + rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, + line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, + start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => a_items_at_level(a_prev_level), + before_all_list => sort_by_seq_no( a_rows( a_idx ).before_all_list), after_all_list => sort_by_seq_no( + a_rows( a_idx ).after_all_list) + ) + else + ut_suite( + self_type => a_rows( a_idx ).self_type, + object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), + name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, + rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, + line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, + start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => ut_suite_items(), + before_all_list => sort_by_seq_no( a_rows( a_idx ).before_all_list), after_all_list => sort_by_seq_no( + a_rows( a_idx ).after_all_list) + ) + end; + when 'UT_SUITE_CONTEXT' then + l_result := + case when a_prev_level > a_level then + ut_suite_context( + self_type => a_rows( a_idx ).self_type, + object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), + name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, + rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, + line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, + start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => a_items_at_level(a_prev_level), + before_all_list => sort_by_seq_no( a_rows( a_idx ).before_all_list), after_all_list => sort_by_seq_no( + a_rows( a_idx ).after_all_list) + ) + else + ut_suite_context( + self_type => a_rows( a_idx ).self_type, + object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), + name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, + rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, + line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, + start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => ut_suite_items(), + before_all_list => sort_by_seq_no( a_rows( a_idx ).before_all_list), after_all_list => sort_by_seq_no( + a_rows( a_idx ).after_all_list) + ) + end; + when 'UT_LOGICAL_SUITE' then + l_result := + case when a_prev_level > a_level then + ut_logical_suite( + self_type => a_rows( a_idx ).self_type, + object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), + name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, + rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, + line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, + start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => a_items_at_level(a_prev_level) + ) + else + ut_logical_suite( + self_type => a_rows( a_idx ).self_type, + object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), + name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, + rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, + line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, + start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => ut_suite_items() + ) + end; + when 'UT_TEST' then + l_result := + ut_test( + self_type => a_rows(a_idx).self_type, + object_owner => a_rows(a_idx).object_owner, object_name => lower(a_rows(a_idx).object_name), + name => lower(a_rows(a_idx).name), description => a_rows(a_idx).description, path => a_rows(a_idx).path, + rollback_type => a_rows(a_idx).rollback_type, disabled_flag => a_rows(a_idx).disabled_flag, + line_no => a_rows(a_idx).line_no, parse_time => a_rows(a_idx).parse_time, + start_time => null, end_time => null, result => null, warnings => a_rows(a_idx).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + before_each_list => sort_by_seq_no(a_rows(a_idx).before_each_list), before_test_list => sort_by_seq_no(a_rows(a_idx).before_test_list), + item => a_rows(a_idx).item, + after_test_list => sort_by_seq_no(a_rows(a_idx).after_test_list), after_each_list => sort_by_seq_no(a_rows(a_idx).after_each_list), + all_expectations => ut_expectation_results(), failed_expectations => ut_expectation_results(), + parent_error_stack_trace => null, expected_error_codes => a_rows(a_idx).expected_error_codes + ); + end case; + l_result.results_count.warnings_count := l_result.warnings.count; + return l_result; + end; + + procedure reconstruct_from_cache( + a_suites in out nocopy ut_suite_items, + a_suite_data_cursor sys_refcursor + ) is + c_bulk_limit constant pls_integer := 1000; + l_items_at_level t_item_levels; + l_rows tt_cached_suites; + l_level pls_integer; + l_prev_level pls_integer; + l_idx integer; + begin + loop + fetch a_suite_data_cursor bulk collect into l_rows limit c_bulk_limit; + + l_idx := l_rows.first; + while l_idx is not null loop + l_level := length(l_rows(l_idx).path) - length( replace(l_rows(l_idx).path, '.') ) + 1; + if l_level > 1 then + if not l_items_at_level.exists(l_level) then + l_items_at_level(l_level) := ut_suite_items(); + end if; + l_items_at_level(l_level).extend; + pragma inline(get_logical_suite, 'YES'); + l_items_at_level(l_level)(l_items_at_level(l_level).last) := get_logical_suite(l_rows, l_idx, l_level,l_prev_level, l_items_at_level ); + else + a_suites.extend; + pragma inline(get_logical_suite, 'YES'); + a_suites(a_suites.last) := get_logical_suite(l_rows, l_idx, l_level,l_prev_level, l_items_at_level ); end if; - l_item_index := a_suite.items.next(l_item_index); + if l_prev_level > l_level then + l_items_at_level(l_prev_level).delete; + end if; + l_prev_level := l_level; + l_idx := l_rows.next(l_idx); end loop; - return l_context; - end; + exit when a_suite_data_cursor%NOTFOUND; + end loop; + + reverse_list_order( a_suites ); + + for i in 1 .. a_suites.count loop + a_suites( i ).set_rollback_type( a_suites( i ).get_rollback_type ); + end loop; + close a_suite_data_cursor; + end reconstruct_from_cache; + + function get_missing_objects(a_object_owner varchar2) return ut_varchar2_rows is + l_rows sys_refcursor; + l_ut_owner varchar2(250) := ut_utils.ut_owner; + l_objects_view varchar2(200) := ut_metadata.get_objects_view_name(); + l_cursor_text varchar2(32767); + l_result ut_varchar2_rows; begin - if a_suite is of (ut_logical_suite) then - l_suite := treat(a_suite as ut_logical_suite); - - l_item := coalesce( - find_item_in_suite(l_suite, c_item_name) - , find_item_in_suite_contexts(l_suite, c_item_name) - ); - if l_item is not null then - if c_child_filter_path is not null then - filter_suite_by_path(l_item, c_child_filter_path); - end if; - l_items.extend; - l_items(l_items.count) := l_item; - else - raise_application_error(-20203, 'Suite item '||c_item_name||' not found'); - end if; + l_cursor_text := + q'[select i.object_name + from ]'||l_ut_owner||q'[.ut_suite_cache_package i + where + not exists ( + select 1 from ]'||l_objects_view||q'[ o + where o.owner = i.object_owner + and o.object_name = i.object_name + and o.object_type = 'PACKAGE' + and o.owner = ']'||a_object_owner||q'[' + ) + and i.object_owner = ']'||a_object_owner||q'[']'; + open l_rows for l_cursor_text; + fetch l_rows bulk collect into l_result limit 1000000; + close l_rows; + return l_result; + end; - l_suite.items := l_items; - a_suite := l_suite; + function get_cached_suite_data( + a_object_owner varchar2, + a_path varchar2 := null, + a_object_name varchar2 := null, + a_procedure_name varchar2 := null, + a_skip_all_objects boolean := false + ) return t_cached_suites_cursor is + l_path varchar2( 4000 ); + l_result sys_refcursor; + l_ut_owner varchar2(250) := ut_utils.ut_owner; + begin + if a_path is null and a_object_name is not null then + execute immediate 'select min(path) + from '||l_ut_owner||q'[.ut_suite_cache + where object_owner = :a_object_owner + and object_name = :a_object_name + and name = nvl(:a_procedure_name, name)]' + into l_path using upper(a_object_owner), upper(a_object_name), upper(a_procedure_name); + else + l_path := lower( a_path ); end if; - end filter_suite_by_path; - function get_suite_filtered_by_path(a_path varchar2, a_schema_suites tt_schema_suites) return ut_logical_suite is - l_suite ut_logical_suite; - c_suite_path constant varchar2(32767) := regexp_substr(a_path, ':(.+)', subexpression => 1); - c_root_suite_name constant varchar2(32767) := regexp_substr(c_suite_path, '^[A-Za-z0-9$#_]+'); - c_child_filter_path constant varchar2(32767) := regexp_substr(c_suite_path, '\.(.+)', subexpression => 1); + open l_result for + q'[with + suite_items as ( + select /*+ cardinality(c 100) */ c.* + from ]'||l_ut_owner||q'[.ut_suite_cache c + where 1 = 1 ]'||case when not a_skip_all_objects then q'[ + and exists + ( select 1 + from all_objects a + where a.object_name = c.object_name + and a.owner = ']'||upper(a_object_owner)||q'[' + and a.owner = c.object_owner + and a.object_type = 'PACKAGE' + )]' end ||q'[ + and c.object_owner = ']'||upper(a_object_owner)||q'[' + and ( ]' || case when l_path is not null then q'[ + :l_path||'.' like c.path || '.%' /*all children and self*/ + or ( c.path||'.' like :l_path || '.%' --all parents + ]' + else ' :l_path is null and ( :l_path is null ' end + || case when a_object_name is not null + then 'and c.object_name = :a_object_name ' + else 'and :a_object_name is null' end ||' + '|| case when a_procedure_name is not null + then 'and c.name = :a_procedure_name' + else 'and :a_procedure_name is null' end ||q'[ + ) + ) + ), + suitepaths as ( + select distinct substr(path,1,instr(path,'.',-1)-1) as suitepath, + path, + object_owner + from suite_items + where self_type = 'UT_SUITE' + ), + gen as ( + select rownum as pos + from xmltable('1 to 20') + ), + suitepath_part AS ( + select distinct + substr(b.suitepath, 1, instr(b.suitepath || '.', '.', 1, g.pos) -1) as path, + object_owner + from suitepaths b + join gen g + on g.pos <= regexp_count(b.suitepath, '\w+') + ), + logical_suite_data as ( + select 'UT_LOGICAL_SUITE' as self_type, p.path, p.object_owner, + upper( substr(p.path, instr( p.path, '.', -1 ) + 1 ) ) as object_name, + cast(null as ]'||l_ut_owner||q'[.ut_executables) as x, + cast(null as ]'||l_ut_owner||q'[.ut_integer_list) as y, + cast(null as ]'||l_ut_owner||q'[.ut_executable_test) as z + from suitepath_part p + where p.path + not in (select s.path from suitepaths s) + ), + logical_suites as ( + select to_number(null) as id, s.self_type, s.path, s.object_owner, s.object_name, + s.object_name as name, null as line_no, null as parse_time, + null as description, null as rollback_type, 0 as disabled_flag, + ]'||l_ut_owner||q'[.ut_varchar2_rows() as warnings, + s.x as before_all_list, s.x as after_all_list, + s.x as before_each_list, s.x as before_test_list, + s.x as after_each_list, s.x as after_test_list, + s.y as expected_error_codes, s.z as item + from logical_suite_data s + ), + items as ( + select * from suite_items + union all + select * from logical_suites + ) + select c.* + from items c + order by c.object_owner, + replace(case + when c.self_type in ( 'UT_TEST' ) + then substr(c.path, 1, instr(c.path, '.', -1) ) + else c.path + end, '.', chr(0)) desc nulls last, + c.object_name desc, + c.line_no]' + using l_path, l_path, upper(a_object_name), upper(a_procedure_name); + + return l_result; + end; + + function can_skip_all_objects_scan( + a_owner_name varchar2 + ) return boolean is begin - l_suite := a_schema_suites(c_root_suite_name); - if c_child_filter_path is not null then - filter_suite_by_path(l_suite, c_child_filter_path); - end if; - return l_suite; - exception - when no_data_found then - raise_application_error(-20203, 'Suite ' || c_root_suite_name || ' does not exist or is invalid'); + return sys_context( 'userenv', 'current_schema' ) = a_owner_name or ut_metadata.user_has_execute_any_proc(); end; - function convert_to_suite_path(a_path varchar2, a_suite_paths t_object_suite_path) return varchar2 is - c_package_path_regex constant varchar2(100) := '^([A-Za-z0-9$#_]+)\.([A-Za-z0-9$#_]+)(\.([A-Za-z0-9$#_]+))?$'; - l_schema_name varchar2(4000) := regexp_substr(a_path, c_package_path_regex, subexpression => 1); - l_package_name varchar2(4000) := regexp_substr(a_path, c_package_path_regex, subexpression => 2); - l_procedure_name varchar2(4000) := regexp_substr(a_path, c_package_path_regex, subexpression => 4); - l_path varchar2(4000) := a_path; + procedure build_and_cache_suites( + a_owner_name varchar2, + a_annotated_objects sys_refcursor + ) is + l_annotated_objects ut_annotated_objects; + l_suite_items ut_suite_items; begin - if regexp_like(l_path, c_package_path_regex) then - if not a_suite_paths.exists(l_package_name) then - raise_application_error(ut_utils.gc_suite_package_not_found,'Suite package '||l_schema_name||'.'||l_package_name|| ' not found'); - end if; - l_path := rtrim(l_schema_name || ':' || a_suite_paths(l_package_name) || '.' || l_procedure_name, '.'); + loop + fetch a_annotated_objects bulk collect into l_annotated_objects limit 10; + + for i in 1 .. l_annotated_objects.count loop + ut_suite_builder.create_suite_item_list( l_annotated_objects( i ), l_suite_items ); + ut_suite_cache_manager.save_object_cache( + a_owner_name, + l_annotated_objects( i ).object_name, + l_annotated_objects( i ).parse_time, + l_suite_items + ); + end loop; + exit when a_annotated_objects%notfound; + end loop; + close a_annotated_objects; + + end; + + procedure refresh_cache( + a_owner_name varchar2, + a_annotations_cursor sys_refcursor := null + ) is + l_annotations_cursor sys_refcursor; + l_suite_cache_time timestamp; + begin + l_suite_cache_time := ut_suite_cache_manager.get_schema_parse_time(a_owner_name); + if a_annotations_cursor is not null then + l_annotations_cursor := a_annotations_cursor; + else + open l_annotations_cursor for + q'[select value(x) + from table( + ]' || ut_utils.ut_owner || q'[.ut_annotation_manager.get_annotated_objects( + :a_owner_name, 'PACKAGE', :a_suite_cache_parse_time + ) + )x ]' + using a_owner_name, l_suite_cache_time; + end if; + + build_and_cache_suites(a_owner_name, l_annotations_cursor); + + if can_skip_all_objects_scan(a_owner_name) or ut_metadata.is_object_visible( 'dba_objects') then + ut_suite_cache_manager.remove_from_cache( a_owner_name, get_missing_objects(a_owner_name) ); end if; - return l_path; + end; - function group_paths_by_schema(a_paths ut_varchar2_list) return t_schema_paths is - l_result t_schema_paths; - l_schema varchar2(4000); + procedure add_suites_for_path( + a_owner_name varchar2, + a_path varchar2 := null, + a_object_name varchar2 := null, + a_procedure_name varchar2 := null, + a_suites in out nocopy ut_suite_items + ) is begin - for i in 1 .. a_paths.count loop - l_schema := upper(regexp_substr(a_paths(i),'^[^.:]+')); - if l_result.exists(l_schema) then - l_result(l_schema).extend; - l_result(l_schema)(l_result(l_schema).last) := a_paths(i); - else - l_result(l_schema) := ut_varchar2_list(a_paths(i)); - end if; + refresh_cache(a_owner_name); + + reconstruct_from_cache( + a_suites, + get_cached_suite_data( + a_owner_name, + a_path, + a_object_name, + a_procedure_name, + can_skip_all_objects_scan(a_owner_name) + ) + ); + + end; + + ----------------------------------------------- + ----------------------------------------------- + ------------- Public definitions ------------- + + function build_suites_from_annotations( + a_owner_name varchar2, + a_annotated_objects sys_refcursor, + a_path varchar2 := null, + a_object_name varchar2 := null, + a_procedure_name varchar2 := null, + a_skip_all_objects boolean := false + ) return ut_suite_items is + l_suites ut_suite_items := ut_suite_items(); + begin + build_and_cache_suites(a_owner_name, a_annotated_objects); + + reconstruct_from_cache( + l_suites, + get_cached_suite_data( + a_owner_name, + a_path, + a_object_name, + a_procedure_name, + a_skip_all_objects + ) + ); + return l_suites; + end; + + function get_schema_ut_packages(a_schema_names ut_varchar2_rows) return ut_object_names is + l_results ut_object_names := ut_object_names( ); + l_schema_names ut_varchar2_rows; + l_object_names ut_varchar2_rows; + l_ut_owner varchar2(250) := ut_utils.ut_owner; + l_need_all_objects_scan boolean := true; + begin + -- if current user is the onwer or current user has execute any procedure privilege + if ut_metadata.user_has_execute_any_proc() + or (a_schema_names is not null and a_schema_names.count = 1 + and sys_context('userenv','current_schema') = a_schema_names(1)) + then + l_need_all_objects_scan := false; + end if; + + execute immediate 'select c.object_owner, c.object_name + from '||l_ut_owner||q'[.ut_suite_cache_package c + join table ( :a_schema_names ) s + on c.object_owner = upper(s.column_value)]' + || case when l_need_all_objects_scan then q'[ + where exists + (select 1 from all_objects a + where a.owner = c.object_owner + and a.object_name = c.object_name + and a.object_type = 'PACKAGE') + ]' end + bulk collect into l_schema_names, l_object_names using a_schema_names; + l_results.extend( l_schema_names.count ); + for i in 1 .. l_schema_names.count loop + l_results( i ) := ut_object_name( l_schema_names( i ), l_object_names( i ) ); end loop; - return l_result; + return l_results; + end; + + function get_schema_names(a_paths ut_varchar2_list) return ut_varchar2_rows is + l_paths ut_varchar2_list; + begin + l_paths := a_paths; + return resolve_schema_names(l_paths); end; function configure_execution_by_path(a_paths in ut_varchar2_list) return ut_suite_items is + l_suites ut_suite_items := ut_suite_items(); + begin + configure_execution_by_path(a_paths, l_suites ); + return l_suites; + end; + + procedure configure_execution_by_path(a_paths in ut_varchar2_list, a_suites out nocopy ut_suite_items) is l_paths ut_varchar2_list := a_paths; - l_path varchar2(32767); + l_path_items t_path_items; + l_path_item t_path_item; l_schema varchar2(4000); - l_suites_info t_schema_suites_info; + l_suites_count pls_integer := 0; l_index varchar2(4000 char); - l_suite ut_logical_suite; - l_objects_to_run ut_suite_items; l_schema_paths t_schema_paths; begin + a_suites := ut_suite_items(); --resolve schema names from paths and group paths by schema name resolve_schema_names(l_paths); l_schema_paths := group_paths_by_schema(l_paths); - l_objects_to_run := ut_suite_items(); - l_schema := l_schema_paths.first; while l_schema is not null loop - l_paths := l_schema_paths(l_schema); - l_suites_info := get_schema_suites(l_schema); - - for i in 1 .. l_paths.count loop - l_path := l_paths(i); - --run whole schema - if regexp_like(l_path, '^[A-Za-z0-9$#_]+$') then - l_index := l_suites_info.schema_suites.first; - while l_index is not null loop - l_objects_to_run.extend; - l_objects_to_run(l_objects_to_run.count) := l_suites_info.schema_suites(l_index); - l_index := l_suites_info.schema_suites.next(l_index); - end loop; - else - l_suite := get_suite_filtered_by_path( convert_to_suite_path( l_path, l_suites_info.suite_paths ), l_suites_info.schema_suites ); - l_objects_to_run.extend; - l_objects_to_run(l_objects_to_run.count) := l_suite; + l_path_items := l_schema_paths(l_schema); + for i in 1 .. l_path_items.count loop + l_path_item := l_path_items(i); + add_suites_for_path( + upper(l_schema), + l_path_item.suite_path, + l_path_item.object_name, + l_path_item.procedure_name, + a_suites + ); + if a_suites.count = l_suites_count then + if l_path_item.suite_path is not null then + raise_application_error(ut_utils.gc_suite_package_not_found,'No suite packages found for path '||l_schema||':'||l_path_item.suite_path|| '.'); + elsif l_path_item.procedure_name is not null then + raise_application_error(ut_utils.gc_suite_package_not_found,'Suite test '||l_schema||'.'||l_path_item.object_name|| '.'||l_path_item.procedure_name||' does not exist'); + elsif l_path_item.object_name is not null then + raise_application_error(ut_utils.gc_suite_package_not_found,'Suite package '||l_schema||'.'||l_path_item.object_name|| ' does not exist'); + end if; end if; + l_index := a_suites.first; + l_suites_count := a_suites.count; end loop; l_schema := l_schema_paths.next(l_schema); end loop; --propagate rollback type to suite items after organizing suites into hierarchy - for i in 1 .. l_objects_to_run.count loop - l_objects_to_run(i).set_rollback_type( l_objects_to_run(i).get_rollback_type() ); + for i in 1 .. a_suites.count loop + a_suites(i).set_rollback_type( a_suites(i).get_rollback_type() ); end loop; - return l_objects_to_run; end configure_execution_by_path; + function get_suites_info( + a_owner_name varchar2, + a_package_name varchar2 := null + ) return sys_refcursor is + l_result sys_refcursor; + l_ut_owner varchar2(250) := ut_utils.ut_owner; + begin + + refresh_cache(a_owner_name); + + open l_result for + q'[with + suite_items as ( + select /*+ cardinality(c 100) */ c.* + from ]'||l_ut_owner||q'[.ut_suite_cache c + where 1 = 1 ]'||case when can_skip_all_objects_scan(a_owner_name) then q'[ + and exists + ( select 1 + from all_objects a + where a.object_name = c.object_name + and a.owner = ']'||upper(a_owner_name)||q'[' + and a.owner = c.object_owner + and a.object_type = 'PACKAGE' + )]' end ||q'[ + and c.object_owner = ']'||upper(a_owner_name) ||q'[' + and ]' + || case when a_package_name is not null + then 'c.object_name = :a_package_name' + else ':a_package_name is null' end + || q'[ + ), + suitepaths as ( + select distinct + substr(path,1,instr(path,'.',-1)-1) as suitepath, + path, + object_owner + from suite_items + where self_type = 'UT_SUITE' + ), + gen as ( + select rownum as pos + from xmltable('1 to 20') + ), + suitepath_part AS ( + select distinct + substr(b.suitepath, 1, instr(b.suitepath || '.', '.', 1, g.pos) -1) as path, + object_owner + from suitepaths b + join gen g + on g.pos <= regexp_count(b.suitepath, '\w+') + ), + logical_suites as ( + select 'UT_LOGICAL_SUITE' as item_type, + p.path, p.object_owner, + upper( substr(p.path, instr( p.path, '.', -1 ) + 1 ) ) as object_name + from suitepath_part p + where p.path + not in (select s.path from suitepaths s) + ), + items as ( + select object_owner, object_name, name as item_name, + description as item_description, self_type as item_type, line_no as item_line_no, + path, disabled_flag + from suite_items + union all + select object_owner, object_name, object_name as item_name, + null as item_description, item_type, null as item_line_no, + s.path, 0 as disabled_flag + from logical_suites s + ) + select ]'||l_ut_owner||q'[.ut_suite_item_info( + object_owner, object_name, item_name, item_description, + item_type, item_line_no, path, disabled_flag + ) + from items c]' using upper(a_package_name); + + return l_result; + end; + + function suite_item_exists( + a_owner_name varchar2, + a_package_name varchar2 := null, + a_procedure_name varchar2 := null, + a_item_type varchar2 := null + ) return boolean is + l_result integer; + l_ut_owner varchar2(250) := ut_utils.ut_owner; + begin + refresh_cache(a_owner_name); + + execute immediate q'[ + select count(1) from dual + where exists ( + select 1 + from ]'||l_ut_owner||q'[.ut_suite_cache c + where 1 = 1 ]'||case when can_skip_all_objects_scan(a_owner_name) then q'[ + and exists + ( select 1 + from all_objects a + where a.object_name = c.object_name + and a.owner = :a_owner_name + and a.owner = c.object_owner + and a.object_type = 'PACKAGE' + )]' else q'[ + and :a_owner_name is not null ]' end ||q'[ + and c.object_owner = :a_owner_name + and ]' + || case when a_package_name is not null + then 'c.object_name = :a_package_name' + else ':a_package_name is null' end + || q'[ + and ]' + || case when a_procedure_name is not null + then 'c.name = :a_procedure_name' + else ':a_procedure_name is null' end + || q'[ + )]' + into l_result + using + upper(a_owner_name), upper(a_owner_name), + upper(a_package_name), upper(a_procedure_name); + + return l_result > 0; + end; + end ut_suite_manager; / diff --git a/source/core/ut_suite_manager.pks b/source/core/ut_suite_manager.pks index 3fde7f6b5..5fd82f9be 100644 --- a/source/core/ut_suite_manager.pks +++ b/source/core/ut_suite_manager.pks @@ -39,11 +39,65 @@ create or replace package ut_suite_manager authid current_user is */ function configure_execution_by_path(a_paths in ut_varchar2_list) return ut_suite_items; + /** + * Builds a hierarchical suites based on given suite-paths + * + * @param a_paths list of suite-paths or procedure names or package names or schema names + * @param a_suites returned array containing root suites-ready to be executed + * + */ + procedure configure_execution_by_path(a_paths in ut_varchar2_list, a_suites out nocopy ut_suite_items); + /** * Cleanup paths by removing leading/trailing whitespace and making paths lowercase * Get list of schema names from execution paths. */ function get_schema_names(a_paths ut_varchar2_list) return ut_varchar2_rows; + + /** + * Constructs a list of suites based on the list of annotations passed + * the suites are stored in cache + */ + function build_suites_from_annotations( + a_owner_name varchar2, + a_annotated_objects sys_refcursor, + a_path varchar2 := null, + a_object_name varchar2 := null, + a_procedure_name varchar2 := null, + a_skip_all_objects boolean := false + ) return ut_suite_items; + + + /** + * Returns a ref cursor containing information about unit test suites and the tests contained in them + * + * @param a_owner owner of unit tests to retrieve + * @param a_package_name name of test package (optional) + * @param a_procedure_name name of test procedure (optional) + * @return ut_suite_items_info table of objects + */ + function get_suites_info( + a_owner_name varchar2, + a_package_name varchar2 := null + ) return sys_refcursor; + + /** + * Returns true if given suite item exists + * + * @param a_owner owner of items to retrieve + * @param a_package_name name of suite package (optional) + * @param a_procedure_name name of suite item (optional) + * @param a_item_type suite_item type (optional) + * @return ut_suite_items_info table of objects + */ + function suite_item_exists( + a_owner_name varchar2, + a_package_name varchar2 := null, + a_procedure_name varchar2 := null, + a_item_type varchar2 := null + ) return boolean; + + end ut_suite_manager; / diff --git a/source/core/ut_utils.pkb b/source/core/ut_utils.pkb index 2528c04e7..dbe57f866 100644 --- a/source/core/ut_utils.pkb +++ b/source/core/ut_utils.pkb @@ -55,18 +55,6 @@ create or replace package body ut_utils is return '"'|| utl_raw.cast_to_varchar2(utl_encode.base64_encode(sys_guid()))||'"'; end; - /* - Procedure: validate_rollback_type - - Validates passed value against supported rollback types - */ - procedure validate_rollback_type(a_rollback_type number) is - begin - if a_rollback_type not in (gc_rollback_auto, gc_rollback_manual) then - raise_application_error(-20200,'Rollback type is not supported'); - end if; - end validate_rollback_type; - procedure debug_log(a_message varchar2) is begin $if $$ut_trace $then @@ -326,7 +314,50 @@ create or replace package body ut_utils is end if; end append_to_list; -procedure append_to_clob(a_src_clob in out nocopy clob, a_clob_table t_clob_tab, a_delimiter varchar2:= chr(10)) is + procedure append_to_list(a_list in out nocopy ut_varchar2_rows, a_items ut_varchar2_rows) is + begin + if a_items is not null then + if a_list is null then + a_list := ut_varchar2_rows(); + end if; + for i in 1 .. a_items.count loop + a_list.extend; + a_list(a_list.last) := a_items(i); + end loop; + end if; + end; + + procedure append_to_list(a_list in out nocopy ut_varchar2_rows, a_item clob) is + begin + append_to_list( + a_list, + convert_collection( + clob_to_table( a_item, ut_utils.gc_max_storage_varchar2_len ) + ) + ); + end; + + procedure append_to_list(a_list in out nocopy ut_varchar2_rows, a_item varchar2) is + begin + if a_item is not null then + if a_list is null then + a_list := ut_varchar2_rows(); + end if; + if length(a_item) > gc_max_storage_varchar2_len then + append_to_list( + a_list, + ut_utils.convert_collection( + ut_utils.clob_to_table( a_item, gc_max_storage_varchar2_len ) + ) + ); + else + a_list.extend; + a_list(a_list.last) := a_item; + end if; + end if; + end append_to_list; + + procedure append_to_clob(a_src_clob in out nocopy clob, a_clob_table t_clob_tab, a_delimiter varchar2:= chr(10)) is begin if a_clob_table is not null and cardinality(a_clob_table) > 0 then if a_src_clob is null then @@ -522,7 +553,7 @@ procedure append_to_clob(a_src_clob in out nocopy clob, a_clob_table t_clob_tab, ||'?>'; end; - function trim_list_elements(a_list IN ut_varchar2_list, a_regexp_to_trim in varchar2 default '[:space:]') return ut_varchar2_list is + function trim_list_elements(a_list ut_varchar2_list, a_regexp_to_trim varchar2 default '[:space:]') return ut_varchar2_list is l_trimmed_list ut_varchar2_list; l_index integer; begin @@ -561,15 +592,13 @@ procedure append_to_clob(a_src_clob in out nocopy clob, a_clob_table t_clob_tab, end; function xmlgen_escaped_string(a_string in varchar2) return varchar2 is - l_result varchar2(4000); + l_result varchar2(4000) := a_string; l_sql varchar2(32767) := q'!select q'[!'||a_string||q'!]' as "!'||a_string||'" from dual'; begin if a_string is not null then select extract(dbms_xmlgen.getxmltype(l_sql),'/*/*/*').getRootElement() into l_result from dual; - else - l_result := a_string; end if; return l_result; end; diff --git a/source/core/ut_utils.pks b/source/core/ut_utils.pks index c384bb693..b35bc3302 100644 --- a/source/core/ut_utils.pks +++ b/source/core/ut_utils.pks @@ -183,12 +183,6 @@ create or replace package ut_utils authid definer is function int_to_boolean(a_value integer) return boolean; - /** - * Validates passed value against supported rollback types - */ - procedure validate_rollback_type(a_rollback_type number); - - /** * * Splits a given string into table of string by delimiter. @@ -247,6 +241,21 @@ create or replace package ut_utils authid definer is */ procedure append_to_list(a_list in out nocopy ut_varchar2_list, a_item varchar2); + /** + * Append a item to the end of ut_varchar2_rows + */ + procedure append_to_list(a_list in out nocopy ut_varchar2_rows, a_item varchar2); + + /** + * Append a item to the end of ut_varchar2_rows + */ + procedure append_to_list(a_list in out nocopy ut_varchar2_rows, a_item clob); + + /** + * Append a list of items to the end of ut_varchar2_rows + */ + procedure append_to_list(a_list in out nocopy ut_varchar2_rows, a_items ut_varchar2_rows); + procedure append_to_clob(a_src_clob in out nocopy clob, a_clob_table t_clob_tab, a_delimiter varchar2 := chr(10)); procedure append_to_clob(a_src_clob in out nocopy clob, a_new_data clob); diff --git a/source/create_synonyms_and_grants_for_public.sql b/source/create_synonyms_and_grants_for_public.sql index 1ac5bb9ea..b8daca313 100644 --- a/source/create_synonyms_and_grants_for_public.sql +++ b/source/create_synonyms_and_grants_for_public.sql @@ -86,10 +86,17 @@ grant execute on &&ut3_owner..ut_annotated_object to public; grant execute on &&ut3_owner..ut_annotated_objects to public; grant select on &&ut3_owner..ut_annotation_cache_info to public; grant select on &&ut3_owner..ut_annotation_cache to public; +grant execute on &&ut3_owner..ut_executables to public; +grant execute on &&ut3_owner..ut_executable_test to public; +grant select on &&ut3_owner..ut_suite_cache to public; +grant select on &&ut3_owner..ut_suite_cache_package to public; +grant select on &&ut3_owner..ut_suite_cache_schema to public; grant execute on &&ut3_owner..ut_annotation_cache_manager to public; grant execute on &&ut3_owner..ut_annotation_parser to public; grant execute on &&ut3_owner..ut_annotation_objs_cache_info to public; grant execute on &&ut3_owner..ut_annotation_obj_cache_info to public; +grant execute on &&ut3_owner..ut_suite_items_info to public; +grant execute on &&ut3_owner..ut_suite_item_info to public; begin $if dbms_db_version.version = 12 and dbms_db_version.release >= 2 or dbms_db_version.version > 12 $then execute immediate 'grant select, insert, delete, update on &&ut3_owner..dbmspcc_blocks to public'; @@ -147,6 +154,8 @@ create public synonym ut_file_mapper for &&ut3_owner..ut_file_mapper; create public synonym ut_key_value_pairs for &&ut3_owner..ut_key_value_pairs; create public synonym ut_key_value_pair for &&ut3_owner..ut_key_value_pair; create public synonym ut_sonar_test_reporter for &&ut3_owner..ut_sonar_test_reporter; +create public synonym ut_suite_items_info for &&ut3_owner..ut_suite_items_info; +create public synonym ut_suite_item_info for &&ut3_owner..ut_suite_item_info; begin $if dbms_db_version.version = 12 and dbms_db_version.release >= 2 or dbms_db_version.version > 12 $then execute immediate 'create public synonym dbmspcc_blocks for &&ut3_owner..dbmspcc_blocks'; diff --git a/source/create_user_grants.sql b/source/create_user_grants.sql index 07d9097f3..0967a0e8c 100644 --- a/source/create_user_grants.sql +++ b/source/create_user_grants.sql @@ -106,6 +106,11 @@ grant execute on &&ut3_owner..ut_annotated_object to &ut3_user; grant execute on &&ut3_owner..ut_annotated_objects to &ut3_user; grant select on &&ut3_owner..ut_annotation_cache_info to &ut3_user; grant select on &&ut3_owner..ut_annotation_cache to &ut3_user; +grant execute on &&ut3_owner..ut_executables to &ut3_user; +grant execute on &&ut3_owner..ut_executable_test to &ut3_user; +grant select on &&ut3_owner..ut_suite_cache to &ut3_user; +grant select on &&ut3_owner..ut_suite_cache_package to public; +grant select on &&ut3_owner..ut_suite_cache_schema to &ut3_user; grant execute on &&ut3_owner..ut_annotation_cache_manager to &ut3_user; grant execute on &&ut3_owner..ut_annotation_parser to &ut3_user; grant execute on &&ut3_owner..ut_annotation_objs_cache_info to &ut3_user; diff --git a/source/install.sql b/source/install.sql index 902b45aba..50d70c944 100644 --- a/source/install.sql +++ b/source/install.sql @@ -109,6 +109,12 @@ alter session set current_schema = &&ut3_owner; @@install_component.sql 'core/annotations/ut_annotation_manager.pkb' --suite builder +@@install_component.sql 'core/ut_suite_cache_schema.sql' +@@install_component.sql 'core/ut_suite_cache_package.sql' +@@install_component.sql 'core/ut_suite_cache_seq.sql' +@@install_component.sql 'core/ut_suite_cache.sql' +@@install_component.sql 'core/ut_suite_cache_manager.pks' +@@install_component.sql 'core/ut_suite_cache_manager.pkb' @@install_component.sql 'core/ut_suite_builder.pks' @@install_component.sql 'core/ut_suite_builder.pkb' --suite manager @@ -253,6 +259,8 @@ prompt Installing DBMSPLSQL Tables objects into &&ut3_owner schema @@install_component.sql 'reporters/ut_documentation_reporter.tpb' --plugin interface API for running utPLSQL +@@install_component.sql 'api/ut_suite_item_info.tps' +@@install_component.sql 'api/ut_suite_items_info.tps' @@install_component.sql 'api/ut_runner.pks' @@install_component.sql 'api/ut_runner.pkb' diff --git a/source/reporters/ut_ansiconsole_helper.pkb b/source/reporters/ut_ansiconsole_helper.pkb index ceb0cf53f..07d9ee9a7 100644 --- a/source/reporters/ut_ansiconsole_helper.pkb +++ b/source/reporters/ut_ansiconsole_helper.pkb @@ -18,8 +18,6 @@ create or replace package body ut_ansiconsole_helper as gc_red constant varchar2(7) := chr(27) || '[31m'; gc_green constant varchar2(7) := chr(27) || '[32m'; gc_yellow constant varchar2(7) := chr(27) || '[33m'; - gc_blue constant varchar2(7) := chr(27) || '[34m'; - gc_magenta constant varchar2(7) := chr(27) || '[35m'; gc_cyan constant varchar2(7) := chr(27) || '[36m'; gc_reset constant varchar2(7) := chr(27) || '[0m'; g_enabled boolean := false; @@ -53,16 +51,6 @@ create or replace package body ut_ansiconsole_helper as return add_color(a_text, gc_yellow); end; - function blue(a_text varchar2) return varchar2 is - begin - return add_color(a_text, gc_blue); - end; - - function magenta(a_text varchar2) return varchar2 is - begin - return add_color(a_text, gc_magenta); - end; - function cyan(a_text varchar2) return varchar2 is begin return add_color(a_text, gc_cyan); diff --git a/source/reporters/ut_ansiconsole_helper.pks b/source/reporters/ut_ansiconsole_helper.pks index 29d746c7b..f34ff12bd 100644 --- a/source/reporters/ut_ansiconsole_helper.pks +++ b/source/reporters/ut_ansiconsole_helper.pks @@ -23,10 +23,6 @@ create or replace package ut_ansiconsole_helper as function yellow(a_text varchar2) return varchar2; - function blue(a_text varchar2) return varchar2; - - function magenta(a_text varchar2) return varchar2; - function cyan(a_text varchar2) return varchar2; end; / diff --git a/source/reporters/ut_coverage_cobertura_reporter.tpb b/source/reporters/ut_coverage_cobertura_reporter.tpb index 0d702dbbd..18221e3d9 100644 --- a/source/reporters/ut_coverage_cobertura_reporter.tpb +++ b/source/reporters/ut_coverage_cobertura_reporter.tpb @@ -39,8 +39,7 @@ create or replace type body ut_coverage_cobertura_reporter is l_line_no := a_unit_coverage.lines.first; if l_line_no is null then for i in 1 .. a_unit_coverage.total_lines loop - l_file_part := ''||chr(10); - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_clob(l_result, ''); end loop; else while l_line_no is not null loop @@ -68,71 +67,75 @@ create or replace type body ut_coverage_cobertura_reporter is function get_coverage_xml( a_coverage_data ut_coverage.t_coverage, a_run ut_run - ) return clob is + ) return ut_varchar2_rows is l_file_part varchar2(32767); - l_result clob; + l_result ut_varchar2_rows := ut_varchar2_rows(); l_unit ut_coverage.t_full_name; l_obj_name ut_coverage.t_object_name; - c_coverage_def constant varchar2(200) := ''||chr(10); - c_file_footer constant varchar2(30) := ''||chr(10); + c_coverage_def constant varchar2(200) := ''; + c_file_footer constant varchar2(30) := ''; c_coverage_footer constant varchar2(30) := ''; - c_sources_footer constant varchar2(30) := ''||chr(10); - c_packages_footer constant varchar2(30) := ''||chr(10); - c_package_footer constant varchar2(30) := ''||chr(10); - c_class_footer constant varchar2(30) := ''||chr(10); - c_lines_footer constant varchar2(30) := ''||chr(10); + c_sources_footer constant varchar2(30) := ''; + c_packages_footer constant varchar2(30) := ''; + c_package_footer constant varchar2(30) := ''; + c_class_footer constant varchar2(30) := ''; + c_lines_footer constant varchar2(30) := ''; l_epoch varchar2(50) := (sysdate - to_date('01-01-1970 00:00:00', 'dd-mm-yyyy hh24:mi:ss')) * 24 * 60 * 60; begin - dbms_lob.createtemporary(l_result,true); - - ut_utils.append_to_clob(l_result, ut_utils.get_xml_header(a_run.client_character_set)||chr(10)); - ut_utils.append_to_clob(l_result, c_coverage_def); + ut_utils.append_to_list( l_result, ut_utils.get_xml_header(a_run.client_character_set) ); + ut_utils.append_to_list( l_result, c_coverage_def ); --write header - l_file_part:= ''; - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list( + l_result, + '' + ); --Write sources l_unit := a_coverage_data.objects.first; - l_file_part := ''||CHR(10); - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list( l_result, '' ); while l_unit is not null loop - l_file_part := ''||dbms_xmlgen.convert(l_unit)||''||chr(10); - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list(l_result, ''||dbms_xmlgen.convert(l_unit)||''); l_unit := a_coverage_data.objects.next(l_unit); end loop; - ut_utils.append_to_clob(l_result, c_sources_footer); + ut_utils.append_to_list(l_result, c_sources_footer); --write packages l_unit := a_coverage_data.objects.first; - l_file_part := ''||CHR(10); - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list(l_result, ''); while l_unit is not null loop l_obj_name := a_coverage_data.objects(l_unit).name; - l_file_part := ''||CHR(10); - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list( + l_result, + '' + ); - l_file_part := ''||CHR(10); - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list( + l_result, + '' + ); - l_file_part := ''||CHR(10); - ut_utils.append_to_clob(l_result, l_file_part); - - dbms_lob.append(l_result,get_lines_xml(a_coverage_data.objects(l_unit))); + ut_utils.append_to_list(l_result, ''); + + ut_utils.append_to_list( l_result, get_lines_xml(a_coverage_data.objects(l_unit)) ); - ut_utils.append_to_clob(l_result, c_lines_footer); - ut_utils.append_to_clob(l_result, c_class_footer); - ut_utils.append_to_clob(l_result, c_package_footer); + ut_utils.append_to_list(l_result, c_lines_footer); + ut_utils.append_to_list(l_result, c_class_footer); + ut_utils.append_to_list(l_result, c_package_footer); l_unit := a_coverage_data.objects.next(l_unit); end loop; - ut_utils.append_to_clob(l_result, c_packages_footer); - ut_utils.append_to_clob(l_result, c_coverage_footer); + ut_utils.append_to_list(l_result, c_packages_footer); + ut_utils.append_to_list(l_result, c_coverage_footer); return l_result; end; begin @@ -140,7 +143,7 @@ create or replace type body ut_coverage_cobertura_reporter is l_coverage_data := ut_coverage.get_coverage_data(a_run.coverage_options); - self.print_clob( get_coverage_xml( l_coverage_data, a_run ) ); + self.print_text_lines( get_coverage_xml( l_coverage_data, a_run ) ); (self as ut_reporter_base).after_calling_run(a_run); end; diff --git a/source/reporters/ut_coverage_html_reporter.tpb b/source/reporters/ut_coverage_html_reporter.tpb index a6b5b4517..77d4b46ff 100644 --- a/source/reporters/ut_coverage_html_reporter.tpb +++ b/source/reporters/ut_coverage_html_reporter.tpb @@ -29,13 +29,12 @@ create or replace type body ut_coverage_html_reporter is end; overriding member procedure after_calling_run(self in out nocopy ut_coverage_html_reporter, a_run in ut_run) as - l_report_lines ut_varchar2_list; l_coverage_data ut_coverage.t_coverage; begin ut_coverage.coverage_stop(); l_coverage_data := ut_coverage.get_coverage_data(a_run.coverage_options); - self.print_clob( + self.print_text_lines( ut_coverage_report_html_helper.get_index( a_coverage_data => l_coverage_data, a_assets_path => self.assets_path, diff --git a/source/reporters/ut_coverage_report_html_helper.pkb b/source/reporters/ut_coverage_report_html_helper.pkb index 725a232f2..3ab0b1fb6 100644 --- a/source/reporters/ut_coverage_report_html_helper.pkb +++ b/source/reporters/ut_coverage_report_html_helper.pkb @@ -101,11 +101,12 @@ create or replace package body ut_coverage_report_html_helper is -function get_details_file_content(a_object_id varchar2, a_unit ut_object_name, a_unit_coverage ut_coverage.t_unit_coverage) - return clob is - l_source_code ut_varchar2_list; - l_result clob; - + function get_details_file_content( + a_object_id varchar2, + a_unit ut_object_name, + a_unit_coverage ut_coverage.t_unit_coverage + ) return ut_varchar2_rows is + function get_block_file_attributes(a_coverage_unit ut_coverage.t_unit_coverage) return varchar2 is l_result varchar2(32767); begin @@ -129,15 +130,14 @@ function get_details_file_content(a_object_id varchar2, a_unit ut_object_name, a end; function build_details_file_content(a_object_id varchar2, a_object_full_name varchar2, a_source_code ut_varchar2_list, a_coverage_unit ut_coverage.t_unit_coverage) - return clob is - l_file_part varchar2(32767); - l_result clob; - l_coverage_pct number(5, 2); + return ut_varchar2_rows is + l_file_part varchar2(32767); + l_result ut_varchar2_rows := ut_varchar2_rows(); + l_coverage_pct number(5, 2); l_coverage_block_pct number(5, 2); - l_hits varchar2(30); - l_blocks varchar2(30); + l_hits varchar2(30); + l_blocks varchar2(30); begin - dbms_lob.createtemporary(l_result, true); l_coverage_pct := coverage_pct(a_coverage_unit.covered_lines, a_coverage_unit.uncovered_lines); @@ -145,7 +145,7 @@ function get_details_file_content(a_object_id varchar2, a_unit ut_object_name, a dbms_xmlgen.convert(a_object_full_name) || '

' || l_coverage_pct || ' % lines covered

' ||get_common_file_attributes(a_coverage_unit) ||'
    '; - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list(l_result, l_file_part); for line_no in 1 .. a_source_code.count loop if not a_coverage_unit.lines.exists(line_no) then @@ -191,22 +191,20 @@ function get_details_file_content(a_object_id varchar2, a_unit ut_object_name, a ' || (dbms_xmlgen.convert(a_source_code(line_no))) || ''; end if; - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list(l_result, l_file_part); end loop; l_file_part := '
'; - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list(l_result, l_file_part); return l_result; end; begin - l_source_code := ut_coverage_helper.get_tmp_table_object_lines(a_unit.owner, a_unit.name); - dbms_lob.createtemporary(l_result, true); - l_result := build_details_file_content(a_object_id - ,a_unit.identity - ,l_source_code - ,a_unit_coverage - ); - return l_result; + return build_details_file_content( + a_object_id, + a_unit.identity, + ut_coverage_helper.get_tmp_table_object_lines(a_unit.owner, a_unit.name), + a_unit_coverage + ); end; function get_block_list_attributes(a_coverage_unit ut_coverage.t_coverage) return varchar2 is @@ -220,20 +218,18 @@ function get_details_file_content(a_object_id varchar2, a_unit ut_object_name, a return l_result; end; - function file_list(a_title varchar2, a_coverage ut_coverage.t_coverage) return clob is + function file_list(a_title varchar2, a_coverage ut_coverage.t_coverage) return ut_varchar2_rows is l_file_part varchar2(32767); l_title varchar2(100) := 'All files'; l_coverage_pct number(5, 2); l_coverage_block_pct number(5, 2); - l_result clob; + l_result ut_varchar2_rows; l_id varchar2(50) := object_id(a_title); l_unit_coverage ut_coverage.t_unit_coverage; l_unit ut_coverage.t_object_name; begin l_coverage_pct := coverage_pct(a_coverage.covered_lines, a_coverage.uncovered_lines); - dbms_lob.createtemporary(l_result, true); - l_file_part := '
' || '

' || l_title || '' || ' (' || l_coverage_pct || '%' || ' lines covered'|| @@ -251,7 +247,7 @@ function get_details_file_content(a_object_id varchar2, a_unit ut_object_name, a 'File% coveredLinesRelevant LinesLines coveredLines missed' ||'Avg. Hits / Line ' || ''; - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list( l_result, l_file_part ); l_unit := a_coverage.objects.first; loop exit when l_unit is null; @@ -266,11 +262,11 @@ function get_details_file_content(a_object_id varchar2, a_unit ut_object_name, a '' || to_char(executions_per_line(l_unit_coverage.executions ,l_unit_coverage.uncovered_lines + l_unit_coverage.covered_lines)) || ''; - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list( l_result, l_file_part ); l_unit := a_coverage.objects.next(l_unit); end loop; l_file_part := '

'; - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list( l_result, l_file_part ); return l_result; end; @@ -283,10 +279,10 @@ function get_details_file_content(a_object_id varchar2, a_unit ut_object_name, a a_project_name varchar2 := null, a_command_line varchar2 := null, a_charset varchar2 := null - ) return clob is + ) return ut_varchar2_rows is l_file_part varchar2(32767); - l_result clob; + l_result ut_varchar2_rows := ut_varchar2_rows(); l_title varchar2(250); l_coverage_pct number(5, 2); l_time_str varchar2(50); @@ -302,8 +298,6 @@ function get_details_file_content(a_object_id varchar2, a_unit ut_object_name, a when a_command_line is not null then '
using ' || dbms_xmlgen.convert(a_command_line) end; - dbms_lob.createtemporary(l_result, true); - l_title := case when a_project_name is null then 'Code coverage' @@ -323,32 +317,35 @@ function get_details_file_content(a_object_id varchar2, a_unit ut_object_name, a ''; - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list(l_result, l_file_part); return l_result; end; diff --git a/source/reporters/ut_coverage_report_html_helper.pks b/source/reporters/ut_coverage_report_html_helper.pks index d140588ad..bc4d025f3 100644 --- a/source/reporters/ut_coverage_report_html_helper.pks +++ b/source/reporters/ut_coverage_report_html_helper.pks @@ -37,7 +37,7 @@ create or replace package ut_coverage_report_html_helper authid current_user is a_project_name varchar2 := null, a_command_line varchar2 := null, a_charset varchar2 := null - ) return clob; + ) return ut_varchar2_rows; end; / diff --git a/source/reporters/ut_coverage_sonar_reporter.tpb b/source/reporters/ut_coverage_sonar_reporter.tpb index 249736f92..fcc213665 100644 --- a/source/reporters/ut_coverage_sonar_reporter.tpb +++ b/source/reporters/ut_coverage_sonar_reporter.tpb @@ -26,73 +26,72 @@ create or replace type body ut_coverage_sonar_reporter is overriding member procedure after_calling_run(self in out nocopy ut_coverage_sonar_reporter, a_run in ut_run) as - l_report_lines ut_varchar2_list; - l_coverage_data ut_coverage.t_coverage; - function get_lines_xml(a_unit_coverage ut_coverage.t_unit_coverage) return clob is + + function get_lines_xml(a_unit_coverage ut_coverage.t_unit_coverage) return ut_varchar2_rows is l_file_part varchar2(32767); - l_result clob; + l_result ut_varchar2_rows := ut_varchar2_rows(); l_line_no binary_integer; begin - dbms_lob.createtemporary(l_result, true); l_line_no := a_unit_coverage.lines.first; if l_line_no is null then for i in 1 .. a_unit_coverage.total_lines loop - l_file_part := ''||chr(10); - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list(l_result, ''); end loop; else while l_line_no is not null loop if a_unit_coverage.lines(l_line_no).executions = 0 then - l_file_part := ''||chr(10); + l_file_part := ''; else l_file_part := ''||chr(10); + l_file_part := l_file_part ||'/>'; end if; - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list(l_result, l_file_part); l_line_no := a_unit_coverage.lines.next(l_line_no); end loop; end if; return l_result; end; + function get_coverage_xml( a_coverage_data ut_coverage.t_coverage, a_run ut_run - ) return clob is - l_file_part varchar2(32767); - l_result clob; + ) return ut_varchar2_rows is + l_result ut_varchar2_rows := ut_varchar2_rows(); l_unit ut_coverage.t_full_name; - c_coverage_header constant varchar2(30) := ''||chr(10); - c_file_footer constant varchar2(30) := ''||chr(10); + c_coverage_header constant varchar2(30) := ''; + c_file_footer constant varchar2(30) := ''; c_coverage_footer constant varchar2(30) := ''; - begin - dbms_lob.createtemporary(l_result,true); + begin - ut_utils.append_to_clob(l_result, ut_utils.get_xml_header(a_run.client_character_set)||chr(10)); - ut_utils.append_to_clob(l_result, c_coverage_header); - l_unit := a_coverage_data.objects.first; - while l_unit is not null loop - l_file_part := ''||chr(10); - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list(l_result, ut_utils.get_xml_header(a_run.client_character_set)); + ut_utils.append_to_list(l_result, c_coverage_header); + l_unit := a_coverage_data.objects.first; + while l_unit is not null loop + ut_utils.append_to_list(l_result, ''); - dbms_lob.append(l_result,get_lines_xml(a_coverage_data.objects(l_unit))); + ut_utils.append_to_list(l_result,get_lines_xml(a_coverage_data.objects(l_unit))); - ut_utils.append_to_clob(l_result, c_file_footer); + ut_utils.append_to_list(l_result, c_file_footer); - l_unit := a_coverage_data.objects.next(l_unit); - end loop; - ut_utils.append_to_clob(l_result, c_coverage_footer); - return l_result; - end; + l_unit := a_coverage_data.objects.next(l_unit); + end loop; + ut_utils.append_to_list(l_result, c_coverage_footer); + return l_result; + end; + begin ut_coverage.coverage_stop(); - l_coverage_data := ut_coverage.get_coverage_data(a_run.coverage_options); - - self.print_clob( get_coverage_xml( l_coverage_data, a_run ) ); + self.print_text_lines( + get_coverage_xml( + ut_coverage.get_coverage_data(a_run.coverage_options), + a_run + ) + ); end; overriding member function get_description return varchar2 as diff --git a/source/reporters/ut_coveralls_reporter.tpb b/source/reporters/ut_coveralls_reporter.tpb index 3681147f3..46c0947d0 100644 --- a/source/reporters/ut_coveralls_reporter.tpb +++ b/source/reporters/ut_coveralls_reporter.tpb @@ -25,22 +25,19 @@ create or replace type body ut_coveralls_reporter is end; overriding member procedure after_calling_run(self in out nocopy ut_coveralls_reporter, a_run in ut_run) as - l_report_lines ut_varchar2_list; - l_coverage_data ut_coverage.t_coverage; - function get_lines_json(a_unit_coverage ut_coverage.t_unit_coverage) return clob is + function get_lines_json(a_unit_coverage ut_coverage.t_unit_coverage) return ut_varchar2_rows is l_file_part varchar2(32767); - l_result clob; + l_result ut_varchar2_rows := ut_varchar2_rows(); l_last_line_no binary_integer; c_coverage_header constant varchar2(30) := '"coverage": ['; c_null constant varchar2(4) := 'null'; begin - dbms_lob.createtemporary(l_result, true); - ut_utils.append_to_clob(l_result, c_coverage_header); + ut_utils.append_to_list(l_result, c_coverage_header); l_last_line_no := a_unit_coverage.lines.last; if l_last_line_no is null then - ut_utils.append_to_clob( + ut_utils.append_to_list( l_result , rpad( to_clob( '0' ), ( a_unit_coverage.total_lines * 3 ) - 2, ','||chr(10)||'0' ) ); @@ -54,48 +51,46 @@ create or replace type body ut_coveralls_reporter is if line_no < l_last_line_no then l_file_part := l_file_part ||','; end if; - ut_utils.append_to_clob(l_result, l_file_part||chr(10)); + ut_utils.append_to_list(l_result, l_file_part); end loop; end if; - ut_utils.append_to_clob(l_result, ']'); + ut_utils.append_to_list(l_result, ']'); return l_result; end; function get_coverage_json( a_coverage_data ut_coverage.t_coverage - ) return clob is - l_file_part varchar2(32767); - l_result clob; + ) return ut_varchar2_rows is + l_result ut_varchar2_rows := ut_varchar2_rows(); l_unit ut_coverage.t_full_name; - c_coverage_header constant varchar2(30) := '{"source_files":['||chr(10); - c_coverage_footer constant varchar2(30) := ']}'||chr(10)||chr(10)||chr(10)||chr(10)||' '; - begin - dbms_lob.createtemporary(l_result,true); - - ut_utils.append_to_clob(l_result, c_coverage_header); + c_coverage_header constant varchar2(30) := '{"source_files":['; + c_coverage_footer constant varchar2(30) := ']}'||chr(10)||' '; + begin + ut_utils.append_to_list(l_result, c_coverage_header); l_unit := a_coverage_data.objects.first; while l_unit is not null loop - l_file_part := '{ "name": "'||l_unit||'",'||chr(10); - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list(l_result, '{ "name": "'||l_unit||'",'); - dbms_lob.append(l_result,get_lines_json(a_coverage_data.objects(l_unit))); + ut_utils.append_to_list(l_result,get_lines_json(a_coverage_data.objects(l_unit))); - ut_utils.append_to_clob(l_result, '}'); + ut_utils.append_to_list(l_result, '}'); l_unit := a_coverage_data.objects.next(l_unit); if l_unit is not null then - ut_utils.append_to_clob(l_result, ','||chr(10)); + ut_utils.append_to_list(l_result, ','); end if; end loop; - ut_utils.append_to_clob(l_result, c_coverage_footer); + ut_utils.append_to_list(l_result, c_coverage_footer); return l_result; end; begin ut_coverage.coverage_stop(); - l_coverage_data := ut_coverage.get_coverage_data(a_run.coverage_options); - - self.print_clob( get_coverage_json( l_coverage_data ) ); + self.print_text_lines( + get_coverage_json( + ut_coverage.get_coverage_data(a_run.coverage_options) + ) + ); end; overriding member function get_description return varchar2 as diff --git a/source/reporters/ut_junit_reporter.tpb b/source/reporters/ut_junit_reporter.tpb index 63d256aab..bc88aa8af 100644 --- a/source/reporters/ut_junit_reporter.tpb +++ b/source/reporters/ut_junit_reporter.tpb @@ -35,48 +35,54 @@ create or replace type body ut_junit_reporter is end; procedure print_test_elements(a_test ut_test) is - l_lines ut_varchar2_list; + l_results ut_varchar2_rows := ut_varchar2_rows(); + l_lines ut_varchar2_list; l_output clob; begin - self.print_text(''); + ut_utils.append_to_list( + l_results, + '' + ); if a_test.result = ut_utils.gc_disabled then - self.print_text(''); + ut_utils.append_to_list( l_results, '' ); end if; if a_test.result = ut_utils.gc_error then - self.print_text(''); - self.print_text(c_cddata_tag_start); - self.print_clob(ut_utils.table_to_clob(a_test.get_error_stack_traces())); - self.print_text(c_cddata_tag_end); - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, c_cddata_tag_start); + ut_utils.append_to_list( l_results, ut_utils.convert_collection(a_test.get_error_stack_traces()) ); + ut_utils.append_to_list( l_results, c_cddata_tag_end); + ut_utils.append_to_list( l_results, ''); elsif a_test.result > ut_utils.gc_success then - self.print_text(''); + ut_utils.append_to_list( l_results, ''); for i in 1 .. a_test.failed_expectations.count loop l_lines := a_test.failed_expectations(i).get_result_lines(); for j in 1 .. l_lines.count loop - self.print_text(dbms_xmlgen.convert(l_lines(j))); + ut_utils.append_to_list( l_results, dbms_xmlgen.convert(l_lines(j)) ); end loop; - self.print_text(dbms_xmlgen.convert(a_test.failed_expectations(i).caller_info)); + ut_utils.append_to_list( l_results, dbms_xmlgen.convert(a_test.failed_expectations(i).caller_info) ); end loop; - self.print_text(''); + ut_utils.append_to_list( l_results, ''); end if; -- TODO - decide if we need/want to use the tag too l_output := a_test.get_serveroutputs(); if l_output is not null then - self.print_text(''); - self.print_text(c_cddata_tag_start); - self.print_clob(l_output); - self.print_text(c_cddata_tag_end); - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, c_cddata_tag_start); + ut_utils.append_to_list( l_results, l_output); + ut_utils.append_to_list( l_results, c_cddata_tag_end ); + ut_utils.append_to_list( l_results, '' ); else - self.print_text(''); + ut_utils.append_to_list( l_results, ''); end if; - self.print_text(''); - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ''); + + self.print_text_lines(l_results); end; procedure print_suite_elements(a_suite ut_logical_suite, a_suite_id in out nocopy integer) is @@ -84,6 +90,7 @@ create or replace type body ut_junit_reporter is a_suite.results_count.failure_count + a_suite.results_count.errored_count; l_suite ut_suite; l_tests ut_suite_items := ut_suite_items(); + l_results ut_varchar2_rows := ut_varchar2_rows(); l_data clob; l_errors ut_varchar2_list; begin @@ -111,28 +118,31 @@ create or replace type body ut_junit_reporter is l_data := l_suite.get_serveroutputs(); if l_data is not null and l_data != empty_clob() then - self.print_text(''); - self.print_text(c_cddata_tag_start); - self.print_clob(l_data); - self.print_text(c_cddata_tag_end); - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, c_cddata_tag_start); + ut_utils.append_to_list( l_results, l_data); + ut_utils.append_to_list( l_results, c_cddata_tag_end); + ut_utils.append_to_list( l_results, ''); else - self.print_text(''); + ut_utils.append_to_list( l_results, ''); end if; l_errors := l_suite.get_error_stack_traces(); if l_errors is not empty then - self.print_text(''); - self.print_text(c_cddata_tag_start); - self.print_clob(ut_utils.table_to_clob(l_errors)); - self.print_text(c_cddata_tag_end); - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, c_cddata_tag_start); + ut_utils.append_to_list( l_results, ut_utils.table_to_clob(l_errors)); + ut_utils.append_to_list( l_results, c_cddata_tag_end); + ut_utils.append_to_list( l_results, ''); else - self.print_text(''); + ut_utils.append_to_list( l_results, ''); end if; end if; - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + + self.print_text_lines(l_results); end; + begin l_suite_id := 0; self.print_text(ut_utils.get_xml_header(a_run.client_character_set)); diff --git a/source/reporters/ut_sonar_test_reporter.tpb b/source/reporters/ut_sonar_test_reporter.tpb index 913ae8b50..1da349d83 100644 --- a/source/reporters/ut_sonar_test_reporter.tpb +++ b/source/reporters/ut_sonar_test_reporter.tpb @@ -43,28 +43,31 @@ create or replace type body ut_sonar_test_reporter is end; procedure print_test_results(a_test ut_test) is - l_lines ut_varchar2_list; + l_results ut_varchar2_rows := ut_varchar2_rows(); + l_lines ut_varchar2_list; begin - self.print_text(''); + ut_utils.append_to_list( l_results, ''); if a_test.result = ut_utils.gc_disabled then - self.print_text(''); + ut_utils.append_to_list( l_results, ''); elsif a_test.result = ut_utils.gc_error then - self.print_text(''); - self.print_text(''); - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ''); elsif a_test.result > ut_utils.gc_success then - self.print_text(''); + ut_utils.append_to_list( l_results, ''); for i in 1 .. a_test.failed_expectations.count loop l_lines := a_test.failed_expectations(i).get_result_lines(); for i in 1 .. l_lines.count loop - self.print_text(dbms_xmlgen.convert(l_lines(i))); + ut_utils.append_to_list( l_results, dbms_xmlgen.convert(l_lines(i))); end loop; end loop; - self.print_text(''); + ut_utils.append_to_list( l_results, ''); end if; - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + + self.print_text_lines(l_results); end; procedure print_suite_results(a_suite ut_logical_suite, a_file_mappings ut_file_mappings) is diff --git a/source/reporters/ut_teamcity_reporter.tpb b/source/reporters/ut_teamcity_reporter.tpb index 086775254..d01e85153 100644 --- a/source/reporters/ut_teamcity_reporter.tpb +++ b/source/reporters/ut_teamcity_reporter.tpb @@ -57,68 +57,91 @@ create or replace type body ut_teamcity_reporter is end; overriding member procedure after_calling_test(self in out nocopy ut_teamcity_reporter, a_test in ut_test) is + l_results ut_varchar2_rows := ut_varchar2_rows(); l_test_full_name varchar2(4000); l_std_err_msg varchar2(32767); + function add_error_message( a_message varchar2, a_message_name varchar2) return varchar2 is + begin + return + case + when a_message is not null + then a_message_name || chr(10) || a_message || chr(10) + end; + end; + function add_error_messages(a_executables ut_executables, a_message_name varchar2) return varchar2 is + l_message varchar2(32767); + l_idx binary_integer; + begin + l_idx := a_executables.first; + while l_idx is not null loop + l_message := l_message || add_error_message(a_executables(l_idx).error_backtrace, a_message_name); + l_idx := a_executables.next(l_idx); + end loop; + return l_message; + end; begin l_test_full_name := lower(a_test.item.owner_name) || '.' || lower(a_test.item.object_name) || '.' || lower(a_test.item.procedure_name); if a_test.result = ut_utils.gc_disabled then - self.print_text(ut_teamcity_reporter_helper.test_disabled(l_test_full_name)); + ut_utils.append_to_list( l_results, ut_teamcity_reporter_helper.test_disabled(l_test_full_name)); else - self.print_clob(a_test.get_serveroutputs()); + ut_utils.append_to_list( l_results, a_test.get_serveroutputs()); if a_test.result = ut_utils.gc_error then - for i in 1 .. a_test.before_each_list.count loop - if a_test.before_each_list(i).error_backtrace is not null then - l_std_err_msg := l_std_err_msg || 'Before each exception:' || chr(10) || a_test.before_each_list(i).error_backtrace || chr(10); - end if; - end loop; - - for i in 1 .. a_test.before_test_list.count loop - if a_test.before_test_list(i).error_backtrace is not null then - l_std_err_msg := l_std_err_msg || 'Before test exception:' || chr(10) || a_test.before_test_list(i).error_backtrace || chr(10); - end if; - end loop; - - if a_test.item.error_backtrace is not null then - l_std_err_msg := l_std_err_msg || 'Test exception:' || chr(10) || a_test.item.error_backtrace || chr(10); - end if; - - for i in 1 .. a_test.after_test_list.count loop - if a_test.after_test_list(i).error_backtrace is not null then - l_std_err_msg := l_std_err_msg || 'After test exception:' || chr(10) || a_test.after_test_list(i).error_backtrace || chr(10); - end if; - end loop; - - for i in 1 .. a_test.after_each_list.count loop - if a_test.after_each_list(i).error_backtrace is not null then - l_std_err_msg := l_std_err_msg || 'After each exception:' || chr(10) || a_test.after_each_list(i).error_backtrace || chr(10); - end if; - end loop; - - self.print_text(ut_teamcity_reporter_helper.test_std_err(a_test_name => l_test_full_name - ,a_out => trim(l_std_err_msg))); - self.print_text(ut_teamcity_reporter_helper.test_failed(a_test_name => l_test_full_name - ,a_msg => 'Error occured' - ,a_details => trim(l_std_err_msg) || case when a_test.failed_expectations is not null and a_test.failed_expectations.count>0 then a_test.failed_expectations(1) - .message end)); + l_std_err_msg := l_std_err_msg || add_error_messages(a_test.before_each_list, 'Before each exception:'); + l_std_err_msg := l_std_err_msg || add_error_messages(a_test.before_test_list, 'Before test exception:'); + l_std_err_msg := l_std_err_msg || add_error_message(a_test.item.error_backtrace, 'Test exception:'); + l_std_err_msg := l_std_err_msg || add_error_messages(a_test.after_test_list, 'After test exception:'); + l_std_err_msg := l_std_err_msg || add_error_messages(a_test.after_each_list, 'After each exception:'); + + ut_utils.append_to_list( + l_results, + ut_teamcity_reporter_helper.test_std_err( + a_test_name => l_test_full_name, + a_out => trim(l_std_err_msg) + ) + ); + ut_utils.append_to_list( + l_results, + ut_teamcity_reporter_helper.test_failed( + a_test_name => l_test_full_name, + a_msg => 'Error occured', + a_details => + trim(l_std_err_msg) + || case when a_test.failed_expectations is not null + and a_test.failed_expectations.count>0 + then a_test.failed_expectations(1).message end + ) + ); elsif a_test.failed_expectations is not null and a_test.failed_expectations.count > 0 then -- Teamcity supports only a single failure message - self.print_text(ut_teamcity_reporter_helper.test_failed(a_test_name => l_test_full_name - ,a_msg => a_test.failed_expectations(a_test.failed_expectations.first).description - ,a_details => a_test.failed_expectations(a_test.failed_expectations.first).message )); + ut_utils.append_to_list( + l_results, + ut_teamcity_reporter_helper.test_failed( + a_test_name => l_test_full_name, + a_msg => a_test.failed_expectations(a_test.failed_expectations.first).description, + a_details => a_test.failed_expectations(a_test.failed_expectations.first).message ) + ); elsif a_test.result = ut_utils.gc_failure then - self.print_text(ut_teamcity_reporter_helper.test_failed(a_test_name => l_test_full_name - ,a_msg => 'Test failed')); + ut_utils.append_to_list( + l_results, + ut_teamcity_reporter_helper.test_failed( + a_test_name => l_test_full_name, + a_msg => 'Test failed' + ) + ); end if; - self.print_text(ut_teamcity_reporter_helper.test_finished(l_test_full_name, trunc(a_test.execution_time * 1e3))); + ut_utils.append_to_list( + l_results, + ut_teamcity_reporter_helper.test_finished(l_test_full_name, trunc(a_test.execution_time * 1e3)) + ); end if; - + self.print_text_lines(l_results); end; overriding member function get_description return varchar2 as diff --git a/source/reporters/ut_tfs_junit_reporter.tpb b/source/reporters/ut_tfs_junit_reporter.tpb index d3edd1208..5f3770b23 100644 --- a/source/reporters/ut_tfs_junit_reporter.tpb +++ b/source/reporters/ut_tfs_junit_reporter.tpb @@ -54,8 +54,8 @@ create or replace type body ut_tfs_junit_reporter is end; procedure print_test_results(a_test ut_test) is - l_lines ut_varchar2_list; - l_output clob; + l_results ut_varchar2_rows := ut_varchar2_rows(); + l_lines ut_varchar2_list; begin self.print_text(''); @@ -68,30 +68,33 @@ create or replace type body ut_tfs_junit_reporter is */ if a_test.result = ut_utils.gc_error then - self.print_text(''); - self.print_text(''); - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ''); -- Do not count error as failure elsif a_test.result = ut_utils.gc_failure then - self.print_text(''); + ut_utils.append_to_list( l_results, ''); for i in 1 .. a_test.failed_expectations.count loop l_lines := a_test.failed_expectations(i).get_result_lines(); for j in 1 .. l_lines.count loop - self.print_text(dbms_xmlgen.convert(l_lines(j))); + ut_utils.append_to_list( l_results, dbms_xmlgen.convert(l_lines(j))); end loop; - self.print_text(dbms_xmlgen.convert(a_test.failed_expectations(i).caller_info)); + ut_utils.append_to_list( l_results, dbms_xmlgen.convert(a_test.failed_expectations(i).caller_info)); end loop; - self.print_text(''); + ut_utils.append_to_list( l_results, ''); end if; - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + + self.print_text_lines(l_results); end; procedure print_suite_results(a_suite ut_logical_suite, a_suite_id in out nocopy integer) is l_tests_count integer := a_suite.results_count.disabled_count + a_suite.results_count.success_count + a_suite.results_count.failure_count + a_suite.results_count.errored_count; + l_results ut_varchar2_rows := ut_varchar2_rows(); l_suite ut_suite; l_outputs clob; l_errors ut_varchar2_list; @@ -116,26 +119,28 @@ create or replace type body ut_tfs_junit_reporter is l_suite := treat(a_suite as ut_suite); l_outputs := l_suite.get_serveroutputs(); if l_outputs is not null and l_outputs != empty_clob() then - self.print_text(''); - self.print_text(''); - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ''); else - self.print_text(''); + ut_utils.append_to_list( l_results, ''); end if; l_errors := l_suite.get_error_stack_traces(); if l_errors is not empty then - self.print_text(''); - self.print_text(''); - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ''); else - self.print_text(''); + ut_utils.append_to_list( l_results, ''); end if; - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + + self.print_text_lines(l_results); end if; end; diff --git a/source/uninstall_objects.sql b/source/uninstall_objects.sql index cf8b3905f..97f2c5a5d 100644 --- a/source/uninstall_objects.sql +++ b/source/uninstall_objects.sql @@ -51,10 +51,22 @@ drop package ut_teamcity_reporter_helper; drop package ut_runner; +drop type ut_suite_items_info force; + +drop type ut_suite_item_info force; + drop package ut_suite_manager; drop package ut_suite_builder; +drop table ut_suite_cache; + +drop sequence ut_suite_cache_seq; + +drop table ut_suite_cache_package; + +drop table ut_suite_cache_schema; + drop package ut; drop table ut_dbms_output_cache; diff --git a/test/api/test_ut_run.pkb b/test/api/test_ut_run.pkb index dae7e175a..c52551b33 100644 --- a/test/api/test_ut_run.pkb +++ b/test/api/test_ut_run.pkb @@ -355,6 +355,94 @@ create or replace package body test_ut_run is ut.expect( l_results ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); end; + procedure create_suite_with_commit is + pragma autonomous_transaction; + begin + execute immediate 'create or replace package test_commit_warning is + --%suite + --%suitepath(ut.run.transaction) + + --%test + procedure does_commit; + end;'; + execute immediate 'create or replace package body test_commit_warning is + procedure does_commit is + begin + ut3.ut.expect(1).to_equal(1); + commit; + end; + end;'; + end; + + procedure drop_suite_with_commit is + pragma autonomous_transaction; + begin + execute immediate 'drop package test_commit_warning'; + end; + + procedure run_proc_warn_on_commit is + l_results clob; + begin + ut3.ut.run('test_commit_warning'); + l_results := get_dbms_output_as_clob(); + ut.expect(l_results).to_be_like( + '%Unable to perform automatic rollback after test%'|| + 'An implicit or explicit commit/rollback occurred in procedures:%' || + 'does_commit%' || + 'Use the "--%rollback(manual)" annotation or remove commit/rollback/ddl statements that are causing the issue.%' + ); + end; + + procedure create_failing_beforeall_suite is + pragma autonomous_transaction; + begin + execute immediate 'create or replace package parent_suite is + --%suite + --%suitepath(ut.run.failing_setup) + + --%beforeall + procedure failing_setup; + end;'; + execute immediate 'create or replace package body parent_suite is + procedure failing_setup is + begin + raise no_data_found; + end; + end;'; + execute immediate 'create or replace package child_suite is + --%suite + --%suitepath(ut.run.failing_setup.parent_suite.some_sub_suite) + + --%test + procedure does_stuff; + end;'; + execute immediate 'create or replace package body child_suite is + procedure does_stuff is + begin + ut3.ut.expect(1).to_equal(1); + end; + end;'; + end; + + procedure drop_failing_beforeall_suite is + pragma autonomous_transaction; + begin + execute immediate 'drop package parent_suite'; + execute immediate 'drop package child_suite'; + end; + + procedure run_proc_fail_child_suites is + l_results clob; + begin + ut3.ut.run('child_suite'); + l_results := get_dbms_output_as_clob(); + ut.expect(l_results).to_be_like( + '%1) does_stuff%' || + 'ORA-01403: no data found%' || + 'ORA-06512: at "UT3_TESTER.PARENT_SUITE%' + ); + end; + procedure run_func_no_params is l_results ut3.ut_varchar2_list; begin @@ -391,7 +479,7 @@ create or replace package body test_ut_run is execute immediate 'begin :l_results := ut3$user#.test_package_1.run(:a_path); end;' using out l_results, in 'test_package_1'; --Assert - ut.expect( ut3.ut_utils.table_to_clob(l_results) ).to_be_like( '%test_package_bal%' ); + ut.expect( ut3.ut_utils.table_to_clob(l_results) ).to_be_like( '%test_package_1%' ); ut.expect( ut3.ut_utils.table_to_clob(l_results) ).not_to_be_like( '%test_package_2%' ); ut.expect( ut3.ut_utils.table_to_clob(l_results) ).not_to_be_like( '%test_package_3%' ); end; @@ -718,7 +806,45 @@ Failures:% begin execute immediate 'drop package invalid_pckag_that_revalidates'; execute immediate 'drop package parent_specs'; - end; - + end; + + procedure run_and_report_warnings is + l_results ut3.ut_varchar2_list; + l_actual clob; + begin + + select * bulk collect into l_results from table(ut3.ut.run('bad_annotations')); + l_actual := ut3.ut_utils.table_to_clob(l_results); + + ut.expect(l_actual).to_be_like('%Invalid annotation "--%context". Cannot find following "--%endcontext". Annotation ignored.% +%1 tests, 0 failed, 0 errored, 0 disabled, 1 warning(s)%'); + + end; + + procedure create_bad_annot is + pragma autonomous_transaction; + begin + execute immediate q'[ + create or replace package bad_annotations as + --%suite + + --%context + + --%test(invalidspecs) + procedure test1; + + end;]'; + + execute immediate q'[ + create or replace package body bad_annotations as + procedure test1 is begin ut.expect(1).to_equal(1); end; + end;]'; + + end; + procedure drop_bad_annot is + pragma autonomous_transaction; + begin + execute immediate 'drop package bad_annotations'; + end; end; / diff --git a/test/api/test_ut_run.pks b/test/api/test_ut_run.pks index cfc06c80d..2ed325b86 100644 --- a/test/api/test_ut_run.pks +++ b/test/api/test_ut_run.pks @@ -24,7 +24,6 @@ create or replace package test_ut_run is --%test(Runs all tests in current schema with coverage file list) procedure run_proc_cov_file_list; - --%disabled(TODO - currently it executes the package and all child packages) --%test(Runs given package only with package name given as path) procedure run_proc_pkg_name; --%test(Runs all from given package with package name given as path and coverage file list) @@ -42,6 +41,21 @@ create or replace package test_ut_run is --%test(Runs all tests in current schema with empty path list given) procedure run_proc_empty_path_list; + procedure create_suite_with_commit; + procedure drop_suite_with_commit; + --%test(Reports a warning if transaction was invalidated by test with automatic rollback) + --%beforetest(create_suite_with_commit) + --%aftertest(drop_suite_with_commit) + procedure run_proc_warn_on_commit; + + + procedure create_failing_beforeall_suite; + procedure drop_failing_beforeall_suite; + --%test(Marks child suite as failed when parent's suite beforeall fails) + --%beforetest(create_failing_beforeall_suite) + --%aftertest(drop_failing_beforeall_suite) + procedure run_proc_fail_child_suites; + --%endcontext @@ -57,7 +71,6 @@ create or replace package test_ut_run is --%test(Runs all tests in current schema with coverage file list) procedure run_func_cov_file_list; - --%disabled(TODO - currently it executes the package and all child packages) --%test(Runs given package only with package name given as path) procedure run_func_pkg_name; --%test(Runs all from given package with package name given as path and coverage file list) @@ -101,6 +114,12 @@ create or replace package test_ut_run is procedure generate_invalid_spec; procedure drop_invalid_spec; + --%test(Provides warnings on invalid annotations) + --%beforetest(create_bad_annot) + --%aftertest(drop_bad_annot) + procedure run_and_report_warnings; + procedure create_bad_annot; + procedure drop_bad_annot; --%endcontext end; diff --git a/test/api/test_ut_runner.pkb b/test/api/test_ut_runner.pkb index 3a8f6f670..96ae08a94 100644 --- a/test/api/test_ut_runner.pkb +++ b/test/api/test_ut_runner.pkb @@ -267,20 +267,24 @@ end;'; ut.expect(l_actual).to_equal(0); end; - procedure test_get_unit_test_info is + procedure test_get_suites_info is l_expected sys_refcursor; l_actual sys_refcursor; begin --Arrange open l_expected for - select 'UT3_TESTER' package_owner, 'DUMMY_TEST_PACKAGE' package_name, - to_char(null) procedure_name, 2 annotation_pos, 'suite' annotation_name, 'dummy_test_suite' annotation_text + select + 'UT3_TESTER' object_owner, 'DUMMY_TEST_PACKAGE' object_name, 'DUMMY_TEST_PACKAGE' item_name, + 'dummy_test_suite' item_description, 'UT_SUITE' item_type, 2 item_line_no, + 'dummy_test_package' path, 0 disabled_flag from dual union all - select 'UT3_TESTER', 'DUMMY_TEST_PACKAGE', to_char(null), 3, 'rollback', 'manual' from dual union all - select 'UT3_TESTER', 'DUMMY_TEST_PACKAGE', 'SOME_DUMMY_TEST_PROCEDURE', 5, 'test', 'dummy_test' from dual union all - select 'UT3_TESTER', 'DUMMY_TEST_PACKAGE', 'SOME_DUMMY_TEST_PROCEDURE', 6, 'beforetest', 'some_procedure' from dual; + select + 'UT3_TESTER' object_owner, 'DUMMY_TEST_PACKAGE' object_name, 'SOME_DUMMY_TEST_PROCEDURE' item_name, + 'dummy_test' item_description, 'UT_TEST' item_type, 5 item_line_no, + 'dummy_test_package.some_dummy_test_procedure' path, 0 disabled_flag + from dual; --Act - open l_actual for select * from table(ut3.ut_runner.get_unit_test_info('UT3_TESTER','DUMMY_TEST_PACKAGE')); + open l_actual for select * from table(ut3.ut_runner.get_suites_info(NULL,'DUMMY_TEST_PACKAGE')); --Assert ut.expect(l_actual).to_equal(l_expected); end; @@ -530,6 +534,59 @@ end;'; ut.expect(l_actual).to_be_like('%Finished in % seconds %2 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'); end; + + procedure is_test_true is + begin + ut.expect( + ut3.ut_runner.is_test( + a_owner => 'UT3_TESTER', + a_package_name => 'DUMMY_TEST_PACKAGE', + a_procedure_name => 'SOME_DUMMY_TEST_PROCEDURE' + ) + ).to_be_true(); + ut.expect( ut3.ut_runner.is_test( 'ut3_tester','dummy_test_package','some_dummy_test_procedure' ) ).to_be_true(); + end; + + procedure is_test_false is + begin + ut.expect( ut3.ut_runner.is_test( 'UT3_TESTER','DUMMY_TEST_PACKAGE', 'BAD' ) ).to_be_false(); + ut.expect( ut3.ut_runner.is_test( 'UT3_TESTER','DUMMY_TEST_PACKAGE', null ) ).to_be_false(); + ut.expect( ut3.ut_runner.is_test( 'UT3_TESTER',null,'some_dummy_test_procedure' ) ).to_be_false(); + ut.expect( ut3.ut_runner.is_test( null,'DUMMY_TEST_PACKAGE','some_dummy_test_procedure' ) ).to_be_false(); + end; + + procedure is_suite_true is + begin + ut.expect( + ut3.ut_runner.is_suite( + a_owner => 'UT3_TESTER', + a_package_name => 'DUMMY_TEST_PACKAGE' + ) + ).to_be_true(); + + ut.expect( ut3.ut_runner.is_suite( 'ut3_tester','dummy_test_package' ) ).to_be_true(); + end; + + procedure is_suite_false is + begin + ut.expect( ut3.ut_runner.is_suite( 'UT3_TESTER','BAD' ) ).to_be_false(); + ut.expect( ut3.ut_runner.is_suite( 'UT3_TESTER', null ) ).to_be_false(); + ut.expect( ut3.ut_runner.is_suite( null,'DUMMY_TEST_PACKAGE' ) ).to_be_false(); + end; + + procedure has_suites_true is + begin + ut.expect( ut3.ut_runner.has_suites( a_owner => 'UT3_TESTER' ) ).to_be_true(); + + ut.expect( ut3.ut_runner.has_suites( 'ut3_tester' ) ).to_be_true(); + end; + + procedure has_suites_false is + begin + ut.expect( ut3.ut_runner.has_suites( 'UT3_LATEST_RELEASE' ) ).to_be_false(); + ut.expect( ut3.ut_runner.has_suites( 'BAD' ) ).to_be_false(); + ut.expect( ut3.ut_runner.has_suites( null ) ).to_be_false(); + end; end; / diff --git a/test/api/test_ut_runner.pks b/test/api/test_ut_runner.pks index 74c93dbae..d67ee45fc 100644 --- a/test/api/test_ut_runner.pks +++ b/test/api/test_ut_runner.pks @@ -10,18 +10,22 @@ create or replace package test_ut_runner is --%test(closes open transactions if no transaction was open before run) procedure close_newly_opened_transaction; - --%test(version_compatibility_check compares major, minor and bugfix number) + --%context(version_compatibility_check) + + --%test(compares major, minor and bugfix number) procedure version_comp_check_compare; - --%test(version_compatibility_check ignores build number) + --%test(ignores build number) procedure version_comp_check_ignore; - --%test(version_compatibility_check compares short version to a full version) + --%test(compares short version to a full version) procedure version_comp_check_short; - --%test(version_compatibility_check raises exception when invalid version passed) + --%test(raises exception when invalid version passed) procedure version_comp_check_exception; + --%endcontext + --%test(run resets cache of package body after every run) procedure run_reset_package_body_cache; @@ -43,10 +47,10 @@ create or replace package test_ut_runner is --%aftertest(cleanup_cache) procedure test_rebuild_cache_schema_type; - --%test(get_unit_tests_info returns a cursor containing records for a newly created test) + --%test(get_suites_info returns a cursor containing records for a newly created test) --%beforetest(setup_cache_objects) --%aftertest(cleanup_cache) - procedure test_get_unit_test_info; + procedure test_get_suites_info; --%test(get_reporters_list returns a cursor containing all built-in reporters and information about output-reporter) --%beforetest(setup_cache_objects) @@ -91,5 +95,41 @@ create or replace package test_ut_runner is --%endcontext + --%context(is_test) + --%beforeall(setup_cache_objects) + --%afterall(cleanup_cache) + + --%test(Returns true when procedure is a test) + procedure is_test_true; + + --%test(Returns false when procedure is not a test) + procedure is_test_false; + + --%endcontext + + --%context(is_suite) + --%beforeall(setup_cache_objects) + --%afterall(cleanup_cache) + + --%test(Returns true when package is a test suite) + procedure is_suite_true; + + --%test(Returns false when package is not a test suite) + procedure is_suite_false; + + --%endcontext + + --%context(has_suites) + --%beforeall(setup_cache_objects) + --%afterall(cleanup_cache) + + --%test(Returns true when schema contains test suites) + procedure has_suites_true; + + --%test(Returns false when schema does not contain test suites) + procedure has_suites_false; + + --%endcontext + end; / diff --git a/test/core/annotations/test_annotation_manager.pkb b/test/core/annotations/test_annotation_manager.pkb index 98bea7452..1fb8115ba 100644 --- a/test/core/annotations/test_annotation_manager.pkb +++ b/test/core/annotations/test_annotation_manager.pkb @@ -31,6 +31,7 @@ create or replace package body test_annotation_manager is --%beforetest(some_procedure) procedure some_dummy_test_procedure; end;]'; + execute immediate q'[grant execute on dummy_test_package to public]'; end; procedure modify_dummy_test_package is @@ -56,6 +57,28 @@ create or replace package body test_annotation_manager is execute immediate q'[alter package dummy_test_package compile]'; end; + procedure create_parse_proc_as_ut3$user# is + pragma autonomous_transaction; + begin + execute immediate q'[ + create or replace procedure ut3$user#.parse_annotations is + begin + ut3.ut_annotation_manager.rebuild_annotation_cache('UT3_TESTER','PACKAGE'); + end;]'; + end; + + procedure parse_dummy_test_as_ut3$user# is + pragma autonomous_transaction; + begin + execute immediate 'begin ut3$user#.parse_annotations; end;'; + end; + + procedure drop_parse_proc_as_ut3$user# is + pragma autonomous_transaction; + begin + execute immediate 'drop procedure ut3$user#.parse_annotations'; + end; + procedure cleanup_annotation_cache is pragma autonomous_transaction; begin @@ -204,12 +227,11 @@ create or replace package body test_annotation_manager is l_expected sys_refcursor; l_start_date date; begin - --Arrange - ut3.ut_annotation_manager.rebuild_annotation_cache(user,'PACKAGE'); + parse_dummy_test_as_ut3$user#(); l_start_date := sysdate; drop_dummy_test_package(); --Act - ut3.ut_annotation_manager.rebuild_annotation_cache(user,'PACKAGE'); + parse_dummy_test_as_ut3$user#(); --Assert select max(cache_id) into l_actual_cache_id @@ -217,7 +239,7 @@ create or replace package body test_annotation_manager is where object_owner = user and object_type = 'PACKAGE' and object_name = 'DUMMY_TEST_PACKAGE' and parse_time >= l_start_date; - ut.expect(l_actual_cache_id).to_be_not_null; + ut.expect(l_actual_cache_id).not_to_be_null(); open l_actual for select annotation_position, annotation_name, annotation_text, subobject_name @@ -252,5 +274,29 @@ create or replace package body test_annotation_manager is ut.expect(l_actual).to_be_empty(); end; + procedure cleanup_dropped_data_in_cache is + l_cache_count integer; + l_actual sys_refcursor; + l_expected sys_refcursor; + l_start_date date; + begin + --Arrange + ut3.ut_annotation_manager.rebuild_annotation_cache(user,'PACKAGE'); + l_start_date := sysdate; + drop_dummy_test_package(); + --Act + ut3.ut_annotation_manager.rebuild_annotation_cache(user,'PACKAGE'); + --Assert + select count(1) + into l_cache_count + from ut3.ut_annotation_cache_info + where object_owner = user + and object_type = 'PACKAGE' + and object_name = 'DUMMY_TEST_PACKAGE'; + + ut.expect(l_cache_count).to_equal(0); + + end; + end test_annotation_manager; / diff --git a/test/core/annotations/test_annotation_manager.pks b/test/core/annotations/test_annotation_manager.pks index fb5e0299d..0726c8256 100644 --- a/test/core/annotations/test_annotation_manager.pks +++ b/test/core/annotations/test_annotation_manager.pks @@ -12,6 +12,10 @@ create or replace package test_annotation_manager is procedure create_dummy_test_package; + procedure create_parse_proc_as_ut3$user#; + + procedure drop_parse_proc_as_ut3$user#; + procedure drop_dummy_test_package; --%test(Adds new package to annotation cache info) @@ -34,13 +38,18 @@ create or replace package test_annotation_manager is --%aftertest(drop_dummy_test_package) procedure update_modified_test_package; - --%test(Keeps annotations in cache after object was removed) - --%beforetest(create_dummy_test_package) + --%test(Keeps annotations in cache when object was removed but user can't see whole schema) + --%beforetest(create_dummy_test_package,create_parse_proc_as_ut3$user#) + --%aftertest(drop_parse_proc_as_ut3$user#) procedure keep_dropped_data_in_cache; --%test(Does not return data for dropped object) --%beforetest(create_dummy_test_package) procedure no_data_for_dropped_object; + --%test(Remove object from cache when object dropped and user can see whole schema) + --%beforetest(create_dummy_test_package) + procedure cleanup_dropped_data_in_cache; + end test_annotation_manager; / diff --git a/test/core/expectations/test_expectations_cursor.pkb b/test/core/expectations/test_expectations_cursor.pkb index fb75b2da8..ac4fc9acf 100644 --- a/test/core/expectations/test_expectations_cursor.pkb +++ b/test/core/expectations/test_expectations_cursor.pkb @@ -1814,13 +1814,13 @@ Diff:% l_expected_message varchar2(32767); l_actual_message varchar2(32767); begin - select ut3.ut_annotated_object('TEST','TEST','TEST', + select ut3.ut_annotated_object('TEST','TEST','TEST', SYSDATE, ut3.ut_annotations(ut3.ut_annotation(1,'test','test','test'), ut3.ut_annotation(2,'test','test','test')) ) into l_actual_tab from dual; - select ut3.ut_annotated_object('TEST','TEST','TEST', + select ut3.ut_annotated_object('TEST','TEST','TEST', SYSDATE, ut3.ut_annotations(ut3.ut_annotation(1,'test','test','test'), ut3.ut_annotation(2,'test','test','test')) ) @@ -1846,13 +1846,13 @@ Diff:% l_expected_message varchar2(32767); l_actual_message varchar2(32767); begin - select ut3.ut_annotated_object('TEST','TEST','TEST', + select ut3.ut_annotated_object('TEST','TEST','TEST', SYSDATE, ut3.ut_annotations(ut3.ut_annotation(1,'test','test','test'), ut3.ut_annotation(2,'test','test','test')) ) into l_actual_tab from dual; - select ut3.ut_annotated_object('TEST','TEST','TEST', + select ut3.ut_annotated_object('TEST','TEST','TEST', SYSDATE, ut3.ut_annotations(ut3.ut_annotation(1,'test','test','test'), ut3.ut_annotation(2,'test','test','test')) ) @@ -1878,13 +1878,13 @@ Diff:% l_expected_message varchar2(32767); l_actual_message varchar2(32767); begin - select ut3.ut_annotated_object('TEST','TEST','TEST', + select ut3.ut_annotated_object('TEST','TEST','TEST', SYSDATE, ut3.ut_annotations(ut3.ut_annotation(1,'test','test','test'), ut3.ut_annotation(2,'test','test','test')) ) into l_actual_tab from dual; - select ut3.ut_annotated_object('TEST','TEST','TEST', + select ut3.ut_annotated_object('TEST','TEST','TEST', SYSDATE, ut3.ut_annotations(ut3.ut_annotation(1,'test','test','test'), ut3.ut_annotation(2,'test','test','test')) ) @@ -1909,15 +1909,16 @@ Diff:% l_expected_tab ut3.ut_annotated_object; l_expected_message varchar2(32767); l_actual_message varchar2(32767); + l_date date := sysdate; begin - select ut3.ut_annotated_object('TEST','TEST','TEST', + select ut3.ut_annotated_object('TEST','TEST','TEST', l_date, ut3.ut_annotations(ut3.ut_annotation(1,'test','test','test'), ut3.ut_annotation(2,'test','test','test')) ) into l_actual_tab from dual; - select ut3.ut_annotated_object('TEST','TEST','TEST', + select ut3.ut_annotated_object('TEST','TEST','TEST', l_date, ut3.ut_annotations(ut3.ut_annotation(1,'1test','test','test'), ut3.ut_annotation(2,'test','test','test')) ) @@ -1938,8 +1939,8 @@ Diff:% l_expected_message := q'[%Actual: refcursor [ count = 1 ] was expected to equal: refcursor [ count = 1 ] %Diff: %Rows: [ 1 differences ] -%PK TEST - Actual: TESTTESTTEST1testtesttest2testtesttest% -%PK TEST - Expected: TESTTESTTEST11testtesttest2testtesttest%]'; +%PK TEST - Actual: TESTTESTTEST%1testtesttest2testtesttest% +%PK TEST - Expected: TESTTESTTEST%11testtesttest2testtesttest%]'; l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; --Assert ut.expect(l_actual_message).to_be_like(l_expected_message); @@ -1954,13 +1955,13 @@ Diff:% l_expected_message varchar2(32767); l_actual_message varchar2(32767); begin - select ut3.ut_annotated_object('TEST','TEST','TEST', + select ut3.ut_annotated_object('TEST','TEST','TEST', SYSDATE, ut3.ut_annotations(ut3.ut_annotation(1,'1test','test','test'), ut3.ut_annotation(2,'test','test','test')) ) into l_actual_tab from dual; - select ut3.ut_annotated_object('TEST','TEST','TEST', + select ut3.ut_annotated_object('TEST','TEST','TEST', SYSDATE, ut3.ut_annotations(ut3.ut_annotation(1,'test','test','test'), ut3.ut_annotation(2,'test','test','test')) ) diff --git a/test/core/reporters/test_coverage/test_cov_cobertura_reporter.pkb b/test/core/reporters/test_coverage/test_cov_cobertura_reporter.pkb index e89fbd283..cabf64e90 100644 --- a/test/core/reporters/test_coverage/test_cov_cobertura_reporter.pkb +++ b/test/core/reporters/test_coverage/test_cov_cobertura_reporter.pkb @@ -7,9 +7,10 @@ create or replace package body test_cov_cobertura_reporter is begin --Arrange l_expected := - ' + q'[ - + + test/ut3.dummy_coverage.pkb @@ -23,7 +24,7 @@ create or replace package body test_cov_cobertura_reporter is
-
'; +
]'; --Act select * bulk collect into l_results diff --git a/test/core/reporters/test_coverage/test_coveralls_reporter.pkb b/test/core/reporters/test_coverage/test_coveralls_reporter.pkb index 3b6b88346..774e796a0 100644 --- a/test/core/reporters/test_coverage/test_coveralls_reporter.pkb +++ b/test/core/reporters/test_coverage/test_coveralls_reporter.pkb @@ -8,14 +8,17 @@ create or replace package body test_coveralls_reporter is --Arrange l_expected := q'[{"source_files":[ { "name": "test/ut3.dummy_coverage.pkb", -"coverage": [null, +"coverage": [ +null, null, null, 1, 0, null, 1 -]}]} +] +} +]} ]'; --Act select * @@ -42,7 +45,8 @@ null, --Arrange l_expected := q'[{"source_files":[ { "name": "ut3.dummy_coverage", -"coverage": [0, +"coverage": [ +0, 0, 0, 0, @@ -51,7 +55,10 @@ null, 0, 0, 0, -0]}]} +0 +] +} +]} ]'; test_coverage.cleanup_dummy_coverage; diff --git a/test/core/test_suite_builder.pkb b/test/core/test_suite_builder.pkb index 19ea81aa0..bd76e88d8 100644 --- a/test/core/test_suite_builder.pkb +++ b/test/core/test_suite_builder.pkb @@ -4,17 +4,24 @@ create or replace package body test_suite_builder is a_annotations ut3.ut_annotations, a_package_name varchar2 := 'TEST_SUITE_BUILDER_PACKAGE' ) return clob is - l_suites ut3.ut_suite_builder.tt_schema_suites; + l_suites ut3.ut_suite_items; l_suite ut3.ut_logical_suite; l_cursor sys_refcursor; l_xml xmltype; begin open l_cursor for select value(x) from table( ut3.ut_annotated_objects( - ut3.ut_annotated_object('UT3_TESTER', a_package_name, 'PACKAGE', a_annotations) + ut3.ut_annotated_object('UT3_TESTER', a_package_name, 'PACKAGE', systimestamp, a_annotations) ) ) x; - l_suites := ut3.ut_suite_builder.build_suites(l_cursor).schema_suites; - l_suite := l_suites(l_suites.first); + + l_suites := ut3.ut_suite_manager.build_suites_from_annotations( + a_owner_name => 'UT3_TESTER', + a_annotated_objects => l_cursor, + a_path => null, + a_object_name => a_package_name, + a_skip_all_objects => true + ); + l_suite := treat( l_suites(l_suites.first) as ut3.ut_logical_suite); select deletexml( xmltype(l_suite), @@ -389,7 +396,7 @@ create or replace package body test_suite_builder is ut3.ut_annotation(1, 'suite','Cool', null), ut3.ut_annotation(2, 'beforeall',null, 'first_before_all'), ut3.ut_annotation(3, 'beforeall',null, 'another_before_all'), - ut3.ut_annotation(4, 'beforeeach',null, 'first_bfore_each'), + ut3.ut_annotation(4, 'beforeeach',null, 'first_before_each'), ut3.ut_annotation(5, 'beforeeach',null, 'another_before_each'), ut3.ut_annotation(6, 'aftereach',null, 'first_after_each'), ut3.ut_annotation(7, 'aftereach',null, 'another_after_each'), @@ -407,7 +414,7 @@ create or replace package body test_suite_builder is ut.expect(l_actual).to_be_like( '%%some_package%some_test' || '%' || - '%some_packagefirst_bfore_each' || + '%some_packagefirst_before_each' || '%some_packageanother_before_each' || '%' || '%' || @@ -843,6 +850,61 @@ create or replace package body test_suite_builder is ); end; + --%test(Gives warning when two contexts have the same name) + procedure duplicate_context_name is + l_actual clob; + l_annotations ut3.ut_annotations; + begin + --Arrange + l_annotations := ut3.ut_annotations( + ut3.ut_annotation(1, 'suite','Cool', null), + ut3.ut_annotation(2, 'beforeall',null, 'suite_level_beforeall'), + ut3.ut_annotation(3, 'test','In suite', 'suite_level_test'), + ut3.ut_annotation(4, 'context','a_context', null), + ut3.ut_annotation(5, 'displayname','A context', null), + ut3.ut_annotation(6, 'beforeall',null, 'context_setup'), + ut3.ut_annotation(7, 'test', 'In context', 'test_in_a_context'), + ut3.ut_annotation(8, 'endcontext',null, null), + ut3.ut_annotation(9, 'context','a_context', null), + ut3.ut_annotation(10, 'displayname','A context', null), + ut3.ut_annotation(11, 'beforeall',null, 'setup_in_duplicated_context'), + ut3.ut_annotation(12, 'test', 'In duplicated context', 'test_in_duplicated_context'), + ut3.ut_annotation(13, 'endcontext',null, null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%Context name must be unique in a suite. Context and all of it's content ignored.%at "UT3_TESTER.SOME_PACKAGE", line 9%' + ,'\' + ); + ut.expect(l_actual).to_be_like( + '' || + '%' || + '' || + '%a_contextA contextsome_package.a_context' || + '%' || + '' || + '%test_in_a_contextIn contextsome_package.a_context.test_in_a_context' || + '%' || + '' || + '' || + '%some_packagecontext_setup' || + '%' || + '' || + '' || + '' || + '%suite_level_testIn suitesome_package.suite_level_test' || + '%' || + '' || + '' || + '%some_packagesuite_level_beforeall' || + '%' || + '' || + '' + ); + end; + procedure throws_value_empty is l_actual clob; l_annotations ut3.ut_annotations; diff --git a/test/core/test_suite_builder.pks b/test/core/test_suite_builder.pks index 36517432b..21ca58206 100644 --- a/test/core/test_suite_builder.pks +++ b/test/core/test_suite_builder.pks @@ -39,6 +39,9 @@ create or replace package test_suite_builder is --%test(Gives warning if more than one --%test annotation used) procedure test_annot_duplicated; + --%test(Is added to suite according to annotation order in package spec) + procedure test_annotation_ordering; + --%endcontext --%context(suitepath) @@ -125,6 +128,9 @@ create or replace package test_suite_builder is --%test(Gives warning if --%endcontext is missing a preceding --%context) procedure endcontext_without_context; + --%test(Gives warning when two contexts have the same name and ignores duplicated context) + procedure duplicate_context_name; + --%endcontext --%context(throws) @@ -155,14 +161,6 @@ create or replace package test_suite_builder is --%endcontext - --%context(test) - --%displayname(--%test annontation) - - --%test(Is added to suite according to annotation order in package spec) - procedure test_annotation_ordering; - - --%endcontext - --%context(unknown_annotation) --%displayname(--%bad_annotation) diff --git a/test/core/test_suite_manager.pkb b/test/core/test_suite_manager.pkb index 59f1f42ea..5d7e91f3d 100644 --- a/test/core/test_suite_manager.pkb +++ b/test/core/test_suite_manager.pkb @@ -313,7 +313,7 @@ end test_package_with_ctx;]'; ut.expect(l_test1_suite.name).to_equal('test_package_1'); ut.expect(l_test1_suite.items.count).to_equal(3); ut.expect(l_test1_suite.rollback_type).to_equal(ut3.ut_utils.gc_rollback_manual); - l_test2_suite := treat(l_test1_suite.items(3) as ut3.ut_logical_suite); + l_test2_suite := treat(l_test1_suite.items(1) as ut3.ut_logical_suite); ut.expect(l_test2_suite.name).to_equal('test_package_2'); ut.expect(l_test2_suite.items.count).to_equal(3); @@ -515,7 +515,6 @@ end test_package_with_ctx;]'; l_test0_suite ut3.ut_logical_suite; l_test1_suite ut3.ut_suite; - l_test2_suite ut3.ut_suite; begin --Act l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(c_path)); @@ -529,7 +528,7 @@ end test_package_with_ctx;]'; l_test1_suite := treat(l_test0_suite.items(1) as ut3.ut_suite); ut.expect(l_test1_suite.name).to_equal('test_package_1'); - ut.expect(l_test1_suite.items.count).to_equal(3); + ut.expect(l_test1_suite.items.count).to_equal(2); ut.expect(l_test1_suite.items(1).name).to_equal('test1'); ut.expect(l_test1_suite.items(1).description).to_equal('Test1 from test package 1'); @@ -545,12 +544,6 @@ end test_package_with_ctx;]'; ut.expect(treat(l_test1_suite.items(2) as ut3.ut_test).before_each_list.count).to_be_greater_than(0); ut.expect(treat(l_test1_suite.items(2) as ut3.ut_test).disabled_flag).to_equal(0); - -- temporary behavior. - -- decided that when executed by package, not path, only that package has to execute - l_test2_suite := treat(l_test1_suite.items(3) as ut3.ut_suite); - - ut.expect(l_test2_suite.name).to_equal('test_package_2'); - ut.expect(l_test2_suite.items.count).to_equal(3); end; procedure test_top_pack_by_name_cu is @@ -573,7 +566,7 @@ end test_package_with_ctx;]'; l_test1_suite := treat(l_test0_suite.items(1) as ut3.ut_suite); ut.expect(l_test1_suite.name).to_equal('test_package_1'); - ut.expect(l_test1_suite.items.count).to_equal(3); + ut.expect(l_test1_suite.items.count).to_equal(2); ut.expect(l_test1_suite.items(1).name).to_equal('test1'); ut.expect(l_test1_suite.items(1).description).to_equal('Test1 from test package 1'); @@ -589,12 +582,6 @@ end test_package_with_ctx;]'; ut.expect(treat(l_test1_suite.items(2) as ut3.ut_test).before_each_list.count).to_be_greater_than(0); ut.expect(treat(l_test1_suite.items(2) as ut3.ut_test).disabled_flag).to_equal(0); - -- temporary behavior. - -- decided that when executed by package, not path, only that package has to execute - l_test2_suite := treat(l_test1_suite.items(3) as ut3.ut_suite); - - ut.expect(l_test2_suite.name).to_equal('test_package_2'); - ut.expect(l_test2_suite.items.count).to_equal(3); end; procedure test_top_pack_by_path is @@ -618,7 +605,7 @@ end test_package_with_ctx;]'; ut.expect(l_test1_suite.name).to_equal('test_package_1'); ut.expect(l_test1_suite.items.count).to_equal(3); - l_test2_suite := treat(l_test1_suite.items(3) as ut3.ut_logical_suite); + l_test2_suite := treat(l_test1_suite.items(1) as ut3.ut_logical_suite); ut.expect(l_test2_suite.name).to_equal('test_package_2'); ut.expect(l_test2_suite.items.count).to_equal(3); @@ -645,7 +632,7 @@ end test_package_with_ctx;]'; ut.expect(l_test1_suite.name).to_equal('test_package_1'); ut.expect(l_test1_suite.items.count).to_equal(3); - l_test2_suite := treat(l_test1_suite.items(3) as ut3.ut_logical_suite); + l_test2_suite := treat(l_test1_suite.items(1) as ut3.ut_logical_suite); ut.expect(l_test2_suite.name).to_equal('test_package_2'); ut.expect(l_test2_suite.items.count).to_equal(3); @@ -942,7 +929,7 @@ end;]'; l_objects_to_run ut3.ut_suite_items; begin l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list('ut3.failing_non_existing')); - ut.fail('Non existing package didnt raised exception'); + ut.fail('Non existing package did not raise exception'); exception when others then ut.expect(sqlerrm).to_be_like('%failing_non_existing%'); @@ -952,7 +939,7 @@ end;]'; l_objects_to_run ut3.ut_suite_items; begin l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list('failing_non_existing')); - ut.fail('Non existing package without schema didnt raised exception'); + ut.fail('Non existing package without schema did not raise exception'); exception when others then ut.expect(sqlerrm).to_be_like('%ORA-44001: invalid schema%'); @@ -979,10 +966,10 @@ end;]'; ut.expect(l_test.name).to_equal('test1'); ut.expect(l_test.description).to_equal('A test description, though with comma, is assigned by suite_manager'); - l_test := treat(l_suite.items(2) as ut3.ut_test); - - ut.expect(l_test.name).to_equal('test2'); - ut.expect(l_test.description).to_equal('A test description, though with comma, is assigned by suite_manager'); +-- l_test := treat(l_suite.items(2) as ut3.ut_test); +-- +-- ut.expect(l_test.name).to_equal('test2'); +-- ut.expect(l_test.description).to_equal('A test description, though with comma, is assigned by suite_manager'); end; procedure setup_desc_with_comma is @@ -1029,7 +1016,7 @@ end;'; ut.fail('Cache not invalidated on package drop'); exception when others then - ut.expect(sqlerrm).to_be_like('%tst_package_to_be_dropped%not found%'); + ut.expect(sqlerrm).to_be_like('%tst_package_to_be_dropped%does not exist%'); end; end; diff --git a/test/core/test_ut_executable.pkb b/test/core/test_ut_executable.pkb index 2d4cde518..d09a25a6d 100644 --- a/test/core/test_ut_executable.pkb +++ b/test/core/test_ut_executable.pkb @@ -8,7 +8,7 @@ create or replace package body test_ut_executable is l_result boolean; begin --Arrange - l_test := ut3.ut_test(a_object_name => 'test_ut_executable',a_name => 'test_ut_executable'); + l_test := ut3.ut_test(a_object_name => 'test_ut_executable',a_name => 'test_ut_executable', a_line_no=> 1); l_executable := ut3.ut_executable_test( null, 'test_ut_executable', 'passing_proc', ut3.ut_utils.gc_test_execute ); --Act l_result := l_executable.do_execute(l_test); @@ -24,7 +24,7 @@ create or replace package body test_ut_executable is l_result boolean; begin --Arrange - l_test := ut3.ut_test(a_object_name => 'test_ut_executable',a_name => 'test_ut_executable'); + l_test := ut3.ut_test(a_object_name => 'test_ut_executable',a_name => 'test_ut_executable', a_line_no=> 1); l_executable := ut3.ut_executable_test( user, 'test_ut_executable', 'output_proc', ut3.ut_utils.gc_test_execute ); --Act l_result := l_executable.do_execute(l_test); @@ -40,7 +40,7 @@ create or replace package body test_ut_executable is l_result boolean; begin --Arrange - l_test := ut3.ut_test(a_object_name => 'test_ut_executable',a_name => 'test_ut_executable'); + l_test := ut3.ut_test(a_object_name => 'test_ut_executable',a_name => 'test_ut_executable', a_line_no=> 1); l_executable := ut3.ut_executable_test( user, 'test_ut_executable', 'throwing_proc', ut3.ut_utils.gc_test_execute ); --Act l_result := l_executable.do_execute(l_test); @@ -80,10 +80,10 @@ create or replace package body test_ut_executable is procedure form_name is begin - ut.expect(ut3.ut_executable_test( user, 'package', 'proc', null ).form_name()).to_equal(user||'.package.proc'); - ut.expect(ut3.ut_executable_test( null, 'package', 'proc', null ).form_name()).to_equal('package.proc'); + ut.expect(ut3.ut_executable_test( user, ' package ', 'proc', null ).form_name()).to_equal(user||'.package.proc'); + ut.expect(ut3.ut_executable_test( null, 'package', ' proc ', null ).form_name()).to_equal('package.proc'); ut.expect(ut3.ut_executable_test( null, 'proc', null, null ).form_name()).to_equal('proc'); - ut.expect(ut3.ut_executable_test( user, 'proc', null, null ).form_name()).to_equal(user||'.proc'); + ut.expect(ut3.ut_executable_test( ' '||user||' ', 'proc', null, null ).form_name()).to_equal(user||'.proc'); end; procedure passing_proc is diff --git a/test/core/test_ut_suite.pkb b/test/core/test_ut_suite.pkb index c66e25af3..557d3cb7b 100644 --- a/test/core/test_ut_suite.pkb +++ b/test/core/test_ut_suite.pkb @@ -9,13 +9,15 @@ create or replace package body test_ut_suite is l_suite ut3.ut_suite; begin --Arrange - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS', a_line_no=> 1); l_suite.path := 'ut_example_tests'; l_suite.disabled_flag := ut3.ut_utils.boolean_to_int(true); l_suite.before_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'set_g_number_0', ut3.ut_utils.gc_before_all)); l_suite.after_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'add_1_to_g_number', ut3.ut_utils.gc_before_all)); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number')); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number')); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); --Act l_suite.do_execute(); --Assert @@ -32,10 +34,11 @@ create or replace package body test_ut_suite is l_suite ut3.ut_suite; begin --Arrange - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS', a_line_no=> 1); l_suite.path := 'ut_example_tests'; l_suite.before_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'failing_procedure', ut3.ut_utils.gc_before_all)); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'set_g_number_0')); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'set_g_number_0', a_line_no=> 1); --Act l_suite.do_execute(); --Assert @@ -52,12 +55,14 @@ create or replace package body test_ut_suite is l_suite ut3.ut_suite; begin --Arrange - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS', a_line_no=> 1); l_suite.path := 'ut_example_tests'; l_suite.after_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'failing_procedure', ut3.ut_utils.gc_after_all)); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'set_g_number_0')); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number')); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'set_g_number_0', a_line_no=> 1); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); --Act l_suite.do_execute(); --Assert @@ -73,9 +78,10 @@ create or replace package body test_ut_suite is procedure package_without_body is l_suite ut3.ut_suite; begin - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_WITHOUT_BODY'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_WITHOUT_BODY', a_line_no=> 1); l_suite.path := 'UT_WITHOUT_BODY'; - l_suite.add_item(ut3.ut_test(a_object_name => 'ut_without_body',a_name => 'test1'/*, a_rollback_type => ut3.ut_utils.gc_rollback_auto*/)); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'ut_without_body',a_name => 'test1', a_line_no=> 1); --Act l_suite.do_execute(); --Assert @@ -85,9 +91,10 @@ create or replace package body test_ut_suite is procedure package_with_invalid_body is l_suite ut3.ut_suite; begin - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_WITH_INVALID_BODY'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_WITH_INVALID_BODY', a_line_no=> 1); l_suite.path := 'UT_WITH_INVALID_BODY'; - l_suite.add_item(ut3.ut_test(a_object_name => 'ut_with_invalid_body',a_name => 'test1'/*, a_rollback_type => ut3.ut_utils.gc_rollback_auto*/)); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'ut_with_invalid_body',a_name => 'test1', a_line_no=> 1); --Act l_suite.do_execute(); --Assert @@ -99,10 +106,11 @@ create or replace package body test_ut_suite is begin --Arrange execute immediate 'delete from ut$test_table'; - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_TRANSACTION_CONTROL'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_TRANSACTION_CONTROL', a_line_no=> 1); l_suite.path := 'ut_transaction_control'; l_suite.before_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_TRANSACTION_CONTROL', 'setup', ut3.ut_utils.gc_before_all)); - l_suite.add_item(ut3.ut_test(a_object_owner => USER, a_object_name => 'ut_transaction_control',a_name => a_procedure_name)); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_owner => USER, a_object_name => 'ut_transaction_control',a_name => a_procedure_name, a_line_no=> 1); l_suite.set_rollback_type(a_rollback_type); --Act diff --git a/test/core/test_ut_test.pkb b/test/core/test_ut_test.pkb index ecce27c3c..b521d6841 100644 --- a/test/core/test_ut_test.pkb +++ b/test/core/test_ut_test.pkb @@ -10,12 +10,14 @@ create or replace package body test_ut_test is l_test ut3.ut_test; begin --Arrange - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS', a_line_no=> 1); l_suite.path := 'ut_example_tests'; l_suite.before_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'set_g_number_0', ut3.ut_utils.gc_before_all)); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number')); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number')); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 2); l_suite.items(l_suite.items.last).disabled_flag := ut3.ut_utils.boolean_to_int(true); --Act l_suite.do_execute(); @@ -34,15 +36,17 @@ create or replace package body test_ut_test is l_test ut3.ut_test; begin --Arrange - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS', a_line_no=> 1); l_suite.path := 'ut_example_tests'; l_suite.before_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'set_g_number_0', ut3.ut_utils.gc_before_all)); - l_test := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number'); + l_test := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); l_test.before_test_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'add_1_to_g_number', ut3.ut_utils.gc_before_test)); l_test.after_test_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'failing_procedure', ut3.ut_utils.gc_after_test)); - l_suite.add_item(l_test); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number')); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := l_test; + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); --Act l_suite.do_execute(); --Assert @@ -60,13 +64,15 @@ create or replace package body test_ut_test is l_test ut3.ut_test; begin --Arrange - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS', a_line_no=> 1); l_suite.before_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'set_g_number_0', ut3.ut_utils.gc_before_all)); - l_test := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number'); + l_test := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); l_test.before_each_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'add_1_to_g_number', ut3.ut_utils.gc_before_each)); l_test.after_each_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'failing_procedure', ut3.ut_utils.gc_after_each)); - l_suite.add_item(l_test); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number')); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := l_test; + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); --Act l_suite.do_execute(); --Assert @@ -84,13 +90,15 @@ create or replace package body test_ut_test is l_test ut3.ut_test; begin --Arrange - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS', a_line_no=> 1); l_suite.before_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'set_g_number_0', ut3.ut_utils.gc_before_all)); - l_test := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number'); + l_test := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); l_test.before_test_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'failing_procedure', ut3.ut_utils.gc_before_test)); l_test.after_test_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'add_1_to_g_number', ut3.ut_utils.gc_after_test)); - l_suite.add_item(l_test); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number')); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := l_test; + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); --Act l_suite.do_execute(); --Assert @@ -108,13 +116,15 @@ create or replace package body test_ut_test is l_test ut3.ut_test; begin --Arrange - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS', a_line_no=> 1); l_suite.before_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'set_g_number_0', ut3.ut_utils.gc_before_all)); - l_test := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number'); + l_test := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); l_test.before_each_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'failing_procedure', ut3.ut_utils.gc_before_each)); l_test.after_each_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'add_1_to_g_number', ut3.ut_utils.gc_after_each)); - l_suite.add_item(l_test); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number')); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := l_test; + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); --Act l_suite.do_execute(); --Assert @@ -127,5 +137,561 @@ create or replace package body test_ut_test is ut.expect(l_suite.results_count.errored_count).to_equal(1); end; + procedure after_each_executed is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.after_each_list := ut3.ut_executables(ut3.ut_executable(user, 'ut_example_tests', 'add_1_to_g_number', ut3.ut_utils.gc_after_each)); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_success); + ut.expect(ut_example_tests.g_number).to_equal(1); + end; + + procedure after_each_proc_name_invalid is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.after_each_list := ut3.ut_executables( + ut3.ut_executable(user, 'ut_example_tests', 'invalid setup name', ut3.ut_utils.gc_after_each) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + ut.expect(ut_example_tests.g_number).to_equal(0); + end; + + procedure after_each_procedure_name_null is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.after_each_list := ut3.ut_executables( + ut3.ut_executable(user, 'ut_example_tests', null, ut3.ut_utils.gc_after_each) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + ut.expect(ut_example_tests.g_number).to_equal(0); + end; + + procedure create_app_info_package is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package ut_output_tests + as + --%suite + + gv_before_all_client_info varchar2(200); + gv_before_each_client_info varchar2(200); + gv_before_test_client_info varchar2(200); + gv_after_test_client_info varchar2(200); + gv_after_each_client_info varchar2(200); + gv_after_all_client_info varchar2(200); + + --%test + --%beforetest(before_test) + --%aftertest(after_test) + procedure the_test; + + --%beforeall + procedure beforeall; + + --%beforeeach + procedure beforeeach; + + procedure before_test; + procedure after_test; + + --%aftereach + procedure aftereach; + + --%afterall + procedure afterall; + + end;]'; + execute immediate q'[create or replace package body ut_output_tests + as + + procedure the_test + as + l_module_name varchar2(4000); + l_action_name varchar2(4000); + l_client_info varchar2(4000); + begin + --Generate empty output + dbms_output.put_line(''); + ut.expect(1,'Test 1 Should Pass').to_equal(1); + dbms_application_info.read_module(module_name => l_module_name, action_name => l_action_name); + dbms_application_info.read_client_info(l_client_info); + ut.expect(l_module_name).to_equal('utPLSQL'); + ut.expect(l_action_name).to_be_like('ut_output_tests'); + ut.expect(l_client_info).to_be_like('the_test'); + end; + + procedure beforeall is + begin + dbms_application_info.read_client_info(gv_before_all_client_info); + end; + + procedure beforeeach is + begin + dbms_application_info.read_client_info(gv_before_each_client_info); + end; + + procedure before_test is + begin + dbms_application_info.read_client_info(gv_before_test_client_info); + end; + procedure after_test is + begin + dbms_application_info.read_client_info(gv_after_test_client_info); + end; + + procedure aftereach is + begin + dbms_application_info.read_client_info(gv_after_each_client_info); + end; + + procedure afterall is + begin + dbms_application_info.read_client_info(gv_after_all_client_info); + end; + + end;]'; + end; + + procedure drop_app_info_package is + pragma autonomous_transaction; + begin + execute immediate q'[drop package ut_output_tests]'; + end; + + procedure application_info_on_execution is + l_output_data ut3.ut_varchar2_list; + l_output clob; + function get_test_value(a_variable_name varchar2) return varchar2 is + l_result varchar2(4000); + begin + execute immediate 'begin :i := ut_output_tests.'||a_variable_name||'; end;' using out l_result; + return l_result; + end; + begin + --act + select * bulk collect into l_output_data + from table(ut3.ut.run('ut_output_tests')); + l_output := ut3.ut_utils.table_to_clob(l_output_data); + --assert + + ut.expect(get_test_value('gv_before_all_client_info')).to_equal('beforeall'); + ut.expect(get_test_value('gv_before_each_client_info')).to_equal('beforeeach'); + ut.expect(get_test_value('gv_before_test_client_info')).to_equal('before_test'); + ut.expect(get_test_value('gv_after_test_client_info')).to_equal('after_test'); + ut.expect(get_test_value('gv_after_each_client_info')).to_equal('aftereach'); + ut.expect(get_test_value('gv_after_all_client_info')).to_equal('afterall'); + ut.expect(l_output).to_be_like('%0 failed, 0 errored, 0 disabled, 0 warning(s)%'); + end; + + procedure before_each_executed is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'add_1_to_g_number', + a_line_no => null + ); + begin + l_test.before_each_list := ut3.ut_executables(ut3.ut_executable(user, 'ut_example_tests', 'set_g_number_0', ut3.ut_utils.gc_before_each)); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_success); + ut.expect(ut_example_tests.g_number).to_equal(1); + end; + + + procedure before_each_proc_name_invalid is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.before_each_list := ut3.ut_executables( + ut3.ut_executable(user, 'ut_example_tests', 'invalid setup name', ut3.ut_utils.gc_before_each) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + ut.expect(ut_example_tests.g_number).to_be_null; + end; + + procedure before_each_proc_name_null is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.before_each_list := ut3.ut_executables( + ut3.ut_executable(user, 'ut_example_tests', null, ut3.ut_utils.gc_before_each) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + ut.expect(ut_example_tests.g_number).to_be_null; + end; + + procedure ignore_savepoint_exception is + pragma autonomous_transaction; + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'ut_commit_test', + a_line_no => null + ); + begin + l_test.rollback_type := ut3.ut_utils.gc_rollback_auto; + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_success); + end; + + procedure owner_name_invalid is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_owner => 'invalid owner name', + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + end; + + procedure owner_name_null is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_owner => null, + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_success); + ut.expect(ut_example_tests.g_number).to_equal(0); + end; + + + procedure create_invalid_package is + pragma autonomous_transaction; + begin + execute immediate 'create or replace package invalid_package is + v_variable non_existing_type; + procedure ut_exampletest; + end;'; + exception when others then + null; + end; + + procedure drop_invalid_package is + pragma autonomous_transaction; + begin + execute immediate 'drop package invalid_package'; + exception when others then + null; + end; + + procedure package_in_invalid_state is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'invalid_package', + a_name => 'ut_exampletest', + a_line_no => null + ); + begin + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + end; + + procedure package_name_invalid is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'invalid package name', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + end; + + procedure package_name_null is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => null, + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + end; + + procedure procedure_name_invalid is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'invalid procedure name', + a_line_no => null + ); + begin + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + end; + + procedure procedure_name_null is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => null, + a_line_no => null + ); + begin + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + end; + + procedure before_test_executed is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'add_1_to_g_number', + a_line_no => null + ); + begin + l_test.before_test_list := ut3.ut_executables(ut3.ut_executable(user, 'ut_example_tests', 'set_g_number_0', ut3.ut_utils.gc_before_test)); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_success); + ut.expect(ut_example_tests.g_number).to_equal(1); + end; + + procedure before_test_proc_name_invalid is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.before_test_list := ut3.ut_executables( + ut3.ut_executable(user, 'ut_example_tests', 'invalid setup name', ut3.ut_utils.gc_before_test) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + ut.expect(ut_example_tests.g_number).to_be_null; + end; + + procedure before_test_proc_name_null is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.before_test_list := ut3.ut_executables( + ut3.ut_executable(user, 'ut_example_tests', null, ut3.ut_utils.gc_before_test) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + ut.expect(ut_example_tests.g_number).to_be_null; + end; + + procedure after_test_executed is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.after_test_list := ut3.ut_executables(ut3.ut_executable(user, 'ut_example_tests', 'add_1_to_g_number', ut3.ut_utils.gc_after_test)); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_success); + ut.expect(ut_example_tests.g_number).to_equal(1); + end; + + procedure after_test_proce_name_invalid is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.after_test_list := ut3.ut_executables( + ut3.ut_executable(user, 'ut_example_tests', 'invalid procedure name', ut3.ut_utils.gc_after_test) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + ut.expect(ut_example_tests.g_number).to_equal(0); + end; + + procedure after_test_proc_name_null is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.after_test_list := ut3.ut_executables( + ut3.ut_executable(user, 'ut_example_tests', null, ut3.ut_utils.gc_after_test) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + ut.expect(ut_example_tests.g_number).to_equal(0); + end; + + procedure create_output_package is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package ut_output_tests + as + --%suite + + --%beforeeach + procedure beforeeach; + + --%aftereach + procedure aftereach; + + --%test + --%beforetest(beforetest) + --%aftertest(aftertest) + procedure ut_passing_test; + + procedure beforetest; + + procedure aftertest; + + --%beforeall + procedure beforeall; + --%afterall + procedure afterall; + + end;]'; + execute immediate q'[create or replace package body ut_output_tests + as + + procedure beforetest is + begin + dbms_output.put_line(''); + end; + + procedure aftertest is + begin + dbms_output.put_line(''); + end; + + procedure beforeeach is + begin + dbms_output.put_line(''); + end; + + procedure aftereach is + begin + dbms_output.put_line(''); + end; + + procedure ut_passing_test is + begin + dbms_output.put_line(''); + ut.expect(1,'Test 1 Should Pass').to_equal(1); + end; + + procedure beforeall is + begin + dbms_output.put_line(''); + end; + + procedure afterall is + begin + dbms_output.put_line(''); + end; + + end;]'; + exception when others then + null; + end; + + procedure drop_output_package is + pragma autonomous_transaction; + begin + execute immediate 'drop package ut_output_tests'; + exception when others then + null; + end; + + procedure test_output_gathering is + l_output_data ut3.ut_varchar2_list; + l_output clob; + begin + select * bulk collect into l_output_data + from table(ut3.ut.run('ut_output_tests')); + l_output := ut3.ut_utils.table_to_clob(l_output_data); + ut.expect(l_output).to_be_like( + '%%%%%%%%1 tests, 0 failed, 0 errored%' + ); + end; + + end; / diff --git a/test/core/test_ut_test.pks b/test/core/test_ut_test.pks index de6107326..ee888ecd3 100644 --- a/test/core/test_ut_test.pks +++ b/test/core/test_ut_test.pks @@ -22,5 +22,73 @@ create or replace package test_ut_test is procedure beforeeach_errors; + --%context(executables in test) + + --%test(Executes aftereach procedure) + procedure after_each_executed; + + --%test(Fails test when aftereach procedure name invalid) + procedure after_each_proc_name_invalid; + --%test(Tails test when aftereach procedure name null) + procedure after_each_procedure_name_null; + + procedure create_app_info_package; + procedure drop_app_info_package; + --%beforetest(create_app_info_package) + --%aftertest(drop_app_info_package) + --%test(Sets application_info on execution of individual items) + procedure application_info_on_execution; + + --%test(Executes beforeeach procedure) + procedure before_each_executed; + --%test(Fails test when beforeeach procedure name invalid) + procedure before_each_proc_name_invalid; + --%test(Fails test when beforeeach procedure name null) + procedure before_each_proc_name_null; + --%test(Does not raise exception when rollback to savepoint fails) + procedure ignore_savepoint_exception; + --%test(Fails when owner name invalid) + procedure owner_name_invalid; + --%test(Runs test as current schema when owner name null) + procedure owner_name_null; + + procedure create_invalid_package; + procedure drop_invalid_package; + --%beforetest(create_app_info_package) + --%aftertest(drop_app_info_package) + --%test(Fails the test that references package with compilation errors) + procedure package_in_invalid_state; + --%test(Fails the test when package name is invalid) + procedure package_name_invalid; + --%test(Fails the test when package name is null) + procedure package_name_null; + --%test(Fails the test when procedure name invalid) + procedure procedure_name_invalid; + --%test(Fails the test when procedure name null) + procedure procedure_name_null; + + + --%test(Executes befroretest procedure) + procedure before_test_executed; + --%test(Fails test when befroretest procedure name invalid) + procedure before_test_proc_name_invalid; + --%test(Fails test when befroretest procedure name is null) + procedure before_test_proc_name_null; + --%test(Executes aftertest procedure) + procedure after_test_executed; + --%test(Fails test when aftertest procedure name invalid) + procedure after_test_proce_name_invalid; + --%test(Fails test when aftertest procedure name is null) + procedure after_test_proc_name_null; + + procedure create_output_package; + procedure drop_output_package; + --%beforetest(create_output_package) + --%aftertest(drop_output_package) + --%test(Test output gathering) + procedure test_output_gathering; + + --%endcontext + end; / diff --git a/test/helpers/ut_example_tests.pkb b/test/helpers/ut_example_tests.pkb index 5059103b6..d8afd592a 100644 --- a/test/helpers/ut_example_tests.pkb +++ b/test/helpers/ut_example_tests.pkb @@ -16,5 +16,9 @@ as g_number := 1 / 0; end; + procedure ut_commit_test is + begin + commit; + end; end; / diff --git a/test/helpers/ut_example_tests.pks b/test/helpers/ut_example_tests.pks index 7ff75ce12..428d55743 100644 --- a/test/helpers/ut_example_tests.pks +++ b/test/helpers/ut_example_tests.pks @@ -1,8 +1,8 @@ -create or replace package ut_example_tests -as - g_number number; - procedure set_g_number_0; - procedure add_1_to_g_number; - procedure failing_procedure; +create or replace package ut_example_tests as + g_number number; + procedure set_g_number_0; + procedure add_1_to_g_number; + procedure failing_procedure; + procedure ut_commit_test; end; /