diff --git a/.gitattributes b/.gitattributes index 02d2d5e4e..2cda5ad55 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,11 +1,18 @@ +.github export-ignore +.idea export-ignore +development export-ignore +test export-ignore .gitattributes export-ignore .gitignore export-ignore .gitmodules export-ignore -.travis.yml export-ignore mkdocs.yml export-ignore -.travis export-ignore +BUILD_NO export-ignore +mkdocs_offline.yml export-ignore sonar-project.properties export-ignore -tests export-ignore -development export-ignore -node_modules export-ignore -^docs/* linguist-documentation +^docs/** linguist-documentation +*.pkb linguist-language=PLSQL +*.pks linguist-language=PLSQL +*.sql linguist-language=PLSQL +*.tpb linguist-language=PLSQL +*.tps linguist-language=PLSQL +*.sh text eol=lf diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..b3e52a19a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,50 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**Provide version info** +Information about utPLSQL and Database version, +```sql +set serveroutput on +declare + l_version varchar2(255); + l_compatibility varchar2(255); +begin + dbms_utility.db_version( l_version, l_compatibility ); + dbms_output.put_line( l_version ); + dbms_output.put_line( l_compatibility ); +end; +/ +select substr(ut.version(),1,60) as ut_version from dual; +select * from v$version; +select * from nls_session_parameters; +select substr(dbms_utility.port_string,1,60) as port_string from dual; +``` + +**Information about client software** +What client was used to run utPLSQL tests? Was it from TOAD, SQLDeveloper, SQLPlus, PLSQL Developer etc... + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Example code** +If applicable, add sample code to help explain your problem. +Please avoid putting your company private/protected code in an issue, as it might violate your company's privacy and security policies. + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..681bc7f3a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,26 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. + +**Note** +> Please do not create issues for generic SQL or PL/SQL questions. There are other forums and communities to help you with those. See [ASKTom](https://asktom.oracle.com) for example. + +**Want to discuss** +If you want to discuss your issue, join [our SLACK chat](https://join.slack.com/t/utplsql/shared_invite/zt-xwm68udy-4cF_3PNEyczYEbWr38W5ww). diff --git a/.github/scripts/create_test_users.sh b/.github/scripts/create_test_users.sh new file mode 100755 index 000000000..fe43b7467 --- /dev/null +++ b/.github/scripts/create_test_users.sh @@ -0,0 +1,115 @@ +#!/bin/bash + +set -ev +SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +cd ${SCRIPT_DIR}/../../source + +time "$SQLCLI" sys/$ORACLE_PWD@//$CONNECTION_STR AS SYSDBA <<-SQL +set feedback off +whenever sqlerror exit failure rollback + +-------------------------------------------------------------------------------- +PROMPT Adding back create-trigger privilege to $UT3_DEVELOP_SCHEMA for testing +grant administer database trigger to $UT3_DEVELOP_SCHEMA; + +-------------------------------------------------------------------------------- +PROMPT Creating UT3_TESTER - Power-user for testing internal framework code + +create user UT3_TESTER identified by "ut3" default tablespace $UT3_TABLESPACE quota unlimited on $UT3_TABLESPACE; +grant create session, create procedure, create type, create table to UT3_TESTER; + +grant execute on dbms_lock to UT3_TESTER; + +PROMPT Granting $UT3_DEVELOP_SCHEMA code to UT3_TESTER + +begin + for i in ( + select object_name from all_objects t + where t.object_type in ('PACKAGE','TYPE') + and owner = '$UT3_DEVELOP_SCHEMA' + and generated = 'N' + and object_name not like 'SYS%') + loop + execute immediate 'grant execute on $UT3_DEVELOP_SCHEMA."'||i.object_name||'" to UT3_TESTER'; + end loop; +end; +/ + +PROMPT Granting $UT3_DEVELOP_SCHEMA tables to UT3_TESTER + +begin + for i in ( select table_name from all_tables t where owner = '$UT3_DEVELOP_SCHEMA' and nested = 'NO' and iot_name is null) + loop + execute immediate 'grant select on $UT3_DEVELOP_SCHEMA.'||i.table_name||' to UT3_TESTER'; + end loop; +end; +/ + + +-------------------------------------------------------------------------------- +PROMPT Creating UT3_USER - minimal privileges user for API testing + +create user UT3_USER identified by "ut3" default tablespace $UT3_TABLESPACE quota unlimited on $UT3_TABLESPACE; +grant create session, create procedure, create type, create table to UT3_USER; + +PROMPT Grants for starting a debugging session from UT3_USER +grant debug connect session to UT3_USER; +grant debug any procedure to UT3_USER; +begin + \$if dbms_db_version.version <= 11 \$then + null; -- no addition action necessary + \$else + -- necessary on 12c or higher + dbms_network_acl_admin.append_host_ace ( + host =>'*', + ace => sys.xs\$ace_type( + privilege_list => sys.xs\$name_list('JDWP') , + principal_name => 'UT3_USER', + principal_type => sys.xs_acl.ptype_db + ) + ); + \$end +end; +/ + +-------------------------------------------------------------------------------- +PROMPT Creating UT3_TESTER_HELPER - provides functions to allow min grant test user setup tests. + +create user UT3_TESTER_HELPER identified by "ut3" default tablespace $UT3_TABLESPACE quota unlimited on $UT3_TABLESPACE; +grant create session, create procedure, create type, create table to UT3_TESTER_HELPER; + +PROMPT Grants for testing distributed transactions +grant create public database link to UT3_TESTER_HELPER; +grant drop public database link to UT3_TESTER_HELPER; + +PROMPT Grants for testing coverage outside of main $UT3_DEVELOP_SCHEMA schema. +grant create any procedure, drop any procedure, execute any procedure, create any type, drop any type, execute any type, under any type, + select any table, update any table, insert any table, delete any table, create any table, drop any table, alter any table, + select any dictionary, create any synonym, drop any synonym, + grant any object privilege, grant any privilege, create public synonym, drop public synonym, create any trigger + to UT3_TESTER_HELPER; + +grant create job to UT3_TESTER_HELPER; + +PROMPT Additional grants for disabling DDL trigger and testing parser without trigger enabled/present + +grant alter any trigger to UT3_TESTER_HELPER; +grant administer database trigger to UT3_TESTER_HELPER; +grant execute on dbms_lock to UT3_TESTER_HELPER; + +create user ut3_cache_test_owner identified by ut3; +grant create session, create procedure to ut3_cache_test_owner; + +create user ut3_no_extra_priv_user identified by ut3; +grant create session, create procedure to ut3_no_extra_priv_user; + +create user ut3_select_catalog_user identified by ut3; +grant create session, create procedure, select_catalog_role to ut3_select_catalog_user; + +create user ut3_select_any_table_user identified by ut3; +grant create session, create procedure, select any table to ut3_select_any_table_user; + +create user ut3_execute_any_proc_user identified by ut3; +grant create session, create procedure, execute any procedure to ut3_execute_any_proc_user; +exit +SQL diff --git a/.github/scripts/get_project_version.sh b/.github/scripts/get_project_version.sh new file mode 100755 index 000000000..54a30a562 --- /dev/null +++ b/.github/scripts/get_project_version.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +version=`cat VERSION` +#When on develop branch, add "-develop" to the version text +if [[ "${CI_ACTION_REF_NAME}" == "develop" ]]; then + version=`sed -E "s/(v?[0-9]+\.[0-9]+\.[0-9]+).*/\1-develop/" <<< "${version}"` +fi +echo ${version} diff --git a/.github/scripts/install.sh b/.github/scripts/install.sh new file mode 100755 index 000000000..46750b89c --- /dev/null +++ b/.github/scripts/install.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +set -ev +SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +cd ${SCRIPT_DIR}/../../source + +INSTALL_FILE="install_headless_with_trigger.sql" +if [[ ! -f "${INSTALL_FILE}" ]]; then + INSTALL_FILE="install_headless.sql" +fi + +#install core of utplsql +time "$SQLCLI" sys/$ORACLE_PWD@//$CONNECTION_STR AS SYSDBA <<-SQL +whenever sqlerror exit failure rollback +set feedback off +set verify off + +--alter session set plsql_warnings = 'ENABLE:ALL', 'DISABLE:(5004,5018,6000,6001,6003,6009,6010,7206)'; +alter session set plsql_optimize_level=0; +@${INSTALL_FILE} $UT3_DEVELOP_SCHEMA $UT3_DEVELOP_SCHEMA_PASSWORD +SQL diff --git a/.travis/install_utplsql_release.sh b/.github/scripts/install_utplsql_release.sh old mode 100644 new mode 100755 similarity index 64% rename from .travis/install_utplsql_release.sh rename to .github/scripts/install_utplsql_release.sh index 889e098da..e50718c7b --- a/.travis/install_utplsql_release.sh +++ b/.github/scripts/install_utplsql_release.sh @@ -1,8 +1,8 @@ #!/bin/bash set -ev - -cd $UTPLSQL_DIR/source +SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +cd ${SCRIPT_DIR}/../../${UTPLSQL_DIR}/source "$SQLCLI" sys/$ORACLE_PWD@//$CONNECTION_STR AS SYSDBA <>index.md + echo "layout: default" >>index.md + echo "---" >>index.md + echo "" >>index.md + echo "# Documentation versions" >>index.md + echo "" >>index.md + echo "" >>index.md #- 7th line - placeholder for latest release doc + echo "" >>index.md #- 8th line - placeholder for develop branch doc + echo "" >>index.md + echo "## Released Version Doc History" >>index.md + echo "" >>index.md +fi +#If build running on a TAG - it's a new release - need to add it to documentation +if [ "${GITHUB_REF_TYPE}" == "tag" ]; then + sed -i '7s@.*@'" - [Latest ${CI_ACTION_REF_NAME} documentation](latest/) - Created $now"'@' index.md + #add entry to the top of version history (line end of file - ## Released Version Doc History + sed -i '12i'" - [${CI_ACTION_REF_NAME} documentation](${UTPLSQL_VERSION}/) - Created $now" index.md +fi +#replace 4th line in log +sed -i '8s@.*@'" - [Latest development version](develop/) - Created $now"'@' index.md +#Add and Commit the changes back to pages repo. +git add . +git commit -m "Deploy to gh-pages branch: base commit ${SHA}" +# Now that we're all set up, we can push. +git push --quiet origin HEAD:${GITHUB_IO_BRANCH} + diff --git a/.github/scripts/run_examples.sh b/.github/scripts/run_examples.sh new file mode 100755 index 000000000..bfa4f7e1a --- /dev/null +++ b/.github/scripts/run_examples.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -ev +SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +cd ${SCRIPT_DIR}/../../examples + +"$SQLCLI" $UT3_DEVELOP_SCHEMA/$UT3_DEVELOP_SCHEMA_PASSWORD@//$CONNECTION_STR <> $GITHUB_ENV +echo "UTPLSQL_VERSION=${version}" >> $GITHUB_ENV +echo UTPLSQL_BUILD_VERSION=$(echo ${version} | sed -E "s/(v?[0-9]+\.)([0-9]+\.)([0-9]+)(-.*)?/\1\2\3\.${build_no}\4/") >> $GITHUB_ENV + diff --git a/.github/scripts/set_version_numbers_env.sh b/.github/scripts/set_version_numbers_env.sh new file mode 100755 index 000000000..c61639bf9 --- /dev/null +++ b/.github/scripts/set_version_numbers_env.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +build_no=$( expr ${GITHUB_RUN_NUMBER} + ${UTPLSQL_BUILD_NO_OFFSET} ) +version=$(.github/scripts/get_project_version.sh) + +echo "UTPLSQL_BUILD_NO=${build_no}" >> $GITHUB_ENV +echo "UTPLSQL_VERSION=${version}" >> $GITHUB_ENV +echo UTPLSQL_BUILD_VERSION=$(echo ${version} | sed -E "s/(v?[0-9]+\.)([0-9]+\.)([0-9]+)(-.*)?/\1\2\3\.${build_no}\4/") >> $GITHUB_ENV diff --git a/.github/scripts/uninstall_validate_utplsql.sh b/.github/scripts/uninstall_validate_utplsql.sh new file mode 100755 index 000000000..d0a2070a8 --- /dev/null +++ b/.github/scripts/uninstall_validate_utplsql.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +set -ev +SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +cd ${SCRIPT_DIR}/../../source + +time "$SQLCLI" sys/$ORACLE_PWD@//$CONNECTION_STR AS SYSDBA <<-SQL + set feedback off + set verify off + whenever sqlerror exit failure rollback + + @uninstall_all.sql $UT3_DEVELOP_SCHEMA +SQL +time "$SQLCLI" sys/$ORACLE_PWD@//$CONNECTION_STR AS SYSDBA <<-SQL + set feedback off + set verify off + whenever sqlerror exit failure rollback + set serverout on + begin + for i in ( + select o.object_type||' '||o.owner||'.'||o.object_name as obj + from dba_objects o + where owner = '$UT3_DEVELOP_SCHEMA' + union all + select 'SYNONYM '||s.owner||'.'||s.synonym_name||' FOR '||s.table_owner||'.'||s.table_name as obj + from dba_synonyms s + where table_owner = '$UT3_DEVELOP_SCHEMA' + ) loop + dbms_output.put_line(i.obj); + end loop; + end; + / + declare + v_leftover_objects_count integer; + begin + select sum(cnt) + into v_leftover_objects_count + from ( + select count(1) cnt from dba_objects + where owner = '$UT3_DEVELOP_SCHEMA' + and object_name not like 'PLSQL_PROFILER%' and object_name not like 'DBMSPCC_%' + union all + select count(1) cnt from dba_synonyms + where table_owner = '$UT3_DEVELOP_SCHEMA' + and table_name not like 'PLSQL_PROFILER%' and table_name not like 'DBMSPCC_%' + ); + if v_leftover_objects_count > 0 then + raise_application_error(-20000, 'Not all objects were successfully uninstalled - leftover objects count='||v_leftover_objects_count); + end if; + end; + / + drop user $UT3_DEVELOP_SCHEMA; +SQL diff --git a/.github/scripts/update_project_version.sh b/.github/scripts/update_project_version.sh new file mode 100755 index 000000000..66e45125a --- /dev/null +++ b/.github/scripts/update_project_version.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +UTPLSQL_VERSION_PATTERN="v?([0-9]+\.){3}[0-9]+[^']*" + +echo Current branch is "${CI_ACTION_REF_NAME}" + +echo Update version in project source files +find source -type f -name '*' -exec sed -i -r "s/${UTPLSQL_VERSION_PATTERN}/${UTPLSQL_BUILD_VERSION}/" {} \; +echo Source files updated with version tag: ${UTPLSQL_BUILD_VERSION} + +echo Update version in documentation files +find docs -type f -name '*.md' -exec sed -i -r "s/(badge\/version-).*(-blue\.svg)/\1${UTPLSQL_BUILD_VERSION/-/--}\2/" {} \; + +echo Update of sonar-project.properties sonar.projectVersion +sed -i -r "s/(sonar\.projectVersion=).*?/\1${UTPLSQL_VERSION}/" sonar-project.properties + +echo Update VERSION file +echo ${UTPLSQL_VERSION} > VERSION +echo ${UTPLSQL_BUILD_NO} > BUILD_NO + diff --git a/.travis/validate_report_files.sh b/.github/scripts/validate_report_files.sh old mode 100644 new mode 100755 similarity index 90% rename from .travis/validate_report_files.sh rename to .github/scripts/validate_report_files.sh index 621297a0b..722a9220a --- a/.travis/validate_report_files.sh +++ b/.github/scripts/validate_report_files.sh @@ -1,11 +1,13 @@ #!/usr/bin/env bash +SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" + GL_VALID=1 -XSD_DIR="$TRAVIS_BUILD_DIR/.travis/xsd" -XML_JAR_DIR="$TRAVIS_BUILD_DIR/.travis/lib" +XSD_DIR="${SCRIPT_DIR}/xsd" +XML_JAR_DIR="${SCRIPT_DIR}/lib" #XML Validator XML_VALIDATOR="$XML_JAR_DIR/xml_validator.jar" -HTML_VALIDATOR_URL="https://validator.w3.org/nu/" +HTML_VALIDATOR_URL="http://localhost:8888/" HTML_FILENAME="coverage.html" declare -A XML_FILES diff --git a/.travis/xsd/junit4.xsd b/.github/scripts/xsd/junit4.xsd similarity index 100% rename from .travis/xsd/junit4.xsd rename to .github/scripts/xsd/junit4.xsd diff --git a/.travis/xsd/junit_windy.xsd b/.github/scripts/xsd/junit_windy.xsd similarity index 88% rename from .travis/xsd/junit_windy.xsd rename to .github/scripts/xsd/junit_windy.xsd index fe134662a..320779edd 100644 --- a/.travis/xsd/junit_windy.xsd +++ b/.github/scripts/xsd/junit_windy.xsd @@ -1,6 +1,6 @@ - - @@ -71,10 +71,11 @@ Permission to waive conditions of this license may be requested from Windy Road - - - Indicates that the test errored. An errored test is one that had an unanticipated problem. e.g., an unchecked throwable; or a problem with the implementation of the test. Contains as a text node relevant data for the error, e.g., a stack trace - + + + + Indicates that the test errored. An errored test is one that had an unanticipated problem. e.g., an unchecked throwable; or a problem with the implementation of the test. Contains as a text node relevant data for the error, e.g., a stack trace + @@ -93,9 +94,9 @@ Permission to waive conditions of this license may be requested from Windy Road - - Indicates that the test failed. A failure is a test which the code has explicitly failed by using the mechanisms for that purpose. e.g., via an assertEquals. Contains as a text node relevant data for the failure, e.g., a stack trace - + + Indicates that the test failed. A failure is a test which the code has explicitly failed by using the mechanisms for that purpose. e.g., via an assertEquals. Contains as a text node relevant data for the failure, e.g., a stack trace + @@ -192,6 +193,11 @@ Permission to waive conditions of this license may be requested from Windy Road The total number of tests in the suite that errored. An errored test is one that had an unanticipated problem. e.g., an unchecked throwable; or a problem with the implementation of the test. + + + The total number of ignored or skipped tests in the suite. + + Time taken (in seconds) to execute the tests in the suite @@ -203,4 +209,4 @@ Permission to waive conditions of this license may be requested from Windy Road - + \ No newline at end of file diff --git a/.github/variables/.env b/.github/variables/.env new file mode 100644 index 000000000..7bb5003e8 --- /dev/null +++ b/.github/variables/.env @@ -0,0 +1,27 @@ +#utPLSQL install env +UT3_DEVELOP_SCHEMA=UT3_DEVELOP +UT3_DEVELOP_SCHEMA_PASSWORD=ut3 +UT3_RELEASE_VERSION_SCHEMA=UT3 +UT3_RELEASE_VERSION_SCHEMA_PASSWORD=ut3 +UT3_TABLESPACE=users + +# Database Env +SQLCLI="sqlplus" +OJDBC_HOME=ojdbc +OJDBC_URL="https://download.oracle.com/otn-pub/otn_software/jdbc/213" +ORACLE_PWD="oracle" +TZ="Europe/London" + +#Build env +UTPLSQL_CLI_VERSION="3.1.8" +UTPLSQL_DIR="utPLSQL_latest_release" +UTPLSQL_BUILD_NO_OFFSET=3563 + +#Git configuration +GIT_AUTHOR_NAME="github-actions[bot]" +GIT_AUTHOR_EMAIL="github-actions[bot]@users.noreply.github.com" +GIT_COMMITTER_NAME="github-actions[bot]" +GIT_COMMITTER_EMAIL="github-actions[bot]@users.noreply.github.com" + +#Docker environment for running utPLSQL install commands +DOCKER_ENV="-e SQLCLI=sqlplus -e UT3_DEVELOP_SCHEMA -e UT3_DEVELOP_SCHEMA_PASSWORD -e UT3_RELEASE_VERSION_SCHEMA -e UT3_RELEASE_VERSION_SCHEMA_PASSWORD -e UT3_TABLESPACE -e ORACLE_PWD -e CONNECTION_STR -e UTPLSQL_DIR" \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..af2e4875d --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,297 @@ +name: Build, test, deploy documentation +on: + push: + branches-ignore: [ main ] + pull_request: + branches: [ develop ] + + workflow_dispatch: + +concurrency: ${{github.ref}} +defaults: + run: + shell: bash + +jobs: + + build: + name: Build and test on ${{matrix.db_version_name}} DB + runs-on: ubuntu-latest + env: + ORACLE_VERSION: ${{matrix.oracle-version}} + ORACLE_SID: ${{matrix.oracle-sid}} + CONNECTION_STR: ${{ format( '127.0.0.1:1521/{0}', matrix.oracle-sid ) }} + ORACLE_PASSWORD: oracle + DOCKER_VOLUME: ${{matrix.docker-volume}} + strategy: + fail-fast: false + matrix: + include: + - id: 1 + db_version_name: '11XE' + oracle-sid: 'XE' + oracle-version: "gvenzl/oracle-xe:11-full" + oracle-base: '/u01/app/oracle' + - id: 2 + db_version_name: '12.1EE' + oracle-sid: 'ORCLCDB' + oracle-version: "utplsqlv3/oracledb:12c-r1-ee-small" + oracle-base: '/opt/oracle' +# - id: 3 +# db_version_name: '12.2se' +# oracle-sid: 'ORCLCDB' +# oracle-version: "utplsqlv3/oracledb:12c-r2-se2-small" +# oracle-base: '/opt/oracle' + - id: 4 + db_version_name: '18XE' + oracle-sid: 'XE' + oracle-version: "gvenzl/oracle-xe:18-slim" + oracle-base: '/opt/oracle' +# TODO - need to add healthcheck.sh into our containers +# - id: 5 +# db_version_name: '19se' +# oracle-sid: 'ORCLCDB' +# oracle-version: "utplsqlv3/oracledb:19c-se2-small" +# oracle-base: '/opt/oracle' + - id: 6 + db_version_name: '21XE' + oracle-sid: 'XE' + oracle-version: "gvenzl/oracle-xe:21-slim" + oracle-base: '/opt/oracle' + - id: 7 + db_version_name: '23free' + oracle-sid: 'FREEPDB1' + oracle-version: "gvenzl/oracle-free:23-slim" + oracle-base: '/opt/oracle' + + services: + html_checker: + image: ghcr.io/validator/validator:latest + options: >- + -p 8888:8888 + oracle: + image: ${{matrix.oracle-version}} + env: + ORACLE_PASSWORD: oracle + credentials: + username: ${{ secrets.DOCKER_USER }} + password: ${{ secrets.DOCKER_PASSWORD }} + volumes: + - ${{github.workspace}}:/utPLSQL + ports: + - 1521:1521 + options: >- + --health-interval 10s + --health-timeout 5s + --health-retries 10 + --name oracle + --health-cmd healthcheck.sh + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: c-py/action-dotenv-to-setenv@v2 + with: + env-file: .github/variables/.env + - uses: FranzDiebold/github-env-vars-action@v2 #https://github.com/marketplace/actions/github-environment-variables-action + + - name: Set build version number env variables + id: set-build-version-number-vars + run: .github/scripts/set_version_numbers_env.sh + + - name: Update project version & build number to verify that code is deployable after the update + id: update-project-version + run: .github/scripts/update_project_version.sh + + - name: Download utPLSQL release for testing +# For PR build - test using target branch as framework, for branch build use self as testing framework + run: git clone --depth=1 --branch=${CI_BASE_REF:-$CI_REF_NAME} https://github.com/utPLSQL/utPLSQL.git $UTPLSQL_DIR + + - name: Update privileges on sources + run: chmod -R go+w ./{source,test,examples,${UTPLSQL_DIR}/source} + + - name: Add OJDBC home + id: get-ojdbc + run: mkdir -p ${OJDBC_HOME} && curl -Lk -o ${OJDBC_HOME}/ojdbc8.jar ${OJDBC_URL}/ojdbc8.jar && curl -Lk -o ${OJDBC_HOME}/orai18n.jar ${OJDBC_URL}/orai18n.jar + + - name: Install utPLSQL-cli + id: install-utplsql-cli + run: curl -Lk -o utPLSQL-cli.zip "https://github.com/utPLSQL/utPLSQL-cli/releases/download/v3.1.8/utPLSQL-cli.zip" && unzip utPLSQL-cli.zip && chmod -R u+x utPLSQL-cli + + - name: Install utPLSQL + id: install-utplsql + run: docker run --rm -v $(pwd):/utPLSQL -w /utPLSQL --network host --entrypoint bash ${DOCKER_ENV} ${ORACLE_VERSION} .github/scripts/install.sh + + - name: Check code style + if: ${{ matrix.id == 1 }} + id: check-coding-style + run: docker run --rm -v $(pwd):/utPLSQL -w /utPLSQL --network host --entrypoint "$SQLCLI" ${DOCKER_ENV} ${ORACLE_VERSION} $UT3_DEVELOP_SCHEMA/$UT3_DEVELOP_SCHEMA_PASSWORD@//$CONNECTION_STR @development/utplsql_style_check.sql + + - name: Validate utPLSQL uninstall + if: ${{ matrix.id == 1 }} + id: validate-uninstall + run: docker run --rm -v $(pwd):/utPLSQL -w /utPLSQL --network host --entrypoint bash ${DOCKER_ENV} ${ORACLE_VERSION} .github/scripts/uninstall_validate_utplsql.sh + + - name: Reinstall utPLSQL + if: ${{ matrix.id == 1 }} + id: reinstall-utplsql + run: docker run --rm -v $(pwd):/utPLSQL -w /utPLSQL --network host --entrypoint bash ${DOCKER_ENV} ${ORACLE_VERSION} .github/scripts/install.sh + + - name: Create test users + id: create-test-users + run: docker run --rm -v $(pwd):/utPLSQL -w /utPLSQL --network host --entrypoint bash ${DOCKER_ENV} ${ORACLE_VERSION} .github/scripts/create_test_users.sh + + - name: Install utPLSQL release + id: install-utplsql-release + run: docker run --rm -v $(pwd):/utPLSQL -w /utPLSQL --network host --entrypoint bash ${DOCKER_ENV} ${ORACLE_VERSION} .github/scripts/install_utplsql_release.sh + + - name: Run Examples + id: run-examples + run: docker run --rm -v $(pwd):/utPLSQL -w /utPLSQL --network host --entrypoint bash ${DOCKER_ENV} ${ORACLE_VERSION} .github/scripts/run_examples.sh + + - name: Install tests + id: install-tests + run: docker run --rm -v $(pwd):/utPLSQL -w /utPLSQL --network host --entrypoint bash ${DOCKER_ENV} ${ORACLE_VERSION} test/install_tests.sh + + - name: Run Tests + id: run-tests + run: bash test/run_tests.sh + +#Start Needed to diagnose occasional failures of DB on test runs + - name: Prepare diagnostic directory + id: preapre-oracle-diag-dir + if: ${{ always() && steps.run-tests.outcome == 'failure' }} + run: | + mkdir database-diag + chmod +777 database-diag + - name: Get ORACLE_BASE/diag data + id: get-oracle-diag-data + if: ${{ always() && steps.run-tests.outcome == 'failure' }} + run: docker exec oracle bash -c "chmod -R +777 ./diag && cp -r ./diag /utPLSQL/database-diag" + - name: Upload ORACLE_BASE/diag data Artifact + id: upload + if: ${{ always() && steps.run-tests.outcome == 'failure' }} + uses: actions/upload-artifact@v4 + with: + name: my-artifact$-${{matrix.db_version_name}} + path: ${{github.workspace}}/database-diag +#End Needed to diagnose occasional failures of DB on test runs + + - name: Validate utPLSQL reports format + id: validate-reports-format + run: bash .github/scripts/validate_report_files.sh + + - name: Codecov + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos + files: ./cobertura.xml + flags: ${{matrix.db_version_name}} + fail_ci_if_error: true # optional (default = false) + + - name: Publish unit test results + uses: EnricoMi/publish-unit-test-result-action@v1.24 + if: always() + with: + files: junit_test_results.xml + + - name: SonarCloud Scan + id: sonar + if: ${{ always() && matrix.db_version_name == '21XE' }} + uses: SonarSource/sonarcloud-github-action@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + with: + args: > + -Dsonar.buildString=${{ format( '{0}.{1}', env.UTPLSQL_BUILD_VERSION, matrix.id ) }} + -Dsonar.plsql.jdbc.url=${{ format( 'jdbc:oracle:thin:@//oracle:1521/{0}', env.ORACLE_SID ) }} + -Dsonar.plsql.jdbc.driver.path=${{ format( '{0}/ojdbc8.jar', env.OJDBC_HOME ) }} + + publish: + name: Deploy documentation + needs: [ build ] + concurrency: publish + runs-on: ubuntu-latest + env: + API_TOKEN_GITHUB: ${{ secrets.API_TOKEN_GITHUB }} + if: | + github.repository == 'utPLSQL/utPLSQL' && + github.base_ref == null && github.ref == 'refs/heads/develop' + steps: + - name: 🔍 API_TOKEN_GITHUB + if: env.API_TOKEN_GITHUB == '' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: echo "API_TOKEN_GITHUB=${GITHUB_TOKEN}" >> $GITHUB_ENV + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + token: ${{ env.API_TOKEN_GITHUB }} + - uses: c-py/action-dotenv-to-setenv@v2 + with: + env-file: .github/variables/.env + - uses: FranzDiebold/github-env-vars-action@v2 #https://github.com/marketplace/actions/github-environment-variables-action + + - name: Set buid version number env variables + id: set-build-version-number-vars + run: .github/scripts/set_version_numbers_env.sh + + - name: Update project version & build number in source code and documentation + id: update-project-version + run: .github/scripts/update_project_version.sh + + - name: Push version update to repository + id: push-version-number-update + run: | + git add sonar-project.properties VERSION BUILD_NO source/* docs/* + git commit -m 'Updated project version after build [skip ci]' + git push --quiet origin HEAD:${CI_ACTION_REF_NAME} + + - name: Setup git config + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + + - name: Build and publish documentation + run: | + pip install mkdocs + pip install mkdocs-git-revision-date-localized-plugin + pip install mkdocs-material + pip install git+https://github.com/jimporter/mike.git + mike deploy -p develop + + dispatch: + name: Dispatch downstream builds + concurrency: trigger + needs: [ build, publish ] + runs-on: ubuntu-latest + if: | + github.repository == 'utPLSQL/utPLSQL' && github.base_ref == null && + ( startsWith( github.ref, 'refs/heads/release/v' ) || github.ref == 'refs/heads/develop' ) + strategy: + matrix: + repo: [ 'utPLSQL/utPLSQL-demo-project', 'utPLSQL/utPLSQL-java-api' ] +# repo: [ 'utPLSQL/utPLSQL-v2-v3-migration' ] + steps: + - name: Repository Dispatch + uses: peter-evans/repository-dispatch@v1 + with: + token: ${{ secrets.API_TOKEN_GITHUB }} + repository: ${{ matrix.repo }} + event-type: utPLSQL-build + + slack-workflow-status: + if: always() + name: Post Workflow Status To Slack + needs: [ build, publish, dispatch ] + runs-on: ubuntu-latest + steps: + - name: Slack Workflow Notification + uses: Gamesight/slack-workflow-status@master + with: + repo_token: ${{secrets.GITHUB_TOKEN}} + slack_webhook_url: ${{secrets.SLACK_WEBHOOK_URL}} + name: 'Github Actions[bot]' + icon_url: 'https://octodex.github.com/images/mona-the-rivetertocat.png' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..1c4db5d59 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,80 @@ +name: Create and publish release artifacts +on: + release: + types: [ released ] +#See: https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#example-using-multiple-events-with-activity-types-or-configuration + +defaults: + run: + shell: bash + +jobs: + + upload_artifacts: + name: Upload archives + concurrency: upload + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: c-py/action-dotenv-to-setenv@v2 + with: + env-file: .github/variables/.env + - uses: FranzDiebold/github-env-vars-action@v2 #https://github.com/marketplace/actions/github-environment-variables-action + + - name: Set build version number env variables + run: .github/scripts/set_release_version_numbers_env.sh + + - name: Update project version & build number in source code and documentation + run: .github/scripts/update_project_version.sh + + - name: Setup git config + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + + - name: Build and publish documentation + run: | + pip install mkdocs + pip install mkdocs-git-revision-date-localized-plugin + pip install mkdocs-material + pip install git+https://github.com/jimporter/mike.git + mike deploy -p -u ${UTPLSQL_VERSION} latest + mkdocs build --clean -f mkdocs_offline.yml + rm -rf docs/* + cp -r -v site/* docs + git add . + git commit -m "tmp commit of HTML documentation for building a release archive" + + - name: Build release archives + run: | + git archive --prefix=utPLSQL/ -o utPLSQL.zip --format=zip HEAD + git archive --prefix=utPLSQL/ -o utPLSQL.tar.gz --format=tar.gz HEAD + md5sum utPLSQL.zip --tag > utPLSQL.zip.md5 + md5sum utPLSQL.tar.gz --tag > utPLSQL.tar.gz.md5 + + - name: Release + uses: softprops/action-gh-release@v1 + with: + files: | + utPLSQL.zip + utPLSQL.zip.md5 + utPLSQL.tar.gz + utPLSQL.tar.gz.md5 + + slack-workflow-status: + if: always() + name: Post Workflow Status To Slack + needs: [ upload_artifacts ] + runs-on: ubuntu-latest + steps: + - name: Slack Workflow Notification + uses: Gamesight/slack-workflow-status@master + with: + repo_token: ${{secrets.GITHUB_TOKEN}} + slack_webhook_url: ${{secrets.SLACK_WEBHOOK_URL}} + name: 'Github Actions[bot]' + icon_url: 'https://octodex.github.com/images/mona-the-rivetertocat.png' + diff --git a/.gitignore b/.gitignore index 13452754f..be442d164 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,17 @@ node_modules/ utPLSQL_latest_release/ utPLSQL-cli/ development/env.sh +development/*.jar *.log + +# exclusions based on artifacts created via actions documented in CONTRIBUTING.md +test/dummy.sql +coverage.html_assets/ +coverage.html +coverage.json +coverage.xml +tfs_test_results.xml +junit_test_results.xml +test_results.xml +*debug*.xml +cobertura.xml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a6aecb53c..000000000 --- a/.travis.yml +++ /dev/null @@ -1,140 +0,0 @@ -sudo: required -language: python - -addons: - apt: - packages: - - unzip - # Java9 Required for Sonar and SQLCL - - oracle-java9-installer - - oracle-java9-set-default - sonarcloud: - organization: utplsql - token: - secure: ${SONAR_TOKEN} - -services: - - docker - -env: - global: - - UT3_OWNER=ut3 - - UT3_OWNER_PASSWORD=ut3 - - UT3_RELEASE_VERSION_SCHEMA=UT3_LATEST_RELEASE - - UT3_USER="UT3\$USER#" - - UT3_USER_PASSWORD=ut3 - - UT3_TESTER=ut3_tester - - UT3_TESTER_PASSWORD=ut3 - - UT3_TABLESPACE=users - # Environment for building a release - - CURRENT_BRANCH=${TRAVIS_BRANCH} - - UTPLSQL_REPO="utPLSQL/utPLSQL" - - UTPLSQL_BUILD_NO="${TRAVIS_BUILD_NUMBER:-0}" - - UTPLSQL_VERSION_PATTERN="v?([0-9]+\.){3}[0-9]+[^']*" - - UTPLSQL_VERSION=$(. .travis/get_project_version.sh) - - UTPLSQL_BUILD_VERSION=$(. .travis/get_project_build_version.sh) - - UTPLSQL_SOURCES_DIR='source' - - UTPLSQL_BUILD_USER_NAME="Travis CI" - - CACHE_DIR=$HOME/.cache - # Database Env - - SQLCLI="$HOME/sqlcl/bin/sql" - - ORACLE_PWD="oracle" - - UT3_DOCKER_REPO="utplsqlv3/oracledb" - - DOCKHER_HUB_REPO="${DOCKER_BASE_TAG:-$UT3_DOCKER_REPO}" - #utPLSQL released version directory - - UTPLSQL_DIR="utPLSQL_latest_release" - - SELFTESTING_BRANCH=${TRAVIS_BRANCH} - - UTPLSQL_CLI_VERSION="3.1.0" - # Maven - - MAVEN_HOME=/usr/local/maven - - MAVEN_CFG=$HOME/.m2 - matrix: - - ORACLE_VERSION="${DOCKER_TAG_11G:-11g-r2-xe}" CONNECTION_STR='127.0.0.1:1521/XE' DOCKER_OPTIONS='--shm-size=1g' - - ORACLE_VERSION="${DOCKER_TAG_12C:-12c-r1-se2-small}" CONNECTION_STR='127.0.0.1:1521/ORCLCDB' DOCKER_OPTIONS="-v /dev/pdbs:/opt/oracle/oradata/pdbs" - - ORACLE_VERSION="${DOCKER_TAG_12C2:-12c-r2-se2-small}" CONNECTION_STR='127.0.0.1:1521/ORCLCDB' DOCKER_OPTIONS="-v /dev/pdbs:/opt/oracle/oradata/pdbs" - - ORACLE_VERSION="${DOCKER_TAG_18:-18c-se2-small}" CONNECTION_STR='127.0.0.1:1521/ORCLCDB' DOCKER_OPTIONS="-v /dev/pdbs:/opt/oracle/oradata/pdbs" - -cache: - pip: true - directories: - - $CACHE_DIR - - /home/travis/.sonar/cache - - node_modules - - $MAVEN_CFG - -before_install: - #cache to be used between stages. Based on https://github.com/travis-ci/docs-travis-ci-com/issues/1329 - #delete all files in cache that are older than 5 days - - mkdir -p $CACHE_DIR/stages_cache; find $CACHE_DIR/stages_cache/ -mtime +5 -exec rm {} \; - #The update_project_version.sh is done before deployment to validate that the change of project files does not break installation - - bash .travis/update_project_version.sh - #Allow for sonar to blame issues - - git fetch --unshallow - # download latest utPLSQL release - #- curl -LOk $(curl --silent https://api.github.com/repos/utPLSQL/utPLSQL/releases/latest | awk '/browser_download_url/ { print $2 }' | grep ".zip" | sed 's/"//g') - - git clone --depth=1 --branch=${SELFTESTING_BRANCH:-master} https://github.com/utPLSQL/utPLSQL.git $UTPLSQL_DIR - # download latest utPLSQL-cli release - - curl -Lk -o utPLSQL-cli.zip https://github.com/utPLSQL/utPLSQL-cli/releases/download/v${UTPLSQL_CLI_VERSION}/utPLSQL-cli.zip - -install: - #- unzip utPLSQL.zip - - unzip utPLSQL-cli.zip && chmod -R u+x utPLSQL-cli - # Get ojdbc via maven - - bash .travis/maven_cfg.sh - - bash .travis/install_sqlcl.sh - - sudo mkdir -p /dev/pdbs - - sudo chmod -R 777 /dev/pdbs - - if [[ ! $TRAVIS_TAG ]]; then bash .travis/start_db.sh; fi - -before_script: - - if [[ ! $TRAVIS_TAG ]]; then bash .travis/install.sh; fi - - if [[ ! $TRAVIS_TAG ]]; then bash .travis/install_utplsql_release.sh; fi - - if [[ ! $TRAVIS_TAG ]]; then bash .travis/run_examples.sh; fi - - if [[ ! $TRAVIS_TAG ]]; then bash .travis/run_old_tests.sh; fi - -script: - - if [[ ! $TRAVIS_TAG ]]; then bash test/install_and_run_tests.sh; fi - - if [[ ! $TRAVIS_TAG ]]; then bash .travis/validate_report_files.sh; fi - - if [[ ! $TRAVIS_TAG ]] && [ "${TRAVIS_REPO_SLUG}" = "${UTPLSQL_REPO}" ]; then bash .travis/run_sonar_scanner.sh; fi - - if [[ ! $TRAVIS_TAG ]]; then bash .travis/coveralls_uploader.sh; fi - -notifications: - slack: - rooms: - - secure: "nemt9n2y5sVCAKqa/s7JDQ8AcM59Xu/XbH/RkMOXvPgc+KtR8lBtVD1LkvJ5BaQhqgjuDT7DNt/uisQJ7k6a2OsrVFbnkypZ1hCvntOBpJyoSpD/YL1X8a9GbGojuJcph0BX76KN21LaOVdyOfY0TSlw53XiYWS8iL5HtjpWCbIwHL1SJ8JT8mhdT4hDoUWZjcZ4s4bLH6BQm4un/bMQOmB4sDoCeg4CllJwxgkswVF7OHpOFjgPetvUp7ps8b/Rj8en6zCj9drb0SVbXFgumo2Wd1bC3HHZB8MAZU0kuEV5VgUdum6EelUL5yfB72hssNQA0+CaT3HjBFkTlqWYJmjC4/xyGN3sseiW82T9FDY0g0GAGayNRW+QSiTQ1hbJEcAnNe0GrBUdRsgXdI6COd76YP5VxzRSF6H7niLfgCZdKbIivKUd1o+wBhuyJmqCFIkRWmT38tMGJqJAzbY1jq5gQXbb6E7gt+KdTjlSjcnJYf7XI7zqm+BRr+fbA0ixfXHvfqOBgZN6g08y9nPlDnIjtSF2NSdrj2zqYQAtKuWSOD1bnTyfDJyrtK7OLffZcMYD5Bcss4c8op8tP7MGTjt1S046SJocboh6H4c/nTokpoMRsWs6MKRdebl8C2RObGf5FebSOJg+oh2ZYS5Z/G9GshiY2BD/81+Hc4Miacc=" - on_success: change - on_failure: always - -jobs: - include: - - stage: deploy - env: ORACLE_VERSION="none" - before_install: skip - install: - - pip install mkdocs - before_script: skip - script: - - if [[ ($TRAVIS_BRANCH == develop) && ($TRAVIS_PULL_REQUEST == false) ]]; then bash .travis/trigger_travis.sh $TRAVIS_ACCESS_TOKEN; fi - - #The update_project_version.sh needs to be done before pushing changes to develop branch - - bash .travis/update_project_version.sh - - git config --global user.email "builds@travis-ci.com" - - git config --global user.name "${UTPLSQL_BUILD_USER_NAME}" - - git remote rm origin - - git remote add origin https://${github_api_token}@github.com/${UTPLSQL_REPO} - - if [[ ! $TRAVIS_TAG ]]; then bash .travis/push_release_version.sh; fi - - bash .travis/build_docs.sh - - bash .travis/push_docs_to_gh_pages.sh - before_deploy: - - bash .travis/build_release_archive.sh - deploy: - provider: releases - api_key: $github_api_token - file: - - utPLSQL.zip - - utPLSQL.tar.gz - - utPLSQL.zip.md5 - - utPLSQL.tar.gz.md5 - skip_cleanup: true - on: - repo: ${UTPLSQL_REPO} - tags: true diff --git a/.travis/build_docs.sh b/.travis/build_docs.sh deleted file mode 100644 index db43d7ca9..000000000 --- a/.travis/build_docs.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -# Change working directory to script directory -cd "${0%/*}" -# Change back to root -cd .. -mkdocs build --clean --strict diff --git a/.travis/build_release_archive.sh b/.travis/build_release_archive.sh deleted file mode 100644 index 9667cba7e..000000000 --- a/.travis/build_release_archive.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -# remove markdown documentation -rm -rf docs/* -# and replace it with generated html documentation from the ignored site folder -cp -r -v site/* docs - -git add . -git commit -m "tmp commit for building a release archive" - -# git archive --prefix="utPLSQL${UTPLSQL_BUILD_VERSION}"/ -o "utPLSQL${UTPLSQL_BUILD_VERSION}".zip --format=zip HEAD -# git archive --prefix="utPLSQL${UTPLSQL_BUILD_VERSION}"/ -o "utPLSQL${UTPLSQL_BUILD_VERSION}".tar.gz --format=tar.gz HEAD - -git archive --prefix=utPLSQL/ -o utPLSQL.zip --format=zip HEAD -git archive --prefix=utPLSQL/ -o utPLSQL.tar.gz --format=tar.gz HEAD -md5sum utPLSQL.zip --tag > utPLSQL.zip.md5 -md5sum utPLSQL.tar.gz --tag > utPLSQL.tar.gz.md5 - diff --git a/.travis/coveralls_uploader.js b/.travis/coveralls_uploader.js deleted file mode 100644 index ad6eeee74..000000000 --- a/.travis/coveralls_uploader.js +++ /dev/null @@ -1,31 +0,0 @@ -var fs = require('fs'); -var request = require('request'); -const md5File = require('md5-file'); - -var url -if (process.env.COVERALLS_URL_BASE) { - url = process.env.COVERALLS_URL_BASE+'/api/v1/jobs'; -} else { - url = 'https://coveralls.io/api/v1/jobs'; -} - -fs.readFile('../coverage.json',function (err,data) { - if (err) { - return console.log(err); - } - req = JSON.parse(data); - req.service_job_id = process.env.TRAVIS_JOB_ID; - req.service_name = 'travis-ci'; - if (process.env.COVERALLS_REPO_TOKEN) { - req.repo_token = process.env.COVERALLS_REPO_TOKEN; - } - - for (var i in req.source_files) { - req.source_files[i].source_digest = md5File.sync("../" + req.source_files[i].name); - } - - var requestStr = JSON.stringify(req); - - request.post({url : url, form : { json:requestStr}}, function(err, response, body){process.stdout.write(body);}); - -}); diff --git a/.travis/coveralls_uploader.sh b/.travis/coveralls_uploader.sh deleted file mode 100644 index 8fcbad58d..000000000 --- a/.travis/coveralls_uploader.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -e -echo "coveralls_uploader" -npm install request --save -npm install --save md5-file -cd "$(dirname "$(readlink -f "$0")")" -exec node coveralls_uploader.js diff --git a/.travis/download.js b/.travis/download.js deleted file mode 100644 index bc981cdf4..000000000 --- a/.travis/download.js +++ /dev/null @@ -1,54 +0,0 @@ - -var casper = require("casper").create({ - // verbose: true, - // logLevel: "debug", - pageSettings: { - loadImages: false, - loadPlugins: false - } -}); - -if (casper.cli.args.length < 4) { - casper.echo("Missing parameters: username password agreementUrl downloadUrl").exit(1); -} - -// Script parameters. -var paramUsername = casper.cli.get(0); -var paramPassword = casper.cli.get(1); -var agreementUrl = casper.cli.get(2); -var downloadUrl = casper.cli.get(3); - -casper.start(); -// TODO: Error handling. - -// Accept the license agreement. -casper.thenOpen(agreementUrl, function () { - // this.echo("Accepting License"); - this.evaluate(function () { - acceptAgreement(window.self); - }); -}); - -// Try to access the download page, wait for redirection and submit the login form. -casper.thenOpen(downloadUrl).waitForUrl(/signon\.jsp$/, function (re) { - // this.echo("Injecting Login Info"); - this.evaluate(function (username, password) { - document.getElementById("sso_username").value = username; - document.getElementById("ssopassword").value = password; - doLogin(document.LoginForm); - }, paramUsername, paramPassword); - // this.capture("Screenshot.png"); -}); - -casper.on("resource.received", function (resource) { - if (resource.url.indexOf("AuthParam") !== -1) { - // this.echo("DownloadUrl:"); - // Print the download url. - this.echo(resource.url); - // TODO: Try to download file from here. this.download is not working because of cross site request. - } -}); - -casper.run(function () { - this.exit(); -}); diff --git a/.travis/download.sh b/.travis/download.sh deleted file mode 100644 index d7f0b7d0f..000000000 --- a/.travis/download.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/bash -set -e - -if [ "$ORACLE_OTN_USER" == "" ] || [ "$ORACLE_OTN_PASSWORD" == "" ]; then - echo "Error: Oracle OTN username/password not specified." - exit 1 -fi - -PRODUCT="" - -# Call the casperjs script to return the download url. -# Then download the file using curl. -downloadFile() { - downloadUrl=$(exec casperjs download.js $ORACLE_OTN_USER $ORACLE_OTN_PASSWORD $1 $2) - echo "DownloadURL: $downloadUrl" - curl $downloadUrl -o $3 -} - -############################# -########### START ########### -############################# - -while getopts "p:" OPTNAME; do - case "${OPTNAME}" in - "p") PRODUCT="${OPTARG}" ;; - esac -done - -if [ "$PRODUCT" == "se12c" ]; then - agreementUrl="http://www.oracle.com/technetwork/database/enterprise-edition/downloads/index.html" - downloadUrl="http://download.oracle.com/otn/linux/oracle12c/121020/linuxamd64_12102_database_se2_1of2.zip" - outputFile=linuxamd64_12102_database_se2_1of2.zip - downloadFile $agreementUrl $downloadUrl $outputFile - agreementUrl="http://www.oracle.com/technetwork/database/enterprise-edition/downloads/index.html" - downloadUrl="http://download.oracle.com/otn/linux/oracle12c/121020/linuxamd64_12102_database_se2_2of2.zip" - outputFile=linuxamd64_12102_database_se2_2of2.zip - downloadFile $agreementUrl $downloadUrl $outputFile - exit 0 -fi - -if [ "$PRODUCT" == "ee12c" ]; then - agreementUrl="http://www.oracle.com/technetwork/database/enterprise-edition/downloads/index.html" - downloadUrl="http://download.oracle.com/otn/linux/oracle12c/121020/linuxamd64_12102_database_1of2.zip" - outputFile=linuxamd64_12102_database_1of2.zip - downloadFile $agreementUrl $downloadUrl $outputFile - agreementUrl="http://www.oracle.com/technetwork/database/enterprise-edition/downloads/index.html" - DOWNLOAD_URL="http://download.oracle.com/otn/linux/oracle12c/121020/linuxamd64_12102_database_2of2.zip" - outputFile=linuxamd64_12102_database_2of2.zip - downloadFile $agreementUrl $downloadUrl $outputFile - exit 0 -fi - -if [ "$PRODUCT" == "xe11g" ]; then - agreementUrl="http://www.oracle.com/technetwork/database/database-technologies/express-edition/downloads/index.html" - downloadUrl="https://edelivery.oracle.com/akam/otn/linux/oracle11g/xe/oracle-xe-11.2.0-1.0.x86_64.rpm.zip" - outputFile=oracle-xe-11.2.0-1.0.x86_64.rpm.zip - downloadFile $agreementUrl $downloadUrl $outputFile - exit 0 -fi - -if [ "$PRODUCT" == "sqlcl" ]; then - agreementUrl="http://www.oracle.com/technetwork/developer-tools/sqlcl/downloads/index.html" - downloadUrl="http://download.oracle.com/otn/java/sqldeveloper/sqlcl-18.2.0.zip" - outputFile=sqlcl-18.2.0.zip - downloadFile $agreementUrl $downloadUrl $outputFile - exit 0 -fi - -echo "Error: invalid product: $PRODUCT" -exit 1 diff --git a/.travis/get_project_build_version.sh b/.travis/get_project_build_version.sh deleted file mode 100644 index 6f759bf99..000000000 --- a/.travis/get_project_build_version.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env bash -echo `sed -r "s/(v?[0-9]+\.)([0-9]+\.)([0-9]+)(-.*)?/\1\2\3\.${UTPLSQL_BUILD_NO}\4/" <<< "${UTPLSQL_VERSION}"` diff --git a/.travis/get_project_version.sh b/.travis/get_project_version.sh deleted file mode 100644 index 2ac4c6ab4..000000000 --- a/.travis/get_project_version.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -#When building a new version from a release branch, the version is taken from release branch name -if [[ "${CURRENT_BRANCH}" =~ ^release/v[0-9]+\.[0-9]+\.[0-9]+.*$ ]]; then - version=${CURRENT_BRANCH#release\/} -else - #Otherwise, version is taken from the VERSION file - version=`cat VERSION` - #When on develop branch, add "-develop" to the version text - if [[ "${CURRENT_BRANCH}" == "develop" ]]; then - version=`sed -r "s/(v?[0-9]+\.[0-9]+\.[0-9]+).*/\1-develop/" <<< "${version}"` - fi -fi -echo ${version} diff --git a/.travis/install.sh b/.travis/install.sh deleted file mode 100644 index 7b799eaa0..000000000 --- a/.travis/install.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/bin/bash - -cd source -set -ev - -#install core of utplsql -time "$SQLCLI" sys/$ORACLE_PWD@//$CONNECTION_STR AS SYSDBA <<-SQL -set feedback off -set verify off - -alter session set plsql_warnings = 'ENABLE:ALL', 'DISABLE:(5004,5018,6000,6001,6003,6009,6010,7206)'; -alter session set plsql_optimize_level=0; -@install_headless.sql $UT3_OWNER $UT3_OWNER_PASSWORD -SQL - -#Run this step only on first job slave (11.2 - at it's fastest) -if [[ "${TRAVIS_JOB_NUMBER}" =~ \.1$ ]]; then - - #check code-style for errors - time "$SQLCLI" $UT3_OWNER/$UT3_OWNER_PASSWORD@//$CONNECTION_STR @../development/utplsql_style_check.sql - - #test install/uninstall process - time "$SQLCLI" sys/$ORACLE_PWD@//$CONNECTION_STR AS SYSDBA <<-SQL - set feedback off - set verify off - - @uninstall_all.sql $UT3_OWNER - declare - v_leftover_objects_count integer; - begin - select sum(cnt) - into v_leftover_objects_count - from (select count(1) cnt from dba_objects where owner = '$UT3_OWNER' - union all - select count(1) cnt from dba_synonyms where table_owner = '$UT3_OWNER' - ); - if v_leftover_objects_count > 0 then - raise_application_error(-20000, 'Not all objects were successfully uninstalled - leftover objects count='||v_leftover_objects_count); - end if; - end; - / -SQL - - time "$SQLCLI" sys/$ORACLE_PWD@//$CONNECTION_STR AS SYSDBA <<-SQL - set feedback off - set verify off - - alter session set plsql_optimize_level=0; - @install.sql $UT3_OWNER -SQL - -fi - -#additional privileges to run scripted tests -time "$SQLCLI" sys/$ORACLE_PWD@//$CONNECTION_STR AS SYSDBA <<-SQL -set feedback on ---needed for Mystats script to work -grant select any dictionary to $UT3_OWNER; ---Needed for testing a coverage outside ut3_owner. -grant create any procedure, drop any procedure, execute any procedure to $UT3_OWNER; -SQL - -#Create user that will own the tests -time "$SQLCLI" sys/$ORACLE_PWD@//$CONNECTION_STR AS SYSDBA <<-SQL -set feedback off -@create_utplsql_owner.sql $UT3_TESTER $UT3_TESTER_PASSWORD $UT3_TABLESPACE - ---needed for testing distributed transactions -grant create public database link to $UT3_TESTER; -grant drop public database link to $UT3_TESTER; -set feedback on ---Needed for testing coverage outside of main UT3 schema. -grant create any procedure, drop any procedure, execute any procedure, create any type, drop any type, execute any type, under any type, select any table, update any table, insert any table, delete any table, create any table, drop any table, alter any table, select any dictionary to $UT3_TESTER; -revoke execute on dbms_crypto from $UT3_TESTER; -grant create job to $UT3_TESTER; -exit -SQL - -#Create additional UT3$USER# to test for special characters -time "$SQLCLI" sys/$ORACLE_PWD@//$CONNECTION_STR AS SYSDBA <<-SQL -set feedback off -@create_utplsql_owner.sql $UT3_USER $UT3_USER_PASSWORD $UT3_TABLESPACE ---Grant UT3 framework to UT3$USER# -@create_user_grants.sql $UT3_OWNER $UT3_USER -exit -SQL diff --git a/.travis/install_sqlcl.sh b/.travis/install_sqlcl.sh deleted file mode 100644 index 9db262c5d..000000000 --- a/.travis/install_sqlcl.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -set -e - -SQLCL_FILE=sqlcl-18.2.0.zip -cd .travis - -# Download if not present on cache dir. -if [ ! -f $CACHE_DIR/$SQLCL_FILE ]; then - npm install -g phantomjs-prebuilt casperjs - bash download.sh -p sqlcl - mv $SQLCL_FILE $CACHE_DIR -else - echo "Installing sqlcl from cache..." -fi; - -# Install sqlcl. -unzip -q $CACHE_DIR/$SQLCL_FILE -d $HOME - -# Check if it is installed correctly. -$SQLCLI -v diff --git a/.travis/maven_cfg.sh b/.travis/maven_cfg.sh deleted file mode 100644 index ef2348099..000000000 --- a/.travis/maven_cfg.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -set -ev -cp .travis/settings.xml $MAVEN_CFG/settings.xml - -cd $(dirname $(readlink -f $0)) - -# Download wagon-http recommended by Oracle. -# On maven latest version this is not needed, but travis doesn't have it. -if [ ! -f $CACHE_DIR/wagon-http-2.8-shaded.jar ]; then - curl -L -O "http://central.maven.org/maven2/org/apache/maven/wagon/wagon-http/2.8/wagon-http-2.8-shaded.jar" - mv wagon-http-2.8-shaded.jar $CACHE_DIR/ - sudo cp $CACHE_DIR/wagon-http-2.8-shaded.jar $MAVEN_HOME/lib/ext/ -else - echo "Using cached wagon-http..." - sudo cp $CACHE_DIR/wagon-http-2.8-shaded.jar $MAVEN_HOME/lib/ext/ -fi - -mvn dependency:copy-dependencies -DoutputDirectory=../utPLSQL-cli/lib \ No newline at end of file diff --git a/.travis/pom.xml b/.travis/pom.xml deleted file mode 100644 index 706bd79bb..000000000 --- a/.travis/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - 4.0.0 - org.utplsql - utplsql - 3.0.4-SNAPSHOT - jar - - utPLSQL - https://github.com/utPLSQL/utPLSQL - - - UTF-8 - - - - - com.oracle.jdbc - ojdbc8 - 12.2.0.1 - compile - - - com.oracle.jdbc - orai18n - 12.2.0.1 - compile - - - - - - maven.oracle.com - - true - - - false - - https://maven.oracle.com - default - - - - - - maven.oracle.com - https://maven.oracle.com - - - - - - - io.packagecloud.maven.wagon - maven-packagecloud-wagon - 0.0.6 - - - - diff --git a/.travis/push_docs_to_gh_pages.sh b/.travis/push_docs_to_gh_pages.sh deleted file mode 100644 index d2c5a685c..000000000 --- a/.travis/push_docs_to_gh_pages.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/bin/bash - -# Many aspects of this came from https://gist.github.com/domenic/ec8b0fc8ab45f39403dd -# Significant alterations -# - Support for multiple copies of documentation, -# - only clearing out develop -# - index.md logging doc history - -# How to run: -# - From repository root .travis/push_docs_to_gh_pages.sh - -# Required files / directories (relative from repo root) -# - File: "docs/index.md" with that contains develop docs - -# Required ENV Variables -PAGES_TARGET_BRANCH="gh-pages" -LATEST_DOCS_BRANCH="develop" -# TRAVIS_* variables are set by travis directly and only need to be if testing externally - -# We don't want a pull request automatically updating the repository -if [ "$TRAVIS_PULL_REQUEST" == "false" ] && { [ "${CURRENT_BRANCH}" == "${LATEST_DOCS_BRANCH}" ] || [ -n "${TRAVIS_TAG}" ]; }; then - - # ENV Variable checks are to help with configuration troubleshooting, they silently exit with unique message. - # Anyone one of them not set can be used to turn off this functionality. - - # If a version of the project is not defined - [[ -n "${UTPLSQL_VERSION}" ]] || { echo "variable UTPLSQL_VERSION is not defines or missing value"; exit 0; } - # Fail if the markdown documentation is not present. - [[ -f ./docs/index.md ]] || { echo "file docs/index.md not found"; exit 1; } - - # Save some useful information - SHA=`git rev-parse --verify HEAD` - - # clone the repository and switch to PAGES_TARGET_BRANCH branch - mkdir pages - cd pages - git clone https://${github_api_token}@github.com/${UTPLSQL_REPO} . - - PAGES_BRANCH_EXISTS=$(git ls-remote --heads origin ${PAGES_TARGET_BRANCH}) - - if [ -n "$PAGES_BRANCH_EXISTS" ] ; then - echo "Pages Branch Found" - git checkout ${PAGES_TARGET_BRANCH} - else - echo "Creating Pages Branch" - git checkout --orphan ${PAGES_TARGET_BRANCH} - git rm -rf . - fi - #clear out develop documentation directory and copy docs contents to it. - echo "updating 'develop' directory" - mkdir -p develop - rm -rf develop/**./* || exit 0 - cp -a ../docs/. ./develop - # If a Tagged Build then copy to it's own directory as well and to the 'latest' release directory - if [ -n "$TRAVIS_TAG" ]; then - echo "Creating ${UTPLSQL_VERSION}" - mkdir -p ${UTPLSQL_VERSION} - rm -rf ${UTPLSQL_VERSION}/**./* || exit 0 - cp -a ../docs/. ${UTPLSQL_VERSION} - echo "Populating 'latest' directory" - mkdir -p latest - rm -rf latest/**./* || exit 0 - cp -a ../docs/. latest - fi - # Stage changes for commit - git add . - #Check if there are doc changes, if none exit the script - if [[ -z `git diff HEAD --exit-code` ]] && [ -n "${PAGES_BRANCH_EXISTS}" ] ; then - echo "No changes to docs detected." - exit 0 - fi - #Changes where detected, so we need to update the version log. - now=$(date +"%d %b %Y - %r") - if [ ! -f index.md ]; then - echo "---" >>index.md - echo "layout: default" >>index.md - echo "---" >>index.md - echo "" >>index.md - echo "# Documentation versions" >>index.md - echo "" >>index.md - echo "" >>index.md #- 7th line - placeholder for latest release doc - echo "" >>index.md #- 8th line - placeholder for develop branch doc - echo "" >>index.md - echo "## Released Version Doc History" >>index.md - echo "" >>index.md - fi - #If build running on a TAG - it's a new release - need to add it to documentation - if [ -n "${TRAVIS_TAG}" ]; then - sed -i '7s@.*@'" - [Latest ${TRAVIS_TAG} documentation](latest/) - Created $now"'@' index.md - #add entry to the top of version history (line end of file - ## Released Version Doc History - sed -i '12i'" - [${TRAVIS_TAG} documentation](${UTPLSQL_VERSION}/) - Created $now" index.md - fi - #replace 4th line in log - sed -i '8s@.*@'" - [Latest development version](develop/) - Created $now"'@' index.md - #Add and Commit the changes back to pages repo. - git add . - git commit -m "Deploy to gh-pages branch: base commit ${SHA}" - # Now that we're all set up, we can push. - git push --quiet origin HEAD:${PAGES_TARGET_BRANCH} -fi - diff --git a/.travis/push_release_version.sh b/.travis/push_release_version.sh deleted file mode 100644 index 43ca773d8..000000000 --- a/.travis/push_release_version.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash - -# We are updating version number only when: -# - not a pull request -# - branch name is = develop or branch name is like release/vX.X.X... -if [ "${TRAVIS_REPO_SLUG}" = "${UTPLSQL_REPO}" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ] && [[ "${CURRENT_BRANCH}" =~ ^(release/v[0-9]+\.[0-9]+\.[0-9]+.*|develop)$ ]]; then - echo Current branch is "${CURRENT_BRANCH}" - echo "Committing version & buildNo into branch (${CURRENT_BRANCH})" - git add sonar-project.properties - git add VERSION - git add source/* - git commit -m 'Updated project version after build [skip ci]' - echo "Pushing to origin" - git push --quiet origin HEAD:${CURRENT_BRANCH} -else - echo "Publishing of version skipped for branch ${CURRENT_BRANCH}, pull request ${TRAVIS_PULL_REQUEST}" -fi diff --git a/.travis/run_examples.sh b/.travis/run_examples.sh deleted file mode 100644 index 967b621c7..000000000 --- a/.travis/run_examples.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -set -ev - -"$SQLCLI" $UT3_OWNER/$UT3_OWNER_PASSWORD@//$CONNECTION_STR <> sonar-project.properties -} - - -if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then - BRANCH=$TRAVIS_BRANCH; - PR_BRANCH="" - echo "BRANCH=$BRANCH" -else - BRANCH=$TRAVIS_PULL_REQUEST_BRANCH - PR_BRANCH=$TRAVIS_BRANCH - echo "TRAVIS_BRANCH=$TRAVIS_BRANCH, PR=$TRAVIS_PULL_REQUEST, BRANCH=$BRANCH" - -fi - - -#Are we running on utPLSQL repo and not an external PR? -echo "Check if we running from develop or on branch" -if [ "${TRAVIS_REPO_SLUG}" = "${UTPLSQL_REPO}" ] && [[ ! "${BRANCH}" =~ ^(release/v[0-9]+\.[0-9]+\.[0-9]+.*|"${MAIN_DEV_BRANCH}")$ ]]; then - - echo "" >> sonar-project.properties - if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then - echo "Updating sonar properties to include branch ${BRANCH}" - add_sonar_property "${BRANCH_SONAR_PROPERTY}" "${BRANCH}" - add_sonar_property "${BRANCH_SONAR_TARGET_PROPERTY}" "${MAIN_DEV_BRANCH}" - elif [ "${TRAVIS_PULL_REQUEST_SLUG}" = "${TRAVIS_REPO_SLUG}" ]; then - echo "Updating sonar properties to include pull request ${BRANCH}" - add_sonar_property "${PR_SONAR_TOKEN_PROPERTY}" "${GITHUB_TRAVISCI_TOKEN}" - add_sonar_property "${PR_SONAR_BRANCH_PROPERTY}" "${BRANCH}" - add_sonar_property "${PR_KEY_PROPERTY}" "${PR}" - add_sonar_property "${PR_SONAR_BASE_PROPERTY}" "${PR_BRANCH}" - else - echo "PR from external source no changes to properties." - fi -else - echo "No need to update sonar we building on release or develop" -fi - -#Execute Sonar scanner -sonar-scanner \ No newline at end of file diff --git a/.travis/settings.xml b/.travis/settings.xml deleted file mode 100644 index 731ef5298..000000000 --- a/.travis/settings.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - maven.oracle.com - ${env.ORACLE_OTN_USER} - ${env.ORACLE_OTN_PASSWORD} - - - ANY - ANY - OAM 11g - - - - - - http.protocol.allow-circular-redirects - %b,true - - - - - - - - - diff --git a/.travis/start_db.sh b/.travis/start_db.sh deleted file mode 100644 index e42656987..000000000 --- a/.travis/start_db.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -set -e - -# Private Repo Login -if [ ! -f $CACHE_DIR/.docker/config.json ]; then - docker login -u "$DOCKER_USER" -p "$DOCKER_PASSWORD" - mkdir -p $CACHE_DIR/.docker && cp $HOME/.docker/config.json $CACHE_DIR/.docker/ -else - echo "Using docker login from cache..." - mkdir -p $HOME/.docker && cp $CACHE_DIR/.docker/config.json $HOME/.docker/ -fi - -df -h -time docker pull $DOCKHER_HUB_REPO:$ORACLE_VERSION -df -h -docker run -d --name $ORACLE_VERSION $DOCKER_OPTIONS -p 1521:1521 $DOCKHER_HUB_REPO:$ORACLE_VERSION -time docker logs -f $ORACLE_VERSION | grep -m 1 "DATABASE IS READY TO USE!" --line-buffered -df -h diff --git a/.travis/trigger_travis.sh b/.travis/trigger_travis.sh deleted file mode 100644 index 039b00bbb..000000000 --- a/.travis/trigger_travis.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash - -# Trigger a new Travis-CI job. -# Ordinarily, a new Travis job is triggered when a commit is pushed to a -# GitHub repository. The trigger-travis.sh script provides a programmatic -# way to trigger a new Travis job. - -# To use this script to trigger a dependent build in Travis, do two things: -# -# 1. Set an environment variable TRAVIS_ACCESS_TOKEN by navigating to -# https://travis-ci.org/MYGITHUBID/MYGITHUBPROJECT/settings -# The TRAVIS_ACCESS_TOKEN environment variable will be set when Travis runs -# the job, but won't be visible to anyone browsing https://travis-ci.org/. -# - -echoerr() { echo "$@" 1>&2; } - -TRAVIS_URL=travis-ci.org -BRANCH=develop -USER="utPLSQL" -RESULT=1 -declare -a REPO_MATRIX=("utPLSQL-java-api" "utPLSQL-v2-v3-migration" "utPLSQL-cli" "utPLSQL-maven-plugin" "utPLSQL-demo-project") - -TOKEN=$1 - -if [ -n "$TRAVIS_REPO_SLUG" ] ; then - MESSAGE=",\"message\": \"Triggered by upstream build of $TRAVIS_REPO_SLUG commit "`git rev-parse --short HEAD`"\"" -else - MESSAGE=",\"message\": \"Triggered manually from shell\"" -fi - -# For debugging: -#echo "MESSAGE=$MESSAGE" - -body="{ -\"request\": { - \"branch\":\"$BRANCH\" - $MESSAGE -}}" - -for DOWNSTREAM_BUILD in "${REPO_MATRIX[@]}"; do - - curl -s -X POST \ - -H "Content-Type: application/json" \ - -H "Accept: application/json" \ - -H "Travis-API-Version: 3" \ - -H "Authorization: token ${TOKEN}" \ - -d "$body" \ - https://api.${TRAVIS_URL}/repo/${USER}%2F${DOWNSTREAM_BUILD}/requests \ - | tee ${DOWNSTREAM_BUILD}-output.txt - - if grep -q '"@type": "error"' ${DOWNSTREAM_BUILD}-output.txt; then - RESULT=0 - echoerr "" - echoerr "ERROR: Failed to start ${DOWNSTREAM_BUILD}" - echoerr "" - fi - if grep -q 'access denied' ${DOWNSTREAM_BUILD}-output.txt; then - RESULT=0 - echoerr "" - echoerr "ERROR: Failed to start ${DOWNSTREAM_BUILD} - access denied" - echoerr "" - fi - -done - -if [[ RESULT -eq 0 ]]; then - exit 1 -fi diff --git a/.travis/update_project_version.sh b/.travis/update_project_version.sh deleted file mode 100644 index cce45cbfe..000000000 --- a/.travis/update_project_version.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -echo Current branch is "${CURRENT_BRANCH}" - -echo Update version in project source files -find ${UTPLSQL_SOURCES_DIR} -type f -name '*' -exec sed -i -r "s/${UTPLSQL_VERSION_PATTERN}/${UTPLSQL_BUILD_VERSION}/" {} \; -echo Source files updated with version tag: ${UTPLSQL_BUILD_VERSION} - -echo Update of sonar-project.properties sonar.projectVersion -sed -i -r "s/(sonar\.projectVersion=).*?/\1${UTPLSQL_VERSION}/" sonar-project.properties - -echo Update VERSION file -echo ${UTPLSQL_VERSION} > VERSION - diff --git a/BUILD_NO b/BUILD_NO new file mode 100644 index 000000000..fab85b21d --- /dev/null +++ b/BUILD_NO @@ -0,0 +1 @@ +4206 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..b90e5e80e --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at utplsql@utplsql.org. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0e82a4ce4..41a86ecdd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,10 +43,11 @@ Your local environment can be of any flavor (Unix/Linux/Windows/Mac). At minimum you need to have Oracle database 11.2 XE accessible for the project and SYS account access to install and develop utPLSQL. We use four different database accounts (users) for development process. -* `ut3_latest_release` - holds latest released version of utPLSQL. This schema holds the testing framework used for self-testing of utPLSQL development. -* `ut3` - holds the version of utPLSQL of your current branch. This is the schema you will be working on. +* `ut3` - holds latest released version of utPLSQL. This schema holds the testing framework used for self-testing of utPLSQL development. +* `ut3_develop` - holds the version of utPLSQL of your current branch. This is the schema you will be working on. * `ut3_tester` - holds unit test packages for development of utPLSQL. -* `ut3$user#` - used for testing accessibility to schema names with special characters. +* `ut3_user` - used for testing accessibility to schema names with special characters. +* `ut3_tester_helper` - elevated privileges user, used for creating and dropping objects in other schemas during test run. @@ -95,8 +96,6 @@ The below script is fetching latest release version from utPLSQL repository. Lat ```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 @@ -108,7 +107,7 @@ development/install.sh You now have the following: - sources from `develop` branch of your fork of utPLSQL repository in `utPLSQL/ut3_latest_release` directory -- sources from `master` branch of utPLSQL/utPLSQL repository in `utPLSQL/ut3_latest_release` directory +- sources from `main` branch of utPLSQL/utPLSQL repository in `utPLSQL/ut3_latest_release` directory - binaries of `utplsql-cli` in `utPLSQL/utPLSQL-cli` directory - database users created - your current branch of utPLSQL deployed into `ut3` schema @@ -134,9 +133,7 @@ Whenever a new version of utPLSQL or a new version of utPLSQL-cli is available, ## Running unit tests -Currently we use two forms of unit tests in our CI build: -- sql scripts as unit tests in the `old_tests` directory -- utPLSQL v3 unit tests in the `test` directory +utPLSQL v3 unit tests are located in the `test` directory Before you push any changes and create a pull request to the utPLSQL project repository, make sure that all of the tests are executing successfully in your local environment. @@ -146,18 +143,13 @@ Every new functionality needs to be documented by unit tests that cover both hap > We do our best to keep utPLSQL covered with unit tests. > Lack of sufficient unit testing is a perfect reason for PR to be rejected. -To suite of legacy unit tests execute: -```bash -development/env.sh -old_tests/runAll.sh -``` To run a full suite of unit tests execute: ```bash development/env.sh test/install_and_run_tests.sh ``` -You can review the results of tests as well as see information about code coverage in `./old_tests/coverage.html, ./coverage.html` files. +You can review the results of tests as well as see information about code coverage in `./coverage.html` file. ## Modules diff --git a/LICENSE b/LICENSE index c024abb72..640d46628 100644 --- a/LICENSE +++ b/LICENSE @@ -187,7 +187,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2016 utPLSQL Project + Copyright 2016 - 2019 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/VERSION b/VERSION index ed4f9d9f8..5fcdcb942 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v3.1.3-develop +v3.1.14-develop diff --git a/development/cleanup.sh b/development/cleanup.sh index 3b6e22e53..65f3ab0c1 100755 --- a/development/cleanup.sh +++ b/development/cleanup.sh @@ -1,16 +1,16 @@ -#!/usr/bin/env bash +#!/bin/bash #goto git root directory git rev-parse && cd "$(git rev-parse --show-cdup)" -. development/env.sh +. ./development/env.sh "${SQLCLI}" sys/${ORACLE_PWD}@//${CONNECTION_STR} AS SYSDBA <<-SQL set echo on begin for x in ( select * from dba_objects - where owner in ( upper('${UT3_RELEASE_VERSION_SCHEMA}'), upper('${UT3_OWNER}') ) + where owner in ( upper('${UT3_RELEASE_VERSION_SCHEMA}'), upper('${UT3_DEVELOP_SCHEMA}') ) and object_name like 'SYS_PLSQL%') loop execute immediate 'drop type '||x.owner||'.'||x.object_name||' force'; @@ -18,19 +18,25 @@ begin end; / -drop user ${UT3_OWNER} cascade; +drop user ${UT3_DEVELOP_SCHEMA} cascade; drop user ${UT3_RELEASE_VERSION_SCHEMA} cascade; -drop user ${UT3_TESTER} cascade; -drop user ${UT3_USER} cascade; +drop user ut3_tester cascade; +drop user ut3_tester_helper cascade; +drop user ut3_user cascade; +drop user ut3_cache_test_owner cascade; +drop user ut3_no_extra_priv_user cascade; +drop user ut3_select_catalog_user cascade; +drop user ut3_select_any_table_user cascade; +drop user ut3_execute_any_proc_user cascade; begin for i in ( - select decode(owner,'PUBLIC','drop public synonym "','drop synonym "'||owner||'"."')|| synonym_name ||'"' drop_orphaned_synonym from dba_synonyms a + select decode(owner,'PUBLIC','drop public synonym "','drop synonym "'||owner||'"."')|| synonym_name ||'"' drop_orphaned_synonym, owner||'.'||synonym_name syn from dba_synonyms a where not exists (select 1 from dba_objects b where (a.table_name=b.object_name and a.table_owner=b.owner or b.owner='SYS' and a.table_owner=b.object_name) ) and a.table_owner not in ('SYS','SYSTEM') ) loop - dbms_output.put_line(i.drop_orphaned_synonym); execute immediate i.drop_orphaned_synonym; + dbms_output.put_line('synonym '||i.syn||' dropped'); end loop; end; / diff --git a/development/install.sh b/development/install.sh index 4104e2672..468bafd38 100755 --- a/development/install.sh +++ b/development/install.sh @@ -1,20 +1,24 @@ -#!/usr/bin/env bash +#!/bin/bash #goto git root directory git rev-parse && cd "$(git rev-parse --show-cdup)" -. development/env.sh +. ./development/env.sh header="******************************************************************************************" if ! development/cleanup.sh; then echo -e ${header}"\nFailed to cleanup utPLSQL environment\n"${header} exit 1 fi -if ! .travis/install.sh; then - echo -e ${header}"\nFailed to install utPLSQL from current branch into ${UT3_OWNER} schema\n"${header} +if ! .github/scripts/install.sh; then + echo -e ${header}"\nFailed to install utPLSQL from current branch into ${UT3_DEVELOP_SCHEMA} schema\n"${header} exit 1 fi -if ! .travis/install_utplsql_release.sh; then +if ! .github/scripts/create_test_users.sh; then + echo -e ${header}"\nFailed to create test users from current branch\n"${header} + exit 1 +fi +if ! .github/scripts/install_utplsql_release.sh; then echo -e ${header}"\nFailed to install utPLSQL from branch ${SELFTESTING_BRANCH} into ${UT3_RELEASE_VERSION_SCHEMA}\n"${header} exit 1 fi diff --git a/old_tests/lib/mystats/README.md b/development/mystats/README.md similarity index 100% rename from old_tests/lib/mystats/README.md rename to development/mystats/README.md diff --git a/old_tests/lib/mystats/mystats.sql b/development/mystats/mystats.sql similarity index 100% rename from old_tests/lib/mystats/mystats.sql rename to development/mystats/mystats.sql diff --git a/old_tests/lib/mystats/mystats_pkg.sql b/development/mystats/mystats_pkg.sql similarity index 100% rename from old_tests/lib/mystats/mystats_pkg.sql rename to development/mystats/mystats_pkg.sql diff --git a/development/refresh_sources.sh b/development/refresh_sources.sh index e051787a1..83518d7cc 100755 --- a/development/refresh_sources.sh +++ b/development/refresh_sources.sh @@ -1,18 +1,18 @@ -#!/usr/bin/env bash +#!/bin/bash #goto git root directory git rev-parse && cd "$(git rev-parse --show-cdup)" -. development/env.sh +. ./development/env.sh -# remove sub-direcotry containing master branch shallow copy +# remove sub-direcotry containing main branch shallow copy rm -rf ${UTPLSQL_DIR:-utPLSQL_latest_release} -# clone utPLSQL master branch from upstream into utPLSQL sub-directory of your project -git clone --depth=1 --branch=${SELFTESTING_BRANCH:-master} https://github.com/utPLSQL/utPLSQL.git ${UTPLSQL_DIR:-utPLSQL_latest_release} +# clone utPLSQL main branch from upstream into utPLSQL sub-directory of your project +git clone --depth=1 --branch=${SELFTESTING_BRANCH:-main} https://github.com/utPLSQL/utPLSQL.git ${UTPLSQL_DIR:-utPLSQL_latest_release} rm -rf utPLSQL-cli/* # download latest release version of utPLSQL-cli -curl -Lk -o utPLSQL-cli.zip https://github.com/utPLSQL/utPLSQL-cli/releases/download/v${UTPLSQL_CLI_VERSION}/utPLSQL-cli.zip +curl -Lk -o utPLSQL-cli.zip https://github.com/utPLSQL/utPLSQL-cli/releases/download/${UTPLSQL_CLI_VERSION}/utPLSQL-cli.zip # unzip utPLSQL-cli and remove the zip file unzip utPLSQL-cli.zip && chmod u+x utPLSQL-cli/bin/utplsql && rm utPLSQL-cli.zip diff --git a/development/refresh_ut3.sh b/development/refresh_ut3.sh old mode 100644 new mode 100755 index 542f5a01c..827af827d --- a/development/refresh_ut3.sh +++ b/development/refresh_ut3.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash #goto git root directory git rev-parse && cd "$(git rev-parse --show-cdup)" @@ -8,7 +8,7 @@ git rev-parse && cd "$(git rev-parse --show-cdup)" cd source "${SQLCLI}" sys/${ORACLE_PWD}@//${CONNECTION_STR} AS SYSDBA <<-SQL -@uninstall ${UT3_OWNER} -@install ${UT3_OWNER} +@uninstall ${UT3_DEVELOP_SCHEMA} +@install ${UT3_DEVELOP_SCHEMA} exit SQL diff --git a/development/releasing.md b/development/releasing.md index added5a92..ac2091632 100644 --- a/development/releasing.md +++ b/development/releasing.md @@ -1,22 +1,28 @@ -The release process is semi-automated. +## Release process -With every build, the build process on Travis updates files with an appropriate version number before deployment into the database. -This step is performed, to confirm that the update of versions works properly. +To create a release follow the below steps -To create a release: - - create release branch from development branch and make sure to name the release branch: `release/vX.Y.Z` - - update, commit and push at least one file change in the release branch, to kickoff a Travis build - - 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) +## Release preparation + - Create a **draft** of a Release with a new tag number `vX.Y.X` sourced from the `develop` branch on [github releases page](https://github.com/utPLSQL/utPLSQL/releases) + - Populate release description using the `Generate release notes` button + - Review the auto-generated release notes and update tem if needed + - Optionally, split the default `## What's Changed` list into `## New features`, `## Enhancements`, `## Bug fixes`. See previous release notes for details + +## Performing a release + - Publish [the previously prepared](#release-preparation) release draft. + - Wait for the [Github Actions `Release`](https://github.com/utPLSQL/utPLSQL/actions/workflows/release.yml) process to complete successfully. The process will upload release artifacts (`zip` and `tar.gz` files along with `md5`) + - After Release build was completed successfully, merge the `develop` branch into `main` branch. At this point, main branch and release tag should be at the same commit version and artifacts should be uploaded into Github release. + - Increase the version number in the `VERSION` file on `develop` branch to open start next release version. + - Clone `utplsql.githug.io` project and: + - Add a new announcement about next version being released in `docs/_posts`. Use previous announcements as a template. Make sure to set date, time and post title properly. + - Add the post to list in `mkdocs.yml` file in root directory of that repository. + - Add the link to the post at the beginning of the `docs/index.md` file. + - Send the announcement on Twitter(X) accoiunt abut utPLSQL release. 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 - - changes to those two files are committed and pushed back to release branch by Travis - - when a release is created, a new tag is added in on the repository and a tag build is executed - - the documentation for new release is published on `utplsql.github.io` and installation archives are added to the tag. + - When a Github release is published, a new tag is added in on the repository and a release build is executed + - With Release action, the documentation for new release is published on `utplsql.github.io` and installation archives are added to the release. -Note: -The sources for release are provided in separate zip files delivered from the Travis build process. -The built zip files include HTML documentation generated from MD files. +# Note: +The utPLSQL installation files are uploaded by the release build process as release artifacts (separate `zip` and `tar.gz` files). +The release artifacts include HTML documentation generated from MD files, sources and tests diff --git a/development/template.env.sh b/development/template.env.sh index 1e90aaed3..7761a70c4 100755 --- a/development/template.env.sh +++ b/development/template.env.sh @@ -1,19 +1,15 @@ -#!/usr/bin/env bash +#!/bin/bash export SQLCLI=sql # For sqlcl client #export SQLCLI=sqlplus # For sqlplus client -export CONNECTION_STR=127.0.0.1:1521/xe # Adjust the connect string +export CONNECTION_STR=127.0.0.1:1521/xe ORACLE_VERSION=11g-r2-xe# Adjust the connect string export ORACLE_PWD=oracle # Adjust your local SYS password -export UTPLSQL_CLI_VERSION="3.0.4" +export UTPLSQL_CLI_VERSION="3.1.6" export SELFTESTING_BRANCH=develop export UTPLSQL_DIR="utPLSQL_latest_release" -export UT3_OWNER=ut3 -export UT3_OWNER_PASSWORD=ut3 -export UT3_RELEASE_VERSION_SCHEMA=ut3_latest_release -export UT3_TESTER=ut3_tester -export UT3_TESTER_PASSWORD=ut3 +export UT3_DEVELOP_SCHEMA=UT3_DEVELOP +export UT3_DEVELOP_SCHEMA_PASSWORD=ut3 +export UT3_RELEASE_VERSION_SCHEMA=UT3 +export UT3_RELEASE_VERSION_SCHEMA_PASSWORD=ut3 export UT3_TABLESPACE=users -export UT3_USER="UT3\$USER#" -export UT3_USER_PASSWORD=ut3 - diff --git a/development/utplsql_style_check.sql b/development/utplsql_style_check.sql index 71c419806..00d562541 100644 --- a/development/utplsql_style_check.sql +++ b/development/utplsql_style_check.sql @@ -40,8 +40,8 @@ select i.name, i.type, i.object_name, i.object_type, i.usage, i.line, i.col, cou and i.usage_context_id = p.usage_id where i.type like 'VARIABLE' and i.usage = 'DECLARATION' and i.object_type not in ('TYPE') - and (i.name not like 'L#_%' escape '#' and p.type in ('PROCEDURE','FUNCTION','ITERATOR') - or i.name not like 'G#_%' escape '#' and p.type not in ('PROCEDURE','FUNCTION','ITERATOR')) + and (i.name not like 'L#_%' escape '#' and p.type in ('PROCEDURE','FUNCTION','ITERATOR','TRIGGER') + or i.name not like 'G#_%' escape '#' and p.type not in ('PROCEDURE','FUNCTION','ITERATOR','TRIGGER')) and p.type != 'RECORD' order by object_name, object_type, line, col ; diff --git a/docs/about/authors.md b/docs/about/authors.md index 55f85642d..499398993 100644 --- a/docs/about/authors.md +++ b/docs/about/authors.md @@ -1,3 +1,4 @@ +![version](https://img.shields.io/badge/version-v3.1.14.4206--develop-blue.svg) ### utPLSQL v3 Major Contributors @@ -7,11 +8,11 @@ | ---------------- | -------------- | David Pyke | [Shoelace](https://github.com/Shoelace) | Jacek Gebal | [jgebal](https://github.com/jgebal) +| Lukasz Wasylow | [lwasylow](https://github.com/lwasylow/) | Pavel Kaplya | [Pazus](https://github.com/Pazus) | Robert Love | [rlove](https://github.com/rlove) -| Vinicius Avellar | [viniciusam](https://github.com/viniciusam/) | Samuel Nitsche | [pesse](https://github.com/pesse/) -| Lukasz Wasylow | [lwasylow](https://github.com/lwasylow/) +| Vinicius Avellar | [viniciusam](https://github.com/viniciusam/) diff --git a/docs/about/license.md b/docs/about/license.md index aef69c41e..03cc286eb 100644 --- a/docs/about/license.md +++ b/docs/about/license.md @@ -1,3 +1,5 @@ +![version](https://img.shields.io/badge/version-v3.1.14.4206--develop-blue.svg) + # Version Information **utPLSQL version 3** is licensed under diff --git a/docs/about/project-details.md b/docs/about/project-details.md index 3ef58c76c..5579a943b 100644 --- a/docs/about/project-details.md +++ b/docs/about/project-details.md @@ -1,8 +1,10 @@ +![version](https://img.shields.io/badge/version-v3.1.14.4206--develop-blue.svg) + # utPLSQL Project Details [![chat](http://img.shields.io/badge/GitHub_Project-Active-blue.svg)](https://github.com/utPLSQL/utPLSQL) [![license](http://img.shields.io/badge/license-apache%202.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0) -[![chat](http://img.shields.io/badge/chat-slack-blue.svg)](http://utplsql-slack-invite.herokuapp.com/) +[![chat](http://img.shields.io/badge/chat-slack-blue.svg)](https://join.slack.com/t/utplsql/shared_invite/zt-xwm68udy-4cF_3PNEyczYEbWr38W5ww) [![twitter](https://img.shields.io/twitter/follow/utPLSQL.svg?style=social&label=Follow)](https://twitter.com/utPLSQL) diff --git a/docs/about/support.md b/docs/about/support.md index 579795528..6d68864bd 100644 --- a/docs/about/support.md +++ b/docs/about/support.md @@ -1,4 +1,6 @@ +![version](https://img.shields.io/badge/version-v3.1.14.4206--develop-blue.svg) + # How to get support - Feel free to post questions, bugs or issues in the [issues area of GitHub](https://github.com/utPLSQL/utPLSQL/issues) -- Join developers at the [utPLSQL team](http://utplsql-slack-invite.herokuapp.com) on [Slack](https://slack.com/) +- [Join](https://join.slack.com/t/utplsql/shared_invite/zt-xwm68udy-4cF_3PNEyczYEbWr38W5ww) developers team on [utPLSQL Slack](https://utplsql.slack.com/) diff --git a/docs/assets/favicon.png b/docs/assets/favicon.png new file mode 100644 index 000000000..7c34109d0 Binary files /dev/null and b/docs/assets/favicon.png differ diff --git a/docs/assets/icon-transparent.png b/docs/assets/icon-transparent.png new file mode 100644 index 000000000..6e4534aad Binary files /dev/null and b/docs/assets/icon-transparent.png differ diff --git a/docs/compare_version2_to_3.md b/docs/compare_version2_to_3.md new file mode 100644 index 000000000..5f53e41d4 --- /dev/null +++ b/docs/compare_version2_to_3.md @@ -0,0 +1,56 @@ +For version 3 has been a complete rewrite of the framework, the way it can be used is different to +the previous versions, but also more in line with other modern unit-testing frameworks like JUnit and RSpec. + +There is a [migration tool](https://github.com/utPLSQL/utPLSQL-v2-v3-migration) that can help you to migrate your existing utPLSQL v2 tests to the v3 capabilities. + +# Feature comparison + +| Feature | Version 2 | Version 3 | +| -------------------------------------- | ---------------------- | ---------------------- | +| Easy to install | Yes | Yes | +| Documentation | Yes | Yes | +| License | GPL v2 | Apache 2.0 | +| **Tests Creation** | | | +| Declarative test configuration | No | Yes - Annotations1| +| Tests as Packages | Yes | Yes | +| Multiple Tests in a single Package | Yes | Yes | +| Optional Setup/Teardown | No | Yes | +| Different Setup/Teardown
For Each Test in a Single Package| No | Yes - Annotations1 | +| Suite Definition Storage | Tables | Package - Annotations1 | +| Multiple Suites | Yes | Yes | +| Suites can contain Suites | No | Yes | +| Automatic Test detection | No | Yes - Annotations1| +| Unconstrained naming of Test packages | No - prefixes | Yes - name not relevant| +| Require Prefix on Test procedures | No - prefixes | Yes - name not relevant| +| Auto Compilation of Tests | Yes | No (Let us know if you use this) | +| Assertion Library | 30 assertions2 | 26 matchers (13 + 13 negated) | +| Extendable assertions | No | Yes - custom matchers | +| PLSQL Record Assertions | generated code through **utRecEq** Package | [possible on Oracle 12c+](https://oracle-base.com/articles/12c/using-the-table-operator-with-locally-defined-types-in-plsql-12cr1) using [cursor matchers](userguide/expectations.md#comparing-cursors)| +| Test Skeleton Generation | Yes | No (Let us know if you use this) | +| **Test Execution3** | | | +| Single Test Package Execution | Yes | Yes | +| Single Test Procedure Execution | No | Yes | +| Test Suite Execution | Yes | Yes | +| Subset of Suite Execution | No | Yes | +| Multiple Suite Execution | No | Yes | +| Organizing Suites into hierarchies | No | Yes | +| **Code Coverage Reporting** | No | Yes | +| Html Coverage Report | No | Yes | +| Sonar XML Coverage Report | No | Yes | +| Coveralls Json Coverage Report | No | Yes | +| Framework Transaction Control | No | Yes - Annotations1 | +| **Test Output** | | | +| Real-time test execution progress reporting | No | Yes | +| Multiple Output Reporters can be used during test execution | No| Yes | +| DBMS_OUTPUT | Yes | Yes (clean formatting) | +| File | Yes (to db server only)| Yes (on client side) | +| Stored in Table | Yes | No (can be added as custom reporter) | +| XUnit format support | No | Yes | +| HTML Format | Yes | No | +| Custom Output reporter | Yes-needs configuration| Yes - no config needed | + +1 Annotations are specially formatted comments in your package specification. This enables *declarative* test configuration that is coupled with the source code. See Documentation for more details. + +2 **utAssert2** package - Contains 59 Assertions - 2 Not implemented = 57, 28 are duplicated only change on outcome_in parameter 57-28 = 29, **utPipe** package - Contains 1 Assertion 29 + 1 = 30 + +3 Test execution comparison is in a single call so the results are combined. We know it was always possible to group in any way with multiple calls. But that may not be desired under a CI system where you want a single JUnit XML Output. diff --git a/docs/images/supported_by_redgate_100.png b/docs/images/supported_by_redgate_100.png new file mode 100644 index 000000000..ea9f93ac5 Binary files /dev/null and b/docs/images/supported_by_redgate_100.png differ diff --git a/docs/images/utPLSQL-testing-framework-transparent_120.png b/docs/images/utPLSQL-testing-framework-transparent_120.png new file mode 100644 index 000000000..98a24faf0 Binary files /dev/null and b/docs/images/utPLSQL-testing-framework-transparent_120.png differ diff --git a/docs/images/venn21.gif b/docs/images/venn21.gif new file mode 100644 index 000000000..0efecae07 Binary files /dev/null and b/docs/images/venn21.gif differ diff --git a/docs/images/venn22.gif b/docs/images/venn22.gif new file mode 100644 index 000000000..52768b71f Binary files /dev/null and b/docs/images/venn22.gif differ diff --git a/docs/index.md b/docs/index.md index 693c8076b..b277c9d16 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,35 +1,23 @@ -# Introduction to utPLSQL +![version](https://img.shields.io/badge/version-v3.1.14.4206--develop-blue.svg) + +## What is utPLSQL utPLSQL is a Unit Testing framework for Oracle PL/SQL. The framework follows industry standards and best patterns of modern Unit Testing frameworks like [JUnit](http://junit.org/junit4/) and [RSpec](http://rspec.info/) + +## Demo project + +Have a look at [utPLSQL demo project](https://github.com/utPLSQL/utPLSQL-demo-project/) to see: - - User Guide - - [Installation](userguide/install.md) - - [Getting Started](userguide/getting-started.md) - - [Annotations](userguide/annotations.md) - - [Expectations](userguide/expectations.md) - - [Advanced data comparison](userguide/advanced_data_comparison.md) - - [Running unit tests](userguide/running-unit-tests.md) - - [Testing best pracitces](userguide/best-practices.md) - - [Upgrade utPLSQL](userguide/upgrade.md) - - Reporting - - [Using reporters](userguide/reporters.md) - - [Reporting errors](userguide/exception-reporting.md) - - [Code coverage](userguide/coverage.md) - - [Cheat-sheet](https://www.cheatography.com/jgebal/cheat-sheets/utplsql-v3-1-2/#downloads) - - About - - [Project Details](about/project-details.md) - - [License](about/license.md) - - [Support](about/support.md) - - [Authors](about/authors.md) - -# Demo project - -Have a look at our [demo project](https://github.com/utPLSQL/utPLSQL-demo-project/). - -It uses [Travis CI](https://travis-ci.org/utPLSQL/utPLSQL-demo-project) to build on every commit, runs all tests, publishes test results and code coverage to [SonarQube](https://sonarqube.com/dashboard?id=utPLSQL%3AutPLSQL-demo-project%3Adevelop). - -# Three steps +- sample code and tests +- demo of deployment automation that leverages: + - Flyway / Liquidbase for scripting and deployment of DB changes + - Docker container with Oracle XE Database + - GitHub Actions and Azure Pipelines to orchestrate the deployment and testing process + - utPLSQL framework for writhing, execution of tests as well as reporting test results and code coverage + - [Sonar]((https://sonarcloud.io/project/overview?id=utPLSQL:utPLSQL-demo-project).) for code quality gate, test results and code coverage reporting + +## Three steps With just three simple steps you can define and run your unit tests for PLSQL code. @@ -44,22 +32,22 @@ Here is how you can simply create tested code, unit tests and execute the tests Check out the sections on [annotations](userguide/annotations.md) and [expectations](userguide/expectations.md) to see how to define your tests. -# Command line +## Command line You can use the utPLSQL command line client [utPLSQL-cli](https://github.com/utPLSQL/utPLSQL-cli) to run tests without the need for Oracle Client or any IDE like SQLDeveloper/TOAD etc. Amongst many benefits they provide ability to: + * see the progress of test execution for long-running tests - real-time reporting * use many reporting formats simultaneously and save reports to files (publish) * map your project source files and test files into database objects -Just download the [latest client](https://github.com/utPLSQL/utPLSQL-cli/releases/latest), download Oracle jdbc driver you are good to go. +Download the [latest client](https://github.com/utPLSQL/utPLSQL-cli/releases/latest) and you are good to go. See [project readme](https://github.com/utPLSQL/utPLSQL-cli/blob/develop/README.md) for details. -# Coverage - -If you want to have code coverage gathered on your code , it's best to use `ut_run` to execute your tests with multiple reporters and have both test execution report as well as coverage report saved to a file. +## Coverage +It is best to use utPLSQL-cli or execute tests and gather code coverage from command line. Check out the [coverage documentation](userguide/coverage.md) for options of coverage reporting diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css new file mode 100644 index 000000000..7f05ab831 --- /dev/null +++ b/docs/stylesheets/extra.css @@ -0,0 +1,12 @@ +[data-md-color-scheme="default"] { + --md-primary-fg-color: #2f8bff; + --md-accent-fg-color: #1f5db0; + --md-accent-fg-color--transparent: #1f5db0; +} + +[data-md-color-scheme="slate"] { + --md-hue: 200; + --md-primary-fg-color: #2f8bff; + --md-accent-fg-color: #1f5db0; + --md-accent-fg-color--transparent: #1f5db0; +} diff --git a/docs/userguide/advanced_data_comparison.md b/docs/userguide/advanced_data_comparison.md index 3eb45fe50..45fca1871 100644 --- a/docs/userguide/advanced_data_comparison.md +++ b/docs/userguide/advanced_data_comparison.md @@ -1,3 +1,5 @@ +![version](https://img.shields.io/badge/version-v3.1.14.4206--develop-blue.svg) + # Advanced data comparison utPLSQL expectations incorporates advanced data comparison options when comparing compound data-types: @@ -5,16 +7,21 @@ utPLSQL expectations incorporates advanced data comparison options when comparin - refcursor - object type - nested table and varray +- json data-types -Advanced data-comparison options are available for the [`equal`](expectations.md#equal) matcher. +Advanced data-comparison options are available for the [`equal`](expectations.md#equal) and [`contain`](expectations.md#include--contain) matcher. -## Syntax +Syntax ``` ut.expect( a_actual {data-type} ).to_( equal( a_expected {data-type})[.extendend_option()[.extendend_option()[...]]]); ut.expect( a_actual {data-type} ).not_to( equal( a_expected {data-type})[.extendend_option()[.extendend_option()[...]]]) ); ut.expect( a_actual {data-type} ).to_equal( a_expected {data-type})[.extendend_option()[.extendend_option()[...]]]); ut.expect( a_actual {data-type} ).not_to_equal( a_expected {data-type})[.extendend_option()[.extendend_option()[...]]] ); + ut.expect( a_actual {data-type} ).to_( contain( a_expected {data-type})[.extendend_option()[.extendend_option()[...]]]); + ut.expect( a_actual {data-type} ).not_to( contain( a_expected {data-type})[.extendend_option()[.extendend_option()[...]]]) ); + ut.expect( a_actual {data-type} ).to_contain( a_expected {data-type})[.extendend_option()[.extendend_option()[...]]]); + ut.expect( a_actual {data-type} ).not_to_contain( a_expected {data-type})[.extendend_option()[.extendend_option()[...]]]); ``` `extended_option` can be one of: @@ -23,28 +30,26 @@ Advanced data-comparison options are available for the [`equal`](expectations.md - `exclude(a_items varchar2)` - item or comma separated list of items to exclude - `include(a_items ut_varchar2_list)` - table of items to include - `exclude(a_items ut_varchar2_list)` - table of items to exclude - - `unordered` - perform compare on unordered set of data, return only missing or actual - - `join_by(a_columns varchar2)` - columns or comma seperated list of columns to join two cursors by + - `unordered` - ignore order of data sets when comparing data. Default when comparing data-sets with `to_contain` + - `join_by(a_columns varchar2)` - column or comma separated list of columns to join two cursors by - `join_by(a_columns ut_varchar2_list)` - table of columns to join two cursors by + - `unordered_columns` / `uc` - ignore the ordering of columns / attributes in compared data-sets. Column/attribute names will be used to identify data to be compared and the position will be ignored. Each item in the comma separated list can be: - a column name of cursor to be compared - an attribute name of object type to be compared - an attribute name of object type within a table of objects to be compared -- an [XPath](http://zvon.org/xxl/XPathTutorial/Output/example1.html) expression representing column/attribute - Include and exclude option will not support implicit colum names that starts with single quota, or in fact any other special characters e.g. <, >, & Each element in `ut_varchar2_list` nested table can be an item or a comma separated list of items. When specifying column/attribute names, keep in mind that the names are **case sensitive**. -**XPath expressions with comma are not supported.** - ## Excluding elements from data comparison -Consider the following example -```sql -procedure test_cursors_skip_columns is +Consider the following examples +```sql linenums="1" +declare l_expected sys_refcursor; l_actual sys_refcursor; begin @@ -52,33 +57,76 @@ begin open l_actual for select sysdate "ADate", d.* from user_tables d; ut.expect( l_actual ).to_equal( l_expected ).exclude( 'IGNORE_ME,ADate' ); end; +/ +declare + l_expected sys_refcursor; + l_actual sys_refcursor; +begin + open l_expected for select 'text' ignore_me, d.* from user_tables d where rownum = 1; + open l_actual for select sysdate "ADate", d.* from user_tables d; + ut.expect( l_actual ).to_contain( l_expected ).exclude( 'IGNORE_ME,ADate' ); +end; +/ +``` +Produces: ``` +SUCCESS + Actual: refcursor [ count = 23 ] was expected to equal: refcursor [ count = 23 ] -Columns 'ignore_me' and "ADate" will get excluded from cursor comparison. -The cursor data is equal, when those columns are excluded. +SUCCESS + Actual: refcursor [ count = 23 ] was expected to contain: refcursor [ count = 1 ] +``` + +Columns 'ignore_me' and "ADate" will get excluded from data comparison. +The actual data is equal/contains expected, when those columns are excluded. -This option is useful in scenarios, when you need to exclude incomparable/unpredictable column data like CREATE_DATE of a record that is maintained by default value on a table column. +**Note** +>This option is useful in scenarios, when you need to exclude incomparable/unpredictable column data like CREATE_DATE of a record that is maintained by default value on a table column. ## Selecting columns for data comparison Consider the following example -```sql -procedure include_columns_as_csv is - l_actual sys_refcursor; - l_expected sys_refcursor; +```sql linenums="1" +declare + l_actual sys_refcursor; + l_expected sys_refcursor; begin - open l_expected for select rownum as rn, 'a' as "A_Column", 'x' SOME_COL from dual a connect by level < 4; - open l_actual for select rownum as rn, 'a' as "A_Column", 'x' SOME_COL, a.* from all_objects a where rownum < 4; - ut.expect( l_actual ).to_equal( l_expected ).include( 'RN,A_Column,SOME_COL' ); + open l_expected for select rownum as rn, 'a' as "A_Column", 'x' SOME_COL from dual a connect by level < 4; + open l_actual for select rownum as rn, 'a' as "A_Column", 'x' SOME_COL, a.* from all_objects a where rownum < 4; + ut.expect( l_actual ).to_equal( l_expected ).include( 'RN,A_Column,SOME_COL' ); +end; +/ +declare + l_actual sys_refcursor; + l_expected sys_refcursor; +begin + open l_expected for select rownum as rn, 'a' as "A_Column", 'x' SOME_COL from dual a connect by level < 4; + open l_actual for select rownum as rn, 'a' as "A_Column", 'x' SOME_COL, a.* from all_objects a where rownum < 6; + ut.expect( l_actual ).to_contain( l_expected ).include( 'RN,A_Column,SOME_COL' ); end; +/ +``` +Produces: +``` +SUCCESS + Actual: refcursor [ count = 3 ] was expected to equal: refcursor [ count = 3 ] + +SUCCESS + Actual: refcursor [ count = 5 ] was expected to contain: refcursor [ count = 3 ] ``` +Only columns `RN`,`A_Column` and `SOME_COL ` will be included in data comparison. +The actual data is equal/contains expected, when only those columns are included. + +**Note** +>This option can be useful in scenarios where you need to narrow-down the scope of test so that the test is only focused on very specific data. + ## Combining include/exclude options You can chain the advanced options in an expectation and mix the `varchar2` with `ut_varchar2_list` arguments. -When doing so, the fianl list of items to include/exclude will be a concatenation of all items. +When doing so, the final list of items to include/exclude will be a concatenation of all items. -```sql -procedure include_columns_as_csv is +```sql linenums="1" +declare l_actual sys_refcursor; l_expected sys_refcursor; begin @@ -89,156 +137,382 @@ begin .include( ut_varchar2_list( 'A_Column', 'SOME_COL' ) ) .exclude( 'SOME_COL' ); end; +/ +declare + l_actual sys_refcursor; + l_expected sys_refcursor; +begin + open l_expected for select rownum as rn, 'a' as "A_Column", 'x' SOME_COL from dual a connect by level < 4; + open l_actual for select rownum as rn, 'a' as "A_Column", 'Y' SOME_COL, a.* from all_objects a where rownum < 6; + ut.expect( l_actual ).to_contain( l_expected ) + .include( 'RN') + .include( ut_varchar2_list( 'A_Column', 'SOME_COL' ) ) + .exclude( 'SOME_COL' ); +end; +/ +``` + +Results: ``` +SUCCESS + Actual: refcursor [ count = 3 ] was expected to equal: refcursor [ count = 3 ] -Only the columns 'RN', "A_Column" will be compared. Column 'SOME_COL' is excluded. +SUCCESS + Actual: refcursor [ count = 5 ] was expected to contain: refcursor [ count = 3 ] +``` -This option can be useful in scenarios where you need to narrow-down the scope of test so that the test is only focused on very specific data. +Example of `include / exclude` for anydata.convertCollection -##Unordered +```sql linenums="1" +create or replace type person as object( + name varchar2(100), + age integer +) +/ +create or replace type people as table of person +/ -Unordered option allows for quick comparison of two cursors without need of ordering them in any way. +declare + l_actual people := people(person('Matt',45)); + l_expected people :=people(person('Matt',47)); +begin + ut3.ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)).include('NAME'); +end; -Result of such comparison will be limited to only information about row existing or not existing in given set without actual information about exact differences. +declare + l_actual people := people(person('Matt',45)); + l_expected people :=people(person('Matt',47)); +begin + ut3.ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)).exclude('AGE'); +end; +declare + l_actual people := people(person('Matt',45)); + l_expected people :=people(person('Matt',47)); +begin + ut3.ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)).include('AGE'); +end; +/ +``` +Results: +``` +SUCCESS + Actual: ut3.people [ count = 1 ] was expected to equal: ut3.people [ count = 1 ] -```sql -procedure unordered_tst is - l_actual sys_refcursor; - l_expected sys_refcursor; +SUCCESS + Actual: ut3.people [ count = 1 ] was expected to equal: ut3.people [ count = 1 ] + +FAILURE + Actual: ut3.people [ count = 1 ] was expected to equal: ut3.people [ count = 1 ] + Diff: + Rows: [ 1 differences ] + Row No. 1 - Actual: 45 + Row No. 1 - Expected: 47 + at "anonymous block", line 5 + +``` + +## Unordered + +Unordered option allows for quick comparison of two compound data types without need of ordering them in any way. + +Result of such comparison will be limited to only information about row existing or not existing in given set without actual information about exact differences. + +```sql linenums="1" +declare + l_actual sys_refcursor; + l_expected sys_refcursor; begin - open l_expected for select username, user_id from all_users + open l_expected for + select username, user_id from all_users union all select 'TEST' username, -600 user_id from dual order by 1 desc; - open l_actual for select username, user_id from all_users + open l_actual for + select username, user_id from all_users union all select 'TEST' username, -610 user_id from dual order by 1 asc; - ut.expect( l_actual ).to_equal( l_expected ).unordered; + ut.expect( l_actual ).to_equal( l_expected ).unordered; end; +/ ``` - - Above test will result in two differences of one row extra and one row missing. - - - -```sql - Diff: - Rows: [ 2 differences ] - Missing: TEST-600 - Extra: TEST-610 ``` - - - +FAILURE + Actual: refcursor [ count = 29 ] was expected to equal: refcursor [ count = 29 ] + Diff: + Rows: [ 2 differences ] + Extra: TEST-610 + Missing: TEST-600 + at "anonymous block", line 15 +``` +**Note** +> Consider using `join_by( columns... )` over `unordered()` with the `equal` matcher. The `join_by` method is much faster at performing data comparison. +> +> The `contain` matcher is not considering the order of the compared data-sets. Using `unordered` makes no difference (it's default). ## Join By option -You can now join two cursors by defining a primary key or composite key that will be used to uniquely identify and compare rows. This option allows us to exactly show which rows are missing, extra and which are different without ordering clause. In the situation where the join key is not unique, join will partition set over rows with a same key and join on row number as well as given join key. The extra rows or missing will be presented to user as well as not matching rows. +The `join_by` syntax enables comparison of unordered compound data types by joining data using specified columns. -Join by option can be used in conjunction with include or exclude options. However if any of the join keys is part of exclude set, comparison will fail and report to user that sets could not be joined on specific key (excluded). +You can join two compound data types by defining join column(s) that will be used to uniquely identify and compare data rows. +With this option, framework is able to identify which rows are missing, which are extra and which are different without need to have both cursors uniformly ordered. +When the specified join column(s) are not unique, join will partition set over rows with the same key and join on row number as well as given join key. +The extra or missing rows will be presented to user as well as all non-matching rows. -```sql -procedure join_by_username is - l_actual sys_refcursor; - l_expected sys_refcursor; +Join by option can be used in conjunction with include or exclude options. +However if any of the join keys is part of exclude set, comparison will fail and report to user that sets could not be joined on specific key, as the key was excluded. + +```sql linenums="1" +declare + l_actual sys_refcursor; + l_expected sys_refcursor; begin - open l_expected for select username, user_id from all_users + open l_expected for + select username, user_id from all_users union all select 'TEST' username, -600 user_id from dual order by 1 desc; - open l_actual for select username, user_id from all_users + open l_actual for + select username, user_id from all_users union all select 'TEST' username, -610 user_id from dual order by 1 asc; - ut.expect( l_actual ).to_equal( l_expected ).join_by('USERNAME'); + ut.expect( l_actual ).to_equal( l_expected ).join_by('USERNAME'); end; +/ ``` -This will show you difference in row 'TEST' regardless of order. -```sql - Rows: [ 1 differences ] - PK TEST - Expected: -600 - PK TEST - Actual: -610 +Above test will result in a difference in row 'TEST' regardless of data order. +``` +FAILURE + Actual: refcursor [ count = 29 ] was expected to equal: refcursor [ count = 29 ] + Diff: + Rows: [ 1 differences ] + PK TEST - Actual: -610 + PK TEST - Expected: -600 + PK TEST - Extra: TEST-610 + at "anonymous block", line 15 ``` -Assumption is that join by is made by column name so that what will be displayed as part of results. +**Note** -Join by options currently doesn't support nested table inside cursor comparison, however is still possible to compare a collection as a whole. +> When using `join_by`, the join column(s) are displayed first (as PK) to help you identify the mismatched rows/columns. -Example. +You can use `join_by` syntax in combination with `contain` matcher. -```sql - procedure compare_collection_in_rec is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_actual_tab ut3.ut_annotated_object; - l_expected_tab ut3.ut_annotated_object; - l_expected_message varchar2(32767); - l_actual_message varchar2(32767); - begin - select ut3.ut_annotated_object('TEST','TEST','TEST', - 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', - ut3.ut_annotations(ut3.ut_annotation(1,'test','test','test'), - ut3.ut_annotation(2,'test','test','test')) - ) - into l_expected_tab from dual; - - --Arrange - open l_actual for select l_actual_tab as nested_table from dual; +```sql linenums="1" +declare + l_actual sys_refcursor; + l_expected sys_refcursor; +begin + open l_actual for select username, user_id from all_users; + open l_expected for + select username, user_id from all_users + union all + select 'TEST' username, -610 user_id from dual; + + ut.expect( l_actual ).to_contain( l_expected ).join_by('USERNAME'); +end; +/ +``` + +Above test will indicate that in actual data-set +```sql linenums="1" +FAILURE + Actual: refcursor [ count = 28 ] was expected to contain: refcursor [ count = 29 ] + Diff: + Rows: [ 1 differences ] + PK TEST - Missing: TEST-610 + at "anonymous block", line 11 +``` - open l_expected for select l_expected_tab as nested_table from dual; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by('NESTED_TABLE/ANNOTATIONS'); +### Joining using multiple columns + +You can specify multiple columns in `join_by` + +```sql linenums="1" +declare + l_actual sys_refcursor; + l_expected sys_refcursor; +begin + open l_expected for + select username, user_id, created from all_users + order by 1 desc; + open l_actual for + select username, user_id, created from all_users + union all + select 'TEST' username, -610 user_id, sysdate from dual + order by 1 asc; + ut.expect( l_actual ).to_equal( l_expected ).join_by('USERNAME, USER_ID'); +end; +/ +``` - end; +Produces: +``` +FAILURE + Actual: refcursor [ count = 29 ] was expected to equal: refcursor [ count = 28 ] + Diff: + Rows: [ 1 differences ] + PK TEST-610 - Extra: TEST-6102019-07-11 + at "anonymous block", line 13 ``` +### Joining using attributes of object in column list +`join_by` allows for joining data by attributes of object from column list of the compared compound data types. -In case when a there is detected collection inside cursor and we cannot join key. Comparison will present a failed joins and also a message about collection being detected. +To reference attribute as PK, use slash symbol `/` to separate nested elements. + +In the below example, cursors are joined using the `NAME` attribute of object in column `SOMEONE` + +```sql linenums="1" +create or replace type person as object( + name varchar2(100), + age integer +) +/ +create or replace type people as table of person +/ + +declare + l_actual sys_refcursor; + l_expected sys_refcursor; +begin + open l_expected for + select person('Jack',42) someone from dual union all + select person('Pat', 44) someone from dual union all + select person('Matt',45) someone from dual; + open l_actual for + select person('Matt',55) someone from dual union all + select person('Pat', 44) someone from dual; + ut.expect( l_actual ).to_equal( l_expected ).join_by( 'SOMEONE/NAME' ); +end; +/ +``` -```sql -Actual: refcursor [ count = 1 ] was expected to equal: refcursor [ count = 1 ] -Diff: - Unable to join sets: - Join key NESTED_TABLE/ANNOTATIONS/TEXT does not exists in expected - Join key NESTED_TABLE/ANNOTATIONS/TEXT does not exists in actual - Please make sure that your join clause is not refferring to collection element +Produces: ``` +FAILURE + Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 3 ] + Diff: + Rows: [ 2 differences ] + PK Matt - Actual: Matt55 + PK Matt - Actual: 55 + PK Matt - Expected: Matt45 + PK Matt - Expected: 45 + PK Jack - Missing: Jack42 + at "anonymous block", line 12 +``` + +**Note** +> `join_by` does not support joining on individual elements of nested table. You can still use data of the nested table as a PK value. +> When collection is referenced in `join_by`, test will fail with appropriate message, as it cannot perform a join. + +```sql linenums="1" +create or replace type person as object( + name varchar2(100), + age integer +) +/ +create or replace type people as table of person +/ + +create or replace package body test_join_by is + procedure test_join_by_collection_elem is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + open l_expected for select people(person('Matt',45)) persons from dual; + open l_actual for select people(person('Matt',45)) persons from dual; + ut.expect( l_actual ).to_equal( l_expected ).join_by('PERSONS/PERSON/NAME'); + end; +end; +/ +``` +``` +FAILURE + Actual: refcursor [ count = 1 ] was expected to equal: refcursor [ count = 1 ] + Diff: + Unable to join sets: + Join key PERSONS/PERSON/NAME does not exists in expected + Join key PERSONS/PERSON/NAME does not exists in actual + Please make sure that your join clause is not refferring to collection element + + at "anonymous block", line 7 +``` +**Note** +>`join_by` option is slower to process as it needs to perform a cursor join. It is still faster than the `unordered`. +## Defining item lists in option -**Please note that .join_by option will take longer to process due to need of parsing via primary keys.** +You may provide items for `include`/`exclude`/`join_by` as a single varchar2 value containing comma-separated list of attributes. -## Defining item as XPath -When using XPath expression, keep in mind the following: +You may provide items for `include`/`exclude`/`join_by` as a a ut_varchar2_list of attributes. -- cursor columns are nested under `` element +**Note** - object type attributes are nested under `` element - nested table and varray items type attributes are nested under `` elements -Example of a valid XPath parameter to include columns: `RN`, `A_Column`, `SOME_COL` in data comparison. -```sql -procedure include_columns_as_xpath is +Example of a valid parameter to include columns: `RN`, `A_Column`, `SOME_COL` in data comparison. +```sql linenums="1" +declare l_actual sys_refcursor; l_expected sys_refcursor; begin open l_expected for select rownum as rn, 'a' as "A_Column", 'x' SOME_COL from dual a connect by level < 4; open l_actual for select rownum as rn, 'a' as "A_Column", 'x' SOME_COL, a.* from all_objects a where rownum < 4; - ut.expect( l_actual ).to_equal( l_expected ).include( '/ROW/RN|/ROW/A_Column|/ROW/SOME_COL' ); + ut.expect( l_actual ).to_equal( l_expected ).include( 'RN,A_Column,SOME_COL' ); + open l_expected for select rownum as rn, 'a' as "A_Column", 'x' SOME_COL from dual a connect by level < 4; + open l_actual for select rownum as rn, 'a' as "A_Column", 'x' SOME_COL, a.* from all_objects a where rownum < 4; + ut.expect( l_actual ).to_equal( l_expected ).include( ut_varchar2_list( 'RN', 'A_Column', 'SOME_COL' ) ); end; +/ +``` + +``` +SUCCESS + Actual: refcursor [ count = 3 ] was expected to equal: refcursor [ count = 3 ] +SUCCESS + Actual: refcursor [ count = 3 ] was expected to equal: refcursor [ count = 3 ] +``` + +## Unordered columns / uc option + +If you need to perform data comparison of compound data types without strictly depending on column order in the returned result-set, use the `unordered_columns` option. +Shortcut name `uc` is also available for that option. + +Expectations that compare compound data type data with `unordered_columns` option, will not fail when columns are ordered differently. + +This option can be useful whn we have no control over the ordering of the column or the column order is not of importance from testing perspective. + +```sql linenums="1" +declare + l_actual sys_refcursor; + l_expected sys_refcursor; +begin + --Arrange + open l_actual for select owner, object_name, object_type from all_objects where owner = user + order by 1,2,3 asc; + open l_expected for select object_type, owner, object_name from all_objects where owner = user + and rownum < 20; + + --Assert + ut.expect(l_actual).to_contain(l_expected).unordered_columns(); +end; +/ +``` + +Produces: +``` +SUCCESS + Actual: refcursor [ count = 348 ] was expected to contain: refcursor [ count = 19 ] ``` diff --git a/docs/userguide/annotations.md b/docs/userguide/annotations.md index d9c731b34..31a91cac2 100644 --- a/docs/userguide/annotations.md +++ b/docs/userguide/annotations.md @@ -1,41 +1,149 @@ -# Annotations +![version](https://img.shields.io/badge/version-v3.1.14.4206--develop-blue.svg) Annotations are used to configure tests and suites in a declarative way similar to modern OOP languages. This way, test configuration is stored along with the test logic inside the test package. -No configuration files or tables are needed. The annotation names are based on popular testing frameworks such as JUnit. +No additional configuration files or tables are needed for test cases. The annotation names are based on popular testing frameworks such as JUnit. The framework runner searches for all the suitable annotated packages, automatically configures suites, forms the suite hierarchy, executes it and reports results in specified formats. -Annotations are interpreted only in the package specification and are case-insensitive. We strongly recommend using lower-case annotations as described in this documentation. +Annotation is defined by: -There are two distinct types of annotations, identified by their location in package: -- Procedure level annotations - placed directly before a procedure (`--%test`, `--%beforeall`, `--%beforeeach` etc.). -- Package level annotations - placed at any place in package except directly before procedure (`--%suite`, `--%suitepath` etc.). +- single line comment `--` (double hyphen) +- followed directly by a `%` (percent) +- followed by annotation name +- followed by optional annotation text placed in single brackets. +All text between first opening bracket and last closing bracket in annotation line is considered to be annotation text + +For example `--%suite(The name of my test suite)` represents `suite` annotation with `The name of my test suite` as annotation text. + +utPLSQL interprets the whole line of annotation and will treat text from the first opening bracket in the line to the last closing bracket in that line as annotation text + +In below example we have a `suite` annotation with `Stuff) -- we should name this ( correctly ` as the annotation text + +`--%suite(Stuff) -- we should name this ( correctly )` + +Do not place comments within annotation line to avoid unexpected behaviors. + +**Note:** +>Annotations are interpreted only in the package specification and are case-insensitive. We strongly recommend using lower-case annotations as described in this documentation. + +There are two distinct types of annotations, identified by their location in package. +- package annotations +- procedure annotations + +### Procedure level annotations + +Annotation placed directly before a procedure (`--%test`, `--%beforeall`, `--%beforeeach` etc.). +There **can not** be any empty lines or comments between annotation line and procedure line. +There can be many annotations for a procedure. + +Valid procedure annotations example: +```sql linenums="1" +package test_package is + --%suite + + + --%test() + --%disabled + procedure my_first_procedure; + + $if dbms_db_version.version >= 12 $then --This is ok - annotation before procedure + --%test() + procedure my_first_procedure; + $end + + --A comment goes before annotations + --%test() + procedure my_first_procedure; +end; +``` + +Invalid procedure annotations examples: +```sql linenums="1" +package test_package is + --%suite + + --%test() --This is wrong as there is an empty line between procedure and annotation + + procedure my_first_procedure; + + --%test() + --This is wrong as there is a comment line between procedure and annotation + procedure proc1; + + --%test() --This is wrong as there is a compiler directive between procedure and annotation + $if dbms_db_version.version >= 12 $then + procedure proc_12; + $end + + --%test() + -- procedure another_proc; + /* The above is wrong as the procedure is commented out + and annotation is not procedure annotation anymore */ + +end; +``` + +### Package level annotations + +Those annotations placed at any place in package except directly before procedure (`--%suite`, `--%suitepath` etc.). We strongly recommend putting package level annotations at the very top of package except for the `--%context` annotations (described below) +Valid package annotations example: +```sql linenums="1" +package test_package is + + --%suite + + --%suitepath(org.utplsql.example) + + --%beforeall(some_package.some_procedure) + + --%context + + --%test() + procedure my_first_procedure; + --%endcontext +end; +``` + +Invalid package annotations examples: +```sql linenums="1" +package test_package is + --%suite --This is wrong as suite annotation is not a procedure annotation + procedure irrelevant; + + --%context --This is wrong as there is no empty line between package level annotation and procedure level annotation + --%test() + procedure my_first_procedure; + +end; +``` ## Supported annotations -| Annotation |Level| Description | -| --- | --- | --- | -| `--%suite()` | Package | Mandatory. Marks package as a test suite. Optional suite description can be provided (see `displayname`). | -| `--%suitepath()` | Package | Similar to java package. The annotation allows logical grouping of suites into hierarchies. | -| `--%displayname()` | Package/procedure | Human-readable and meaningful description of a context/suite/test. Provides description to a `context` when used within `context`. When used with `test` or `suite` annotation, overrides the `` provided with `suite`/`test`. | -| `--%test()` | Procedure | Denotes that the annotated procedure is a unit test procedure. Optional test description can by provided (see `displayname`). | -| `--%throws([,...])`| Procedure | Denotes that the annotated test procedure must throw one of the exceptions provided. Supported forms of exceptions are: numeric literals, numeric contant names, exception constant names, predefined Oracle exception names. | -| `--%beforeall` | Procedure | Denotes that the annotated procedure should be executed once before all elements of the suite. | -| `--%beforeall([[.].][,...])` | Package | Denotes that the mentioned procedure(s) should be executed once before all elements of the suite. | -| `--%afterall` | Procedure | Denotes that the annotated procedure should be executed once after all elements of the suite. | -| `--%afterall([[.].][,...])` | Package | Denotes that the mentioned procedure(s) should be executed once after all elements of the suite. | -| `--%beforeeach` | Procedure | Denotes that the annotated procedure should be executed before each `%test` procedure in the suite. | -| `--%beforeeach([[.].][,...])` | Package | Denotes that the mentioned procedure(s) should be executed before each `%test` procedure in the suite. | -| `--%aftereach` | Procedure | Denotes that the annotated procedure should be executed after each `%test` procedure in the suite. | -| `--%aftereach([[.].][,...])` | Package | Denotes that the mentioned procedure(s) should be executed after each `%test` procedure in the suite. | -| `--%beforetest([[.].][,...])` | Procedure | Denotes that mentioned procedure(s) should be executed before the annotated `%test` procedure. | -| `--%aftertest([[.].][,...])` | Procedure | Denotes that mentioned procedure(s) should be executed after the annotated `%test` procedure. | -| `--%rollback()` | Package/procedure | Defines transaction control. Supported values: `auto`(default) - a savepoint is created before invocation of each "before block" is and a rollback to specific savepoint is issued after each "after" block; `manual` - rollback is never issued automatically. Property can be overridden for child element (test in suite) | -| `--%disabled` | Package/procedure | Used to disable a suite or a test. Disabled suites/tests do not get executed, they are however marked and reported as disabled in a test run. | -| `--%context()` | Package | Denotes start of a named context (sub-suite) in a suite package | -| `--%endcontext` | Package | Denotes end of a nested context (sub-suite) in a suite package | +| Annotation | Level | Description | +|------------------------------------------------------------|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `--%suite( )` | Package | Mandatory. Marks package as a test suite. Optional suite description can be provided (see `displayname`). | +| `--%suitepath( )` | Package | Similar to java package. The annotation allows logical grouping of suites into hierarchies. | +| `--%displayname( )` | Package/procedure | Human-readable and meaningful description of a context/suite/test. Overrides the `` provided with `suite`/`test`/`context` annotation. This annotation is redundant and might be removed in future releases. | +| `--%test( )` | Procedure | Denotes that the annotated procedure is a unit test procedure. Optional test description can be provided (see `displayname`). | +| `--%throws( [,...] )` | Procedure | Denotes that the annotated test procedure must throw one of the exceptions provided. Supported forms of exceptions are: numeric literals, numeric constant names, exception constant names, predefined Oracle exception names. | +| `--%beforeall` | Procedure | Denotes that the annotated procedure should be executed once before all elements of the suite. | +| `--%beforeall( [[.].][,...] )` | Package | Denotes that the mentioned procedure(s) should be executed once before all elements of the suite. | +| `--%afterall` | Procedure | Denotes that the annotated procedure should be executed once after all elements of the suite. | +| `--%afterall( [[.].][,...] )` | Package | Denotes that the mentioned procedure(s) should be executed once after all elements of the suite. | +| `--%beforeeach` | Procedure | Denotes that the annotated procedure should be executed before each `%test` procedure in the suite. | +| `--%beforeeach( [[.].][,...] )` | Package | Denotes that the mentioned procedure(s) should be executed before each `%test` procedure in the suite. | +| `--%aftereach` | Procedure | Denotes that the annotated procedure should be executed after each `%test` procedure in the suite. | +| `--%aftereach( [[.].][,...] )` | Package | Denotes that the mentioned procedure(s) should be executed after each `%test` procedure in the suite. | +| `--%beforetest( [[.].][,...] )` | Procedure | Denotes that mentioned procedure(s) should be executed before the annotated `%test` procedure. | +| `--%aftertest( [[.].][,...] )` | Procedure | Denotes that mentioned procedure(s) should be executed after the annotated `%test` procedure. | +| `--%rollback( )` | Package/procedure | Defines transaction control. Supported values: `auto`(default) - a savepoint is created before invocation of each "before block" is and a rollback to specific savepoint is issued after each "after" block; `manual` - rollback is never issued automatically. Property can be overridden for child element (test in suite) | +| `--%disabled( )` | Package/procedure | Used to disable a suite, whole context or a test. Disabled suites/contexts/tests do not get executed, they are however marked and reported as disabled in a test run. The reason that will be displayed next to disabled tests is decided based on hierarchy suites -> context -> test | +| `--%context( )` | Package | Denotes start of a named context (sub-suite) in a suite package an optional description for context can be provided. | +| `--%name( )` | Package | Denotes name for a context. Must be placed after the context annotation and before start of nested context. | +| `--%endcontext` | Package | Denotes end of a nested context (sub-suite) in a suite package | +| `--%tags` | Package/procedure | Used to label a test or a suite for purpose of identification | ### Suite @@ -55,13 +163,13 @@ If the parameters are placed without brackets or with incomplete brackets, they Suite package without description. -```sql +```sql linenums="1" create or replace package test_package as --%suite end; / ``` -```sql +```sql linenums="1" exec ut.run('test_package'); ``` ``` @@ -72,13 +180,13 @@ Finished in .002415 seconds ``` Suite package with description. -```sql +```sql linenums="1" create or replace package test_package as --%suite(Tests for a package) end; / ``` -```sql +```sql linenums="1" exec ut.run('test_package'); ``` ``` @@ -89,14 +197,14 @@ Finished in .001646 seconds ``` When multiple `--%suite` annotations are specified in package, the first annotation will be used and a warning message will appear indicating duplicate annotation. -```sql +```sql linenums="1" create or replace package test_package as --%suite(Tests for a package) --%suite(Bad annotation) end; / ``` -```sql +```sql linenums="1" exec ut.run('test_package'); ``` ``` @@ -114,14 +222,14 @@ Finished in .003318 seconds ``` When `--%suite` annotation is bound to procedure, it is ignored and results in package not getting recognized as test suite. -```sql +```sql linenums="1" create or replace package test_package as --%suite(Tests for a package) procedure some_proc; end; / ``` -```sql +```sql linenums="1" exec ut.run('test_package'); ``` ``` @@ -148,7 +256,7 @@ If `--%test` raises an unhandled exception the following will happen: - test execution will continue uninterrupted for rest of the suite Test procedure without description. -```sql +```sql linenums="1" create or replace package test_package as --%suite(Tests for a package) @@ -161,7 +269,7 @@ create or replace package body test_package as end; / ``` -```sql +```sql linenums="1" exec ut.run('test_package'); ``` ``` @@ -173,7 +281,7 @@ Finished in .004109 seconds ``` Test procedure with description. -```sql +```sql linenums="1" create or replace package test_package as --%suite(Tests for a package) @@ -187,7 +295,7 @@ end; / ``` -```sql +```sql linenums="1" exec ut.run('test_package'); ``` ``` @@ -199,7 +307,7 @@ Finished in .006828 seconds ``` When multiple `--%test` annotations are specified for a procedure, the first annotation will be used and a warning message will appear indicating duplicate annotation. -```sql +```sql linenums="1" create or replace package test_package as --%suite(Tests for a package) @@ -214,7 +322,7 @@ end; / ``` -```sql +```sql linenums="1" exec ut.run('test_package'); ``` ``` @@ -234,12 +342,13 @@ Finished in .008815 seconds ### Disabled Marks annotated suite package or test procedure as disabled. +You can provide the reason why the test is disabled that will be displayed in output. Disabling suite. -```sql +```sql linenums="1" create or replace package test_package as --%suite(Tests for a package) - --%disabled + --%disabled(Reason for disabling suite) --%test(Description of tested behavior) procedure some_test; @@ -257,20 +366,65 @@ end; / ``` -```sql +```sql linenums="1" exec ut.run('test_package'); ``` ``` Tests for a package - Description of tested behavior [0 sec] (DISABLED) - Description of another behavior [0 sec] (DISABLED) + Description of tested behavior [0 sec] (DISABLED - Reason for disabling suite) + Description of another behavior [0 sec] (DISABLED - Reason for disabling suite) Finished in .001441 seconds 2 tests, 0 failed, 0 errored, 2 disabled, 0 warning(s) ``` +Disabling the context(s). +```sql linenums="1" +create or replace package test_package as + --%suite(Tests for a package) + + --%context(Context1) + + --%test(Description of tested behavior) + procedure some_test; + + --%endcontext + + --%context(Context2) + + --%disabled(Reason for disabling context2) + + --%test(Description of another behavior) + procedure other_test; + + --%endcontext +end; +/ +create or replace package body test_package as + + procedure some_test is begin null; end; + + procedure other_test is begin null; end; +end; +/ +``` + +```sql linenums="1" +exec ut.run('test_package'); +``` +``` +Tests for a package + Context1 + Description of tested behavior [.002 sec] + Context2 + Description of another behavior [0 sec] (DISABLED - Reason for disabling context2) + +Finished in .005079 seconds +2 tests, 0 failed, 0 errored, 1 disabled, 0 warning(s) +``` + Disabling individual test(s). -```sql +```sql linenums="1" create or replace package test_package as --%suite(Tests for a package) @@ -278,7 +432,7 @@ create or replace package test_package as procedure some_test; --%test(Description of another behavior) - --%disabled + --%disabled(Reason for disabling test) procedure other_test; end; / @@ -291,13 +445,13 @@ end; / ``` -```sql +```sql linenums="1" exec ut.run('test_package'); ``` ``` Tests for a package Description of tested behavior [.004 sec] - Description of another behavior [0 sec] (DISABLED) + Description of another behavior [0 sec] (DISABLED - Reason for disabling test) Finished in .005868 seconds 2 tests, 0 failed, 0 errored, 1 disabled, 0 warning(s) @@ -308,7 +462,7 @@ Finished in .005868 seconds There are two possible ways to use the `--%beforeall` annotation. As a procedure level annotation: -```sql +```sql linenums="1" --%suite(Some test suite) --%beforeall @@ -320,7 +474,7 @@ procedure some_test; Marks annotated procedure to be executed before all test procedures in a suite. As a package level annotation (not associated with any procedure). -```sql +```sql linenums="1" --%suite(Some test suite) --%beforeall(to_be_executed_before_all, other_package.some_setup) @@ -337,6 +491,7 @@ Indicates that the procedure(s) mentioned as the annotation parameter are to be If `--%beforeall` raises an exception, suite content cannot be safely executed as the setup was not executed successfully for the suite. If `--%beforeall` raises an exception the following will happen: + - the `--%beforeall` procedures that follow the failed one, **will not be executed** - all `--%test` procedures and their `--%beforeeach`, `--%aftereach`, `--%beforetest` and `--%aftertest` procedures within suite package **will not be executed** - all `--%test` procedures **will be marked as failed** @@ -347,7 +502,7 @@ When multiple `--%beforeall` procedures are defined in a suite package, all of t For multiple `--%beforeall` procedures order of execution is defined by annotation position in the package specification. -```sql +```sql linenums="1" create or replace package test_package as --%suite(Tests for a package) @@ -375,9 +530,10 @@ end; / ``` -```sql +```sql linenums="1" exec ut.run('test_package'); ``` + ``` Tests for a package --- SETUP_STUFF invoked --- @@ -391,7 +547,7 @@ Finished in .012292 seconds In the below example a combination pacakge and procedure level `--%beforeall` annotations is used. The order of execution of the beforeall procedures is determined by the annotation position in package. All of the `--%beforeall` procedures get invoked before any test is executed in a suite. - ```sql +```sql linenums="1" create or replace package test_package as --%suite(Tests for a package) @@ -440,12 +596,13 @@ All of the `--%beforeall` procedures get invoked before any test is executed in procedure other_test is begin null; end; end; / - ``` +``` - ```sql +```sql linenums="1" exec ut.run('test_package'); - ``` - ``` +``` + +``` Tests for a package --- INITIAL_SETUP invoked --- --- ANOTHER_SETUP invoked --- @@ -456,11 +613,11 @@ Tests for a package Finished in .018944 seconds 2 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s) - ``` +``` When multiple `--%beforeall` annotations are specified for a procedure, the first annotation will be used and a warning message will appear indicating duplicate annotation. When procedure is annotated as both `--%beforeall` and `--%test`, the procedure will become a test and a warning message will appear indicating invalid annotation combination. -```sql +```sql linenums="1" create or replace package test_package as --%suite(Tests for a package) @@ -491,10 +648,11 @@ When procedure is annotated as both `--%beforeall` and `--%test`, the procedure / ``` - ```sql +```sql linenums="1" exec ut.run('test_package'); - ``` - ``` +``` + +``` Tests for a package --- INITIAL_SETUP invoked --- Description of tested behavior [.003 sec] @@ -512,7 +670,7 @@ Warnings: Finished in .012158 seconds 2 tests, 0 failed, 0 errored, 0 disabled, 2 warning(s) - ``` +``` ### Afterall @@ -520,7 +678,7 @@ Finished in .012158 seconds There are two possible ways to use the `--%afterall` annotation. As a procedure level annotation: -```sql +```sql linenums="1" --%suite(Some test suite) --%afterall @@ -532,7 +690,7 @@ procedure some_test; Marks annotated procedure to be executed after all test procedures in a suite. As a package level annotation (not associated with any procedure). -```sql +```sql linenums="1" --%suite(Some test suite) --%afterall(to_be_executed_after_all, other_package.some_cleanup) @@ -541,11 +699,12 @@ As a package level annotation (not associated with any procedure). procedure some_test; procedure to_be_executed_after_all; - ``` + Indicates that the procedure(s) mentioned as the annotation parameter are to be executed after all test procedures in a suite. If `--%afterall` raises an exception the following will happen: + - a warning will be raised, indicating that `--%afterall` procedure has failed - execution will continue uninterrupted for rest of the suite @@ -558,7 +717,7 @@ For multiple `--%afterall` procedures order of execution is defined by annotatio All rules defined for `--%beforeall` also apply for `--%afterall` annotation. See [beforeall](#Beforeall) for more details. -```sql +```sql linenums="1" create or replace package test_package as --%suite(Tests for a package) @@ -586,9 +745,10 @@ end; / ``` -```sql +```sql linenums="1" exec ut.run('test_package'); ``` + ``` Tests for a package Description of tested behavior [.003 sec] @@ -607,7 +767,7 @@ That means that the procedure will be executed as many times as there are test i There are two possible ways to use the `--%beforeeach` annotation. As a procedure level annotation: -```sql +```sql linenums="1" --%suite(Some test suite) --%beforeeach @@ -619,7 +779,7 @@ procedure some_test; Marks annotated procedure to be executed before each test procedures in a suite. As a package level annotation (not associated with any procedure). -```sql +```sql linenums="1" --%suite(Some test suite) --%beforeeach(to_be_executed_before_each, other_package.some_setup) @@ -628,14 +788,15 @@ As a package level annotation (not associated with any procedure). procedure some_test; procedure to_be_executed_before_each; - ``` + Indicates that the procedure(s) mentioned as the annotation parameter are to be executed before each test procedure in a suite. If a test is marked as disabled the `--%beforeeach` procedure is not invoked for that test. If `--%beforeeach` raises an unhandled exception the following will happen: + - the following `--%beforeeach` as well as all `--%beforetest` for that test **will not be executed** - the test will be marked as errored and exception stack trace will be captured and reported - the `--%aftertest`, `--%aftereach` procedures **will be executed** for the errored test @@ -648,7 +809,7 @@ When multiple `--%beforeeach` procedures are defined in a suite, all of them wil For multiple `--%beforeeach` procedures order of execution is defined by annotation position in the package specification. -```sql +```sql linenums="1" create or replace package test_package as --%suite(Tests for a package) @@ -689,9 +850,10 @@ end; / ``` -```sql +```sql linenums="1" exec ut.run('test_package'); ``` + ``` Tests for a package ---SETUP_STUFF invoked --- @@ -718,7 +880,7 @@ That means that the procedure will be executed as many times as there are test i There are two possible ways to use the `--%aftereach` annotation. As a procedure level annotation: -```sql +```sql linenums="1" --%suite(Some test suite) --%aftereach @@ -730,7 +892,7 @@ procedure some_test; Marks annotated procedure to be executed after each test procedures in a suite. As a package level annotation (not associated with any procedure). -```sql +```sql linenums="1" --%suite(Some test suite) --%aftereach(to_be_executed_after_each, other_package.some_setup) @@ -739,13 +901,14 @@ As a package level annotation (not associated with any procedure). procedure some_test; procedure to_be_executed_after_each; - ``` + Indicates that the procedure(s) mentioned as the annotation parameter are to be executed after each test procedure in a suite. If a test is marked as disabled the `--%aftereach` procedure is not invoked for that test. If `--%aftereach` raises an unhandled exception the following will happen: + - the test will be marked as errored and exception stack trace will be captured and reported - the `--%aftertest`, `--%aftereach` procedures **will be executed** for the errored test - the `--%afterall` procedures **will be executed** @@ -757,7 +920,7 @@ For multiple `--%aftereach` procedures order of execution is defined by the anno As a rule, the `--%aftereach` gets executed even if the associated `--%beforeeach`, `--%beforetest`, `--%test` or other `--%aftereach` procedures have raised unhandled exceptions. -```sql +```sql linenums="1" create or replace package test_package as --%suite(Tests for a package) @@ -797,7 +960,7 @@ create or replace package body test_package as end; / ``` -```sql +```sql linenums="1" exec ut.run('test_package'); ``` ``` @@ -819,9 +982,10 @@ See [beforeall](#Beforeall) for more examples. ### Beforetest Indicates specific setup procedure(s) to be executed for a test. The procedure(s) can be located either: + - within current package (package name is optional) - within another package - + The annotation need to be placed alongside `--%test` annotation. The `--%beforetest` procedures are executed after invoking all `--%beforeeach` for a test. @@ -829,6 +993,7 @@ The `--%beforetest` procedures are executed after invoking all `--%beforeeach` f If a test is marked as disabled the `--%beforetest` procedures are not invoked for that test. If `--%beforetest` raises an unhandled exception the following will happen: + - the following `--%beforetest` for that test **will not be executed** - the test will be marked as errored and exception stack trace will be captured and reported - the `--%aftertest`, `--%aftereach` procedures **will be executed** for the errored test @@ -838,12 +1003,13 @@ If `--%beforetest` raises an unhandled exception the following will happen: When multiple `--%beforetest` procedures are defined for a test, all of them will be executed before invoking the test. The order of execution for `--%beforetest` procedures is defined by: + - position of procedure on the list within single annotation - annotation position As a rule, the `--%beforetest` execution gets aborted if preceding `--%beforeeach` or `--%beforetest` failed. -```sql +```sql linenums="1" create or replace package test_package as --%suite(Tests for a package) @@ -885,7 +1051,7 @@ create or replace package body test_package as end; / ``` -```sql +```sql linenums="1" exec ut.run('test_package'); ``` ``` @@ -907,28 +1073,31 @@ Finished in .015185 seconds ### Aftertest Indicates specific cleanup procedure(s) to be executed for a test. The procedure(s) can be located either: + - within current package (package name is optional) - within another package - + The annotation need to be placed alongside `--%test` annotation. If a test is marked as disabled the `--%aftertest` procedures are not invoked for that test. If `--%aftertest` raises an unhandled exception the following will happen: + - the test will be marked as errored and exception stack trace will be captured and reported - the following `--%aftertest` and all `--%aftereach` procedures **will be executed** for the errored test - the `--%afterall` procedures **will be executed** - test execution will continue uninterrupted for rest of the suite -When multiple `--%aftertest` procedures are defined for a test, all of them will be executed before invoking the test. +When multiple `--%aftertest` procedures are defined for a test, all of them will be executed after invoking the test. The order of execution for `--%aftertest` procedures is defined by: + - position of procedure on the list within single annotation - annotation position As a rule, the `--%aftertest` gets executed even if the associated `--%beforeeach`, `--%beforetest`, `--%test` or other `--%aftertest` procedures have raised unhandled exceptions. -```sql +```sql linenums="1" create or replace package test_package as --%suite(Tests for a package) @@ -970,7 +1139,7 @@ create or replace package body test_package as end; / ``` -```sql +```sql linenums="1" exec ut.run('test_package'); ``` ``` @@ -994,9 +1163,9 @@ In most of the cases, the code to be tested is consisting of PLSQL packages cont When creating test suites, it's quite common to maintain `one to one` relationship between test suite packages and tested code. When it comes to test procedures themselves, it is best practice to have one test procedure for one tested behavior of the code that is tested. -The relationship between test procedure and tested procedure/function will be therefore `many to one` in most of the cases. +The relationship between test procedure and tested code will be therefore `many to one` or `many to many` in most of the cases. -With this comes a challenge. How to group tests, related to one tested procedure, so that it is obvious that they relate to the same code. +With this comes a challenge. How to group tests, related to one tested behavior, so that it is obvious that they relate to the same thing. This is where utPLSQL contexts come handy. @@ -1005,19 +1174,25 @@ Contexts allow for creating sub-suites within a suite package and they allow for In essence, context behaves like a suite within a suite. Context have following characteristics: -- start with the `--%context` annotation and ends with `--%endcontext` -- can have a name provided as parameter for example `--%context(remove_rooms_by_name)` -- when no name is provided for context, the context is names `context_N` where `N` is the number of the context in suite -- can have their own `--%beforeall`, `--%beforeeach`, `--%afterall` and `--%aftereach` procedures -- `--%beforeall`, `--%beforeeach`, `--%afterall` and `--%aftereach` procedures defined at suite level, propagate to context -- test suite package can have multiple contexts in it -- contexts cannot be nested +- context starts with the `--%context` annotation and ends with `--%endcontext`. Everything placed between those two annotations belongs to that context +- can have a description provided as parameter for example `--%context(Some interesting stuff)`. +- can have a name provided with `--%name` annotation. This is different than with `suite` and `test` annotations, where name is taken from `package/procedure` name. +- contexts can be nested, you can place a context inside another context +- when no name is provided for context, the context is named `context_N` where `N` is the number of the context in suite or parent context. +- context name must be unique within it's parent (suite / parent context) +- if context name is not unique within it's parent, context and it's entire content is excluded from execution +- context name should not contain spaces or special characters +- context name cannot contain a `.` (full stop/period) character +- suite/context can have multiple nested sibling contexts in it +- contexts can have their own `--%beforeall`, `--%beforeeach`, `--%afterall` and `--%aftereach` procedures +- `--%beforeall`, `--%beforeeach`, `--%afterall` and `--%aftereach` procedures defined at ancestor level, propagate to context +- if `--%endcontext` is missing for a context, the context spans to the end of package specification The below example illustrates usage of `--%context` for separating tests for individual procedures of package. -Tested tables and code -```sql +Sample tables and code +```sql linenums="1" create table rooms ( room_key number primary key, name varchar2(100) not null @@ -1074,11 +1249,12 @@ end; ``` Below test suite defines: + - `--%beforeall` outside of context, that will be executed before all tests -- `--%context(remove_rooms_by_name)` to group tests for `remove_rooms_by_name` procedure -- `--%context(add_rooms_content)` to group tests for `add_rooms_content` procedure +- `--%context(remove_rooms_by_name)` to group tests related to `remove_rooms_by_name` functionality +- `--%context(add_rooms_content)` to group tests related to `add_rooms_content` functionality -```sql +```sql linenums="1" create or replace package test_rooms_management is gc_null_value_exception constant integer := -1400; @@ -1100,7 +1276,6 @@ create or replace package test_rooms_management is --%endcontext - --%context(add_rooms_content) --%displayname(Add content to a room) @@ -1109,7 +1284,7 @@ create or replace package test_rooms_management is procedure fails_on_room_name_invalid; --%test(Fails when content name is null) - --%throws(gc_null_value_exception) + --%throws(test_rooms_management.gc_null_value_exception) procedure fails_on_content_null; --%test(Adds a content to existing room) @@ -1146,7 +1321,7 @@ create or replace package body test_rooms_management is begin open l_rooms_not_named_b for select * from rooms where name not like 'B%'; - remove_rooms_by_name('B%'); + rooms_management.remove_rooms_by_name('B%'); open l_remaining_rooms for select * from rooms; ut.expect( l_remaining_rooms ).to_equal(l_rooms_not_named_b); @@ -1154,23 +1329,27 @@ create or replace package body test_rooms_management is procedure room_with_content is begin - remove_rooms_by_name('Living Room'); + rooms_management.remove_rooms_by_name('Living Room'); end; procedure null_room_name is begin - remove_rooms_by_name(NULL); + --Act + rooms_management.remove_rooms_by_name(NULL); + --Assert done by --%throws annotation end; procedure fails_on_room_name_invalid is begin - add_rooms_content('bad room name','Chair'); + --Act + rooms_management.add_rooms_content('bad room name','Chair'); + --Assert done by --%throws annotation end; procedure fails_on_content_null is begin --Act - add_rooms_content('Dining Room',null); + rooms_management.add_rooms_content('Dining Room',null); --Assert done by --%throws annotation end; @@ -1182,7 +1361,7 @@ create or replace package body test_rooms_management is l_expected := 'Table'; --Act - add_rooms_content( 'Dining Room', l_expected ); + rooms_management.add_rooms_content( 'Dining Room', l_expected ); --Assert select name into l_actual from room_contents where contents_key = (select max(contents_key) from room_contents); @@ -1194,9 +1373,9 @@ end; / ``` -When te tests are executed -```sql -exec ut.run('test_package'); +When the tests are executed +```sql linenums="1" +exec ut.run('test_rooms_management'); ``` The following report is displayed ``` @@ -1214,6 +1393,249 @@ Finished in .035261 seconds 5 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s) ``` +Example of nested contexts test suite specification. +*Source - [slide 145](https://www.slideshare.net/Kevlin/structure-and-interpretation-of-test-cases/145?src=clipshare) of Structure and Interpretation of Test Cases by Kevlin Henney* + +```sql linenums="1" +create or replace package queue_spec as + --%suite(Queue specification) + + --%context(A new queue) + + --%test(Is empty) + procedure is_empty; + --%test(Preserves positive bounding capacity) + procedure positive_bounding_capacity; + --%test(Cannot be created with non positive bounding capacity) + procedure non_positive_bounding_cap; + --%endcontext + --%context(An empty queue) + + --%test(Dequeues an empty value) + procedure deq_empty_value; + --%test(Remains empty when null enqueued) + procedure empty_with_null_enq; + --%test(Becomes non empty when non null value enqueued) + procedure non_empty_after_enq; + --%endcontext + --%context(A non empty queue) + + --%context(that is not full) + + --%test(Becomes longer when non null value enqueued) + procedure grow_on_enq_non_null; + --%test(Becomes full when enqueued up to capacity) + procedure full_on_enq_to_cap; + --%endcontext + --%context(that is full) + + --%test(Ignores further enqueued values) + procedure full_ignore_enq; + --%test(Becomes non full when dequeued) + procedure non_full_on_deq; + --%endcontext + + --%test(Dequeues values in order enqueued) + procedure dequeue_ordered; + --%test(Remains unchanged when null enqueued) + procedure no_change_on_null_enq; + --%endcontext +end; +``` + + +When such specification gets executed `ut.run('queue_spec'')` (without body created) you will see the nesting of tests within contexts. +``` +Queue specification + An empty queue + Dequeues an empty value [.014 sec] (FAILED - 1) + Remains empty when null enqueued [.004 sec] (FAILED - 2) + Becomes non empty when non null value enqueued [.005 sec] (FAILED - 3) + A non empty queue + that is not full + Becomes longer when non null value enqueued [.005 sec] (FAILED - 4) + Becomes full when enqueued up to capacity [.005 sec] (FAILED - 5) + That is full + Ignores further enqueued values [.004 sec] (FAILED - 6) + Becomes non full when dequeued [.005 sec] (FAILED - 7) + Dequeues values in order enqueued [.006 sec] (FAILED - 8) + Remains unchanged when null enqueued [.004 sec] (FAILED - 9) + A new queue + Is empty [.007 sec] (FAILED - 10) + Preserves positive bounding capacity [.006 sec] (FAILED - 11) + Cannot be created with non positive bounding capacity [.005 sec] (FAILED - 12) +Failures: + 1) deq_empty_value + ORA-04067: not executed, package body "UT3.QUEUE_SPEC" does not exist + ORA-06508: PL/SQL: could not find program unit being called: "UT3.QUEUE_SPEC" + ORA-06512: at line 6 +... +Finished in .088573 seconds +12 tests, 0 failed, 12 errored, 0 disabled, 0 warning(s) +``` + +Suite nesting allows for organizing tests into human-readable specification of behavior. + +### Name +The `--%name` annotation is currently only used only for naming a context. +If a context doesn't have explicit name specified, then the name is given automatically by framework. + +The automatic name will be `context_#n` where `n` is a context number within a suite/parent context. + +The `--%name` can be useful when you would like to run only a specific context or its items by `suitepath`. + +Consider the below example. + +```sql linenums="1" +create or replace package queue_spec as + --%suite(Queue specification) + + --%context(A new queue) + + --%test(Cannot be created with non positive bounding capacity) + procedure non_positive_bounding_cap; + --%endcontext + --%context(An empty queue) + + --%test(Becomes non empty when non null value enqueued) + procedure non_empty_after_enq; + --%endcontext + --%context(A non empty queue) + + --%context(that is not full) + + --%test(Becomes full when enqueued up to capacity) + procedure full_on_enq_to_cap; + --%endcontext + --%context(that is full) + + --%test(Becomes non full when dequeued) + procedure non_full_on_deq; + --%endcontext + + --%endcontext +end; +``` + +In the above code, suitepaths, context names and context descriptions will be as follows. + +| suitepath | description | name | +|----------------------------------|----------------------|------------| +| queue_spec | Queue specification | queue_spec | +| queue_spec.context_#1 | A new queue | context_#1 | +| queue_spec.context_#2 | An empty queue | context_#2 | +| queue_spec.context_#3 | A non empty queue | context_#3 | +| queue_spec.context_#3.context_#1 | that is not full | context_#1 | +| queue_spec.context_#3.context_#2 | that is full | context_#2 | + +In order to run only the tests for the context `A non empty queue that is not full` you will need to call utPLSQL as below: +```sql linenums="1" + exec ut.run(':queue_spec.context_#3.context_#1'); +``` + +You can use `--%name` annotation to explicitly name contexts on suitepath. +```sql linenums="1" +create or replace package queue_spec as + --%suite(Queue specification) + + --%context(A new queue) + --%name(a_new_queue) + + --%test(Cannot be created with non positive bounding capacity) + procedure non_positive_bounding_cap; + --%endcontext + --%context(An empty queue) + --%name(an_empty_queue) + + --%test(Becomes non empty when non null value enqueued) + procedure non_empty_after_enq; + --%endcontext + --%context(A non empty queue) + --%name(a_non_empty_queue) + + --%context(that is not full) + --%name(that_is_not_full) + + --%test(Becomes full when enqueued up to capacity) + procedure full_on_enq_to_cap; + --%endcontext + --%context(that is full) + --%name(that_is_full) + + --%test(Becomes non full when dequeued) + procedure non_full_on_deq; + --%endcontext + + --%endcontext +end; +``` + +In the above code, suitepaths, context names and context descriptions will be as follows. + +| suitepath | description | name | +|-----------------------------------------------|-----------------------|-------------------| +| queue_spec | Queue specification | queue_spec | +| queue_spec.a_new_queue | A new queue | a_new_queue | +| queue_spec.an_empty_queue | An empty queue | an_empty_queue | +| queue_spec.a_non_empty_queue | A non empty queue | a_non_empty_queue | +| queue_spec.a_non_empty_queue.that_is_not_full | that is not full | that_is_not_full | +| queue_spec.a_non_empty_queue.that_is_full | that is full | that_is_full | + + +The `--%name` annotation is only relevant for: + +- running subsets of tests by given context suitepath +- some of test reports, like `ut_junit_reporter` that use suitepath or test-suite element names (not descriptions) for reporting + +#### Name naming convention + +The value of `--%name` annotation must follow the following naming rules: + +- cannot contain spaces +- cannot contain a `.` (full stop/dot) +- is case-insensitive + +### Tags + +Tag is a label attached to the test or a suite. It is used for identification and execution of a group of tests / suites that share the same tag. + +It allows for grouping of tests / suites using various categorization and place tests / suites in multiple buckets. Same tests can be grouped with other tests based on the functionality , frequency, type of output etc. + +e.g. + +```sql linenums="1" +--%tags(batch,daily,csv) +``` + +or + +```sql linenums="1" +--%tags(online,json) +--%tags(api) +``` + +Tags are defined as a comma separated list within the `--%tags` annotation. + +When a suite/context is tagged, all of its children will automatically inherit the tag and get executed along with the parent, unless they are excluded explicitly at runtime with a negated tag expression. +See [running unit tests](running-unit-tests.md) for more information on using tags to filter test suites that are to be executed. + +#### Tag naming convention + +Tags must follow the below naming convention: + +- tag is case sensitive +- tag must not contain any of the following reserved characters: + - comma (,) + - left or right parenthesis ((, )) + - ampersand (&) + - vertical bar (|) + - exclamation point (!) +- tag cannot be null or blank +- tag cannot start with a dash, e.g. `-some-stuff` is **not** a valid tag +- tag cannot contain spaces, e.g. `test of batch`. To create a multi-word tag use underscores or dashes, e.g. `test_of_batch`, `test-of-batch` +- leading and trailing spaces are ignored in tag name, e.g. `--%tags( tag1 , tag2 )` becomes `tag1` and `tag2` tag names +- tag cannot be one of two reserved words: `none` and `any`. `none` and `any` as a tag will be treated as no tag + ### Suitepath @@ -1232,9 +1654,10 @@ If you want to create tests for your application it is recommended to structure * Payments recognition * Payments set off -The `%suitepath` annotation is used for such grouping. Even though test packages are defined in a flat structure the `%suitepath` is used by the framework to form them into a hierarchical structure. Your payments recognition test package might look like: +The `--%suitepath` annotation is used for such grouping. Even though test packages are defined in a flat structure the `--%suitepath` is used by the framework to form them into a hierarchical structure. -```sql +Your payments recognition test package might look like: +```sql linenums="1" create or replace package test_payment_recognition as --%suite(Payment recognition tests) @@ -1253,7 +1676,7 @@ end test_payment_recognition; ``` And payments set off test package: -```sql +```sql linenums="1" create or replace package test_payment_set_off as --%suite(Payment set off tests) @@ -1268,11 +1691,11 @@ create or replace package test_payment_set_off as end test_payment_set_off; ``` -When you execute tests for your application, the framework constructs a test suite for each test package. Then it combines suites into grouping suites by the `%suitepath` annotation value so that the fully qualified path to the `recognize_by_num` procedure is `USER:payments.test_payment_recognition.test_recognize_by_num`. If any of its expectations fails then the test is marked as failed, also the `test_payment_recognition` suite, the parent suite `payments` and the whole run is marked as failed. -The test report indicates which expectation has failed on the payments module. The payments recognition submodule is causing the failure as `recognize_by_num` has not met the expectations of the test. Grouping tests into modules and submodules using the `%suitepath` annotation allows you to logically organize your project's flat structure of packages into functional groups. +When you execute tests for your application, the framework constructs a test suite for each test package. Then it combines suites into grouping suites by the `--%suitepath` annotation value so that the fully qualified path to the `recognize_by_num` procedure is `USER:payments.test_payment_recognition.test_recognize_by_num`. If any of its expectations fails then the test is marked as failed, also the `test_payment_recognition` suite, the parent suite `payments` and the whole run is marked as failed. +The test report indicates which expectation has failed on the payments module. The payments recognition submodule is causing the failure as `recognize_by_num` has not met the expectations of the test. Grouping tests into modules and submodules using the `--%suitepath` annotation allows you to logically organize your project's flat structure of packages into functional groups. An additional advantage of such grouping is the fact that every element level of the grouping can be an actual unit test package containing a common module level setup for all of the submodules. So in addition to the packages mentioned above you could have the following package. -```sql +```sql linenums="1" create or replace package payments as --%suite(Payments) @@ -1285,9 +1708,11 @@ create or replace package payments as end payments; ``` -A `%suitepath` can be provided in three ways: + +When executing tests, `path` for executing tests can be provided in three ways: + * schema - execute all tests in the schema -* [schema]:suite1[.suite2][.suite3]...[.procedure] - execute all tests in all suites from suite1[.suite2][.suite3]...[.procedure] path. If schema is not provided, then the current schema is used. Example: `:all.rooms_tests` +* [schema]:suite1[.suite2][.suite3]...[.procedure] - execute all tests by `suitepath` in all suites on path suite1[.suite2][.suite3]...[.procedure]. If schema is not provided, then the current schema is used. Example: `:all.rooms_tests` * [schema.]package[.procedure] - execute all tests in the specified test package. The whole hierarchy of suites in the schema is built before all before/after hooks or part suites for the provided suite package are executed as well. Example: `tests.test_contact.test_last_name_validator` or simply `test_contact.test_last_name_validator` if `tests` is the current schema. @@ -1326,6 +1751,7 @@ Keep in mind that when your test runs as autonomous transaction it will not see ### Throws The `--%throws` annotation allows you to specify a list of exceptions as one of: + - number literals - example `--%throws(-20134)` - variables of type exception defined in a package specification - example `--%throws(exc_pkg.c_exception_No_variable)` - variables of type number defined in a package specification - example `--%throws(exc_pkg.c_some_exception)` @@ -1340,11 +1766,11 @@ If `--%throws` annotation is specified with arguments and exception raised is no The framework will raise a warning, when `--%throws` annotation has invalid arguments or when no arguments were provided. Annotation `--%throws(7894562, operaqk, -=1, -20496, pow74d, posdfk3)` will be interpreted as `--%throws(-20496)`. - + Please note that `NO_DATA_FOUND` exception is a special case in Oracle. To capture it use `NO_DATA_FOUND` named exception or `-1403` exception No. Example: -```sql +```sql linenums="1" create or replace package exc_pkg is c_e_option1 constant number := -20200; c_e_option2 constant varchar2(10) := '-20201'; @@ -1507,7 +1933,7 @@ Finished in .025784 seconds ## Order of execution -```sql +```sql linenums="1" create or replace package test_employee_pkg is --%suite(Employee management) @@ -1629,10 +2055,128 @@ When processing the test suite `test_employee_pkg` defined in [Example of annota rollback to savepoint 'before-suite' ``` -**Note** ->utPLSQL does not guarantee ordering of tests in suite. On contrary utPLSQL might give random order of tests/contexts in suite. -> ->Order of execution within multiple occurrences of `before`/`after` procedures is determined by the order of annotations in specific block (context/suite) of package specification. +!!! note + utPLSQL does not guarantee ordering of tests in suite. On contrary utPLSQL might give random order of tests/contexts in suite.
+ Order of execution within multiple occurrences of `before`/`after` procedures is determined by the order of annotations in specific block (context/suite) of package specification. + +## sys_context + +It is possible to access information about currently running suite. +The information is available by calling `sys_context( 'UT3_INFO', attribute )`. +It can be accessed from any procedure invoked as part of utPLSQL test execution. + +!!! note + Context name is derived from schema name where utPLSQL is installed.
+ The context name in below examples represents the default install schema -> `UT3`
+ If you install utPLSQL into another schema the context name will be different.
+ For example if utPLSQL is installed into `HR` schema, the context name will be `HR_INFO` + +Following attributes are populated: + +| Name | Scope | Description | +|-------------------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------| +| COVERAGE_RUN_ID | run | Value of COVERAGE_RUN_ID used by utPLSQL internally for coverage gathering | +| RUN_PATHS | run | list of suitepaths / suitenames used as input parameters for call to `ut.run(...)` or `ut_runner.run(...)` | +| SUITE_DESCRIPTION | run | the description of test suite that is currently being executed | +| SUITE_PACKAGE | run | the owner and name of test suite package that is currently being executed | +| SUITE_PATH | run | the suitepath for the test suite package that is currently being executed | +| SUITE_START_TIME | run | the execution start timestamp of test suite package that is currently being executed | +| CURRENT_EXECUTABLE_NAME | run | the owner.package.procedure of currently running test suite executable | +| CURRENT_EXECUTABLE_TYPE | run | the type of currently running test suite executable (one of: `beforeall`, `beforeeach`, `beforetest`, `test`, `aftertest`, `aftereach`, `afterall` | + | CONTEXT_DESCRIPTION | suite context | the description of test suite context that is currently being executed | + | CONTEXT_NAME | suite context | the name of test suite context that is currently being executed | + | CONTEXT_PATH | suite context | the suitepath for the currently executed test suite context | + | CONTEXT_START_TIME | suite context | the execution start timestamp for the currently executed test suite context | +| TEST_DESCRIPTION | test* | the description of test for which the current executable is being invoked | +| TEST_NAME | test* | the name of test for which the current executable is being invoked | +| TEST_START_TIME | test* | the execution start timestamp of test that is currently being executed (the time when first `beforeeach`/`beforetest` was called for that test) | + +!!! note "Scopes" + - run - context information is available in any element of test run
+ - suite context - context information is available in any element nested within a suite context
+ - test* - context information is available when executing following procedure types: test, beforetest, aftertest, beforeeach or aftereach + + +Example: +```sql linenums="1" +create or replace procedure which_procecure_called_me is +begin + dbms_output.put_line( + 'Currently running utPLSQL ' ||sys_context( 'ut3_info', 'current_executable_type' ) + ||' ' ||sys_context( 'ut3_info', 'current_executable_name' ) + ); +end; +/ + +create or replace package test_call is + + --%suite + + --%beforeall + procedure beforeall; + + --%beforeeach + procedure beforeeach; + + --%test + procedure test1; + + --%test + procedure test2; + +end; +/ + +create or replace package body test_call is + + procedure beforeall is + begin + which_procecure_called_me(); + dbms_output.put_line('Current test procedure is: '||sys_context('ut3_info','test_name')); + end; + + procedure beforeeach is + begin + which_procecure_called_me(); + dbms_output.put_line('Current test procedure is: '||sys_context('ut3_info','test_name')); + end; + + procedure test1 is + begin + which_procecure_called_me(); + ut.expect(sys_context('ut3_info','suite_package')).to_equal(user||'.test_call'); + end; + + procedure test2 is + begin + which_procecure_called_me(); + ut.expect(sys_context('ut3_info','test_name')).to_equal(user||'.test_call.test2'); + end; + +end; +/ +``` + +```sql linenums="1" +exec ut.run('test_call'); +``` + +``` +test_call + Currently running utPLSQL beforeall UT3.test_call.beforeall + Current test procedure is: + test1 [.008 sec] + Currently running utPLSQL beforeeach UT3.test_call.beforeeach + Current test procedure is: UT3.test_call.test1 + Currently running utPLSQL test UT3.test_call.test1 + test2 [.004 sec] + Currently running utPLSQL beforeeach UT3.test_call.beforeeach + Current test procedure is: UT3.test_call.test2 + Currently running utPLSQL test UT3.test_call.test2 + +Finished in .021295 seconds +2 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s) +``` ## Annotation cache @@ -1646,14 +2190,14 @@ If you are in a situation where your database is controlled via CI/CD server and To build the annotation cache without actually invoking any tests, call `ut_runner.rebuild_annotation_cache(a_object_owner)` for every unit test owner for which you want to have the annotation cache prebuilt. Example: -```sql +```sql linenums="1" exec ut_runner.rebuild_annotation_cache('HR'); ``` To purge the annotation cache call `ut_runner.purge_cache(a_object_owner, a_object_type)`. Both parameters are optional and if not provided, all owners/object_types will be purged. Example: -```sql +```sql linenums="1" exec ut_runner.purge_cache('HR', 'PACKAGE'); ``` diff --git a/docs/userguide/best-practices.md b/docs/userguide/best-practices.md index bdfcf99a7..6becefc5c 100644 --- a/docs/userguide/best-practices.md +++ b/docs/userguide/best-practices.md @@ -1,4 +1,4 @@ -# Best Practices +![version](https://img.shields.io/badge/version-v3.1.14.4206--develop-blue.svg) The following are best practices we at utPLSQL have learned about PL/SQL and Unit Testing. @@ -15,9 +15,9 @@ The following are best practices we at utPLSQL have learned about PL/SQL and Uni - Tests should not mimic / duplicate the logic of tested code - Tests should contain zero logic (or as close to zero as possible) - The 3A rule: - - Arrange (setup inputs/data/environment for the tested code) - - Act (execute code under test) - - Assert (validate the outcomes of the execution) + - Arrange (setup inputs/data/environment for the tested code) + - Act (execute code under test) + - Assert (validate the outcomes of the execution) - Each tested procedure/function/trigger (code block) should have more than one test - Each test should check only one behavior (one requirement) of the code block under test - Tests should be maintained as thoroughly as production code diff --git a/docs/userguide/coverage.md b/docs/userguide/coverage.md index 1d4ca93c5..c9015b438 100644 --- a/docs/userguide/coverage.md +++ b/docs/userguide/coverage.md @@ -1,26 +1,35 @@ -# Coverage -utPLSQL comes with a built-in coverage reporting engine. The code coverage reporting is based on the DBMS_PROFILER package provided with Oracle database. +![version](https://img.shields.io/badge/version-v3.1.14.4206--develop-blue.svg) + +utPLSQL comes with a built-in coverage reporting engine. The code coverage reporting uses package DBMS_PROFILER (and DBMS_PLSQL_CODE_COVERAGE on Oracle database version 12.2 and above) provided with Oracle database. Code coverage is gathered for the following source types: + * package bodies * type bodies * triggers * procedures * functions -**Note** +!!! note -> The package and type specifications are explicitly excluded from code coverage analysis. This limitation is introduced to avoid false-negatives. Typically package specifications contain no executable code. The only exception is initialization of global constants and variables in package specification. Since most package specifications are not executable at all, there is no information available on the number of lines covered and those would be reported as 0% covered, which is not desirable. + The package and type specifications are excluded from code coverage analysis. + This limitation is introduced to avoid false-negatives. + Typically package specifications contain no executable code. + The only exception is initialization of global constants and variables in package specification. + Since most package specifications are not executable at all, there is no information available + on the number of lines covered and those would be reported as 0% covered, which is not desirable. -To obtain information about code coverage of your unit tests, all you need to do is run your unit tests with one of built-in code coverage reporters. +To obtain information about code coverage for unit tests, run utPLSQL with one of built-in code coverage reporters. The following code coverage reporters are supplied with utPLSQL: -* `ut_coverage_html_reporter` - generates a HTML coverage report providing summary and detailed information on code coverage. The HTML reporter is based on the open-source [simplecov-html](https://github.com/colszowka/simplecov-html) reporter for Ruby. It includes source code of the code that was covered (if possible) + +* `ut_coverage_html_reporter` - generates a HTML coverage report providing summary and detailed information on code coverage. The HTML reporter is based on the open-source [simplecov-html](https://github.com/colszowka/simplecov-html) reporter for Ruby. It includes source code of the code that was covered (if the code is accessible for test user) * `ut_coveralls_reporter` - generates a [Coveralls compatible JSON](https://coveralls.zendesk.com/hc/en-us/articles/201774865-API-Introduction) coverage report providing detailed information on code coverage with line numbers. This coverage report is designed to be consumed by cloud services like [Coveralls](https://coveralls.io) -* `ut_coverage_sonar_reporter` - generates a [Sonar Compatible XML](https://docs.sonarqube.org/display/SONAR/Generic+Test+Data) coverage report providing detailed information on code coverage with line numbers. This coverage report is designed to be consumed by services like [SonarQube/SonarCloud](https://about.sonarcloud.io/) +* `ut_coverage_sonar_reporter` - generates a [Sonar Compatible XML](https://docs.sonarqube.org/latest/analysis/generic-test/) coverage report providing detailed information on code coverage with line numbers. This coverage report is designed to be consumed by services like [SonarQube](https://www.sonarqube.org/) and [SonarCloud](https://about.sonarcloud.io/) * `ut_coverage_cobertura_reporter` - generates a basic Cobertura coverage (http://cobertura.sourceforge.net/xml/coverage-04.dtd) report providing detailed information on code coverage with line numbers. This coverage report is designed to be consumed by services like TFS and Jenkins. Check this link for an example of XML generated by Java: https://raw.githubusercontent.com/jenkinsci/cobertura-plugin/master/src/test/resources/hudson/plugins/cobertura/coverage-with-data.xml ## Security model utPLSQL code coverage uses DBMS_PROFILER to gather information about the execution of code under test and therefore follows the [DBMS_PROFILER's Security Model](https://docs.oracle.com/database/121/ARPLS/d_profil.htm#ARPLS67465). In order to be able to gather coverage information, the user executing unit tests needs to be either: + * The owner of the code that is being tested * Have the following privileges to be able to gather coverage on code owned by other users: * `create any procedure` system privilege @@ -28,23 +37,24 @@ In order to be able to gather coverage information, the user executing unit test If you have `execute` privilege on the code that is being tested, but do not have `create any procedure` system privilege, then the code that is being tested will be reported as not covered (coverage = 0%). If you have `execute` privilege only on the unit tests, but do not have `execute` privilege on the code that is being tested, the code will not be reported by coverage - as if it did not exist in the database. -If the code that is being tested is complied as NATIVE, the code coverage will not be reported as well. +If the code that is being tested is compiled as NATIVE, the code coverage will not be reported as well. -## Running unit tests with coverage -Using the code coverage functionality is as easy as using any other [reporter](reporters.md) for the utPLSQL project. You just run your tests from your preferred SQL tool and save the reporter results to a file. -All you need to do is pass the constructor of the reporter to your `ut.run` +## Manually running unit tests with coverage +Using the code coverage functionality is as easy as using any other [reporter](reporters.md) for the utPLSQL test-run. Run your tests from your preferred SQL tool and save the reporter results to a file. +All you need to do, is pass the constructor of the reporter to the `ut.run` procedure call. Example: -```sql +```sql linenums="1" +set serveroutput on begin ut.run(ut_coverage_html_reporter()); end; / ``` -Executes all unit tests in the current schema, gathers information about code coverage and outputs the HTML text into DBMS_OUTPUT. +The above command executes all unit tests in the **current schema**, gathers information about code coverage for all sources in that schema and outputs the HTML report as text into DBMS_OUTPUT. The `ut_coverage_html_reporter` will produce an interactive HTML report. You can see a sample of code coverage for the utPLSQL project [here](https://utplsql.github.io/utPLSQL-coverage-html/) -The report provides summary information with a list of source code that was expected to be covered. +The report provides summary information with a list of source code that should be covered. ![Coverage Summary page](../images/coverage_html_summary.png) @@ -53,16 +63,17 @@ The report allow you to navigate to each source file and inspect line by line co ![Coverage Details page](../images/coverage_html_details.png) -#### Oracle 12.2 extended coverage with profiler and block coverage +### Oracle 12.2 extended coverage with profiler and block coverage Using data collected from profiler and block coverage running parallel we are able to enrich information about coverage. -For every line recorded by profiler if we have a partially covered same line in block coverage we will display that information -presenting line as partially covered, displaying number of block and how many blocks been covered in that line.The feature will be automatically enabled in the Oracle database version 12.2 and higher, for older versions current profiler will be used. +For every line recorded by the profiler if we have a partially covered same line in block coverage we will display that information +presenting line as partially covered, displaying number of block and how many blocks have been covered in that line.The feature will be automatically enabled in the Oracle database version 12.2 and higher, for older versions current profiler will be used. utPLSQL installation automatically creates tables needed by `dbms_plsql_code_coverage` on databases in versions above 12c Release 1. Due to security model of `dbms_plsql_code_coverage` package, utPLSQL grants access to those tables and creates synonyms for those tables. The access and synonyms will be public when using the headless installation. This approach avoids complexity of forcing every user of utPLSQL framework to create tables on their own. Sample output: + ![Package Coverage Summary](../images/extended_coverage_html_summary.png) ![Line Coverage Details](../images/extended_coverage_html_line.png) @@ -76,41 +87,41 @@ There are two distinct ways to gather code coverage: - Coverage on project files Those two options are mutually exclusive and cannot be mixed. -By default, when using one of coverage reporters, coverage is gathered on schema(s). +By default, when using one of coverage reporters, coverage is gathered on schema(s). +The database schema(s) containing the tests that were executed during the run will be reported on by coverage reporter. The parameters used to execute tests determine if utPLSQL will be using one approach or the other. +If parameter `a_source_file_mappings` or `a_source_files` is provided, then coverage is gathered on project files provided, otherwise coverage is gathered on schemas. -The database schema(s) containing the tests that were executed during the run will be reported on by coverage reporter. -**Note** - -> Regardless of the options provided, all unit test packages are excluded from the coverage report. Coverage reports provide information only about the **tested** code. +!!! note + Regardless of the options provided, all unit test packages are excluded from the coverage report. Coverage reports provide information only about the **tested** code. The default behavior of coverage reporting can be altered using invocation parameters. ### Schema based Coverage -To simply gather coverage for all objects in your current schema execute tests with coverage reporting. +To gather coverage for all objects in the **current schema** execute tests with coverage report as argument. +This is the default reporting option and therefore additional coverage options don't need to be provided. -```sql +```sql linenums="1" exec ut.run(ut_coverage_html_reporter()); ``` -**Note** +!!! note -> When no filters are used, the size of the coverage report will depend two factors: -> - the type of report (does the report include source code or not) -> - the amount of source code in the database schema -> ->Keep in mind that for schemas containing a lot of code, it can take quite some time to produce the coverage report. + When no filters are used, the size of the coverage report will depend two factors:
+ - the type of report (does the report include source code or not)
+ - the amount of source code in the database schema
+ Keep in mind that for schemas containing a lot of code, it can take quite some time to produce the coverage report. #### Setting coverage schema(s) By default, coverage is gathered on the schema(s) derived from suite paths provided to execute tests. -This is correct as long as your test packages and tested code share the same schema. +This is a valid approach as long as your test packages and tested code share the same schema. So when you run: -```sql +```sql linenums="1" exec ut.run(ut_varchar2_list('user_1','user_2'), ut_coverage_html_reporter()); ``` Coverage will be gathered on both `user_1` and `user_2` objects. @@ -119,31 +130,140 @@ If your tests live in a different schema from the tested code you may override t In the example below, coverage will still be gathered for `user_1` and `user_2` objects, even thought we run the tests located in schema `unit_test_schema` -```sql -exec ut.run('unit_test_schema', ut_coverage_html_reporter(), a_coverage_schemes => ut_varchar2_list('user_1','user_2') ); +```sql linenums="1" +begin + ut.run('unit_test_schema', ut_coverage_html_reporter(), + a_coverage_schemes => ut_varchar2_list('user_1','user_2') + ); +end; ``` #### Filtering objects in coverage reports -There are two options that can be used to narrow down the scope of coverage report: -- `a_include_objects` - list of `[object_owner.].object_name` to be included in the coverage report -- `a_exclude_objects` - list of `[object_owner.].object_name` to be excluded from the coverage report +Multiple parameters can be used to define the scope of coverage report. + +- `a_source_file_mappings ( ut_file_mappings )` - map of filenames to database objects. It is used for file-based coverage - see below. +- `a_include_schema_expr ( varchar(4000) )` - string of regex expression of schemas to be included in the coverage report. Case-insensitive. +- `a_include_object_expr ( varchar(4000) )` - string of regex expression of objects ( without schema name ) to be included in the coverage report. Case-insensitive. +- `a_exclude_schema_expr ( varchar(4000) )` - string of regex expression of schemas to be excluded from the coverage report. Case-insensitive. +- `a_exclude_object_expr ( varchar(4000) )` - string of regex expression of objects ( without schema name ) to be excluded from the coverage report. Case-insensitive. +- `a_coverage_schemes ( ut_varchar2_list )` - List of database schema names to gather coverage on. +- `a_include_objects ( ut_varchar2_list )` - list of `[object_owner.]object_name` to be included in the coverage report. +- `a_exclude_objects ( ut_varchar2_list )` - list of `[object_owner.]object_name` to be excluded from the coverage report. + +You may specify both _include_ and _exclude_ options to gain more control over what needs to be included / excluded from the coverage report. + + +!!! warning "Important note" + + The order of priority is for evaluation of include/exclude filter parameters is as follows.
+ - if `a_source_file_mappings` is defined then all include/exclude parameters are ignored (see section below for usage of `a_source_file_mappings` parameter )
+ - else if `a_include_schema_expr` or `a_include_object_expr` parameter is specified then parameters `a_coverage_schemes` and `a_include_objects` are ignored
+ - else if `a_include_objects` is specified then the coverage is gathered only on specified database objects.
+ - if `a_coverage_schemes` is specified then those schemas are used for objects in `a_include_objects` without schema name
+ - if `a_coverage_schemes` is not specified then schema from paths (`a_paths`) parameter are used for objects in `a_include_objects` without schema name
+ - else if, only the `a_coverage_schemes` is specified then the coverage is gathered only on specified database schemas
+ - else if no coverage specific parameters are provided coverage is gathered on all schemas specified in paths passed to run procedure
+ - else if no paths were specified, the coverage is gathered on current schema of the session running the tests + +The exclude parameters are not mutually-exclusive and can be mixed together. All of exclude parameters are always applied. + +Example: Limiting coverage by schema regex. +```sql linenums="1" +begin + ut.run(ut_varchar2_list('user_1','user_2'), ut_coverage_html_reporter(), + a_include_schema_expr => '^ut3_develop' + ); +end; +``` +Will result in showing coverage for all schemas that match regular expression `^ut3_develop` + +Example: Limiting coverage by schema regex with parameter `a_include_objects` ignored. +```sql linenums="1" +begin + ut.run(ut_varchar2_list('user_1','user_2'), ut_coverage_html_reporter(), + a_include_schema_expr => '^ut3_develop', a_include_objects => ut_varchar2_list( 'ut3_tester_helper.regex_dummy_cov' ) + ); +end; +``` +Will result in showing coverage for all schemas that match regular expression `^ut3_develop`. + +Example: Limiting coverage by object regex. +```sql linenums="1" +begin + ut.run(ut_varchar2_list('user_1','user_2'), ut_coverage_html_reporter(), + a_include_object_expr => 'regex123' + ); +end; +``` +Will result in showing coverage for all objects that name match regular expression `regex123`. -You may specify both _include_ and _exclude_ object lists to gain more control over what needs to be included / excluded from the coverage report. +Example: Limiting coverage by object regex with parameter `a_include_objects` ignored. +```sql linenums="1" +begin + ut.run(ut_varchar2_list('user_1','user_2'), ut_coverage_html_reporter(), + a_include_object_expr => 'utl', a_include_objects => ut_varchar2_list( 'user_2.utils_package' ) + ); +end; +``` +Will result in showing coverage for all objects that name match regular expression `utl`. + +Example: Limiting coverage by excluding schema with regex. +```sql linenums="1" +begin + ut.run(ut_varchar2_list('user_1','user_2'), ut_coverage_html_reporter(), + a_exclude_schema_expr => 'er_1$' + ); +end; +``` +Will result in showing coverage for objects in all schema except schemas that are matching regular expression `er_1$` -The object owner is optional in the object list. -If you do not provide an object owner, the _include_/_exclude_ list will be considered for every schema used for coverage gathering (as described above). +Example: Limiting coverage by excluding schema with regex and excluding specific object. +```sql linenums="1" +begin + ut.run(ut_varchar2_list('user_1','user_2'), ut_coverage_html_reporter(), + a_exclude_schema_expr => 'er_1$', a_exclude_objects => ut_varchar2_list( 'user_2.utils_package' ) + ); +end; +``` +Will result in showing coverage for objects in all schemas except schemas that are matching regular expression `er_1$` +Will also exclude object `user_2.utils_package` from coverage report + +Example: Limiting coverage by excluding objects with regex. +```sql linenums="1" +begin + ut.run(ut_varchar2_list('user_1','user_2'), ut_coverage_html_reporter(), + a_exclude_object_expr => 'utl' + ); +end; +``` +Will result in showing coverage for all objects that name is not matching regular expression `utl`. + +Example: Limiting coverage by excluding objects with regex with parameter `a_exclude_objects` ignored. +```sql linenums="1" +begin + ut.run(ut_varchar2_list('user_1','user_2'), ut_coverage_html_reporter(), + a_exclude_object_expr => 'utl', a_exclude_objects => ut_varchar2_list( 'user_2.utils_package' ) + ); +end; +``` +Will result in showing coverage for all objects that name is not matching regular expression `utl`. +Will also exclude object `user_2.utils_package` from coverage report Example: Limiting coverage by object name, for tested code located in the same schema as the unit tests. -```sql -exec ut.run(ut_varchar2_list('user_1','user_2'), ut_coverage_html_reporter(), a_include_objects=>ut_varchar2_list('award_bonus')); +```sql linenums="1" +begin + ut.run(ut_varchar2_list('user_1','user_2'), ut_coverage_html_reporter(), + a_include_objects=>ut_varchar2_list('award_bonus') + ); +end; ``` Executes all tests in schemas: `user_1` and `user_2`. Coverage will only be reported on objects `user_1.award_bonus`, `user_2.award_bonus` Example: Limiting coverage by object name, for tested code located in different schemas than the unit tests. -```sql +```sql linenums="1" begin ut.run( 'unit_test_schema', ut_coverage_html_reporter(), @@ -156,7 +276,7 @@ Executes all tests in schema `unit_test_schema`. Coverage will only be reported Objects that do not exist in the database but were specified in `a_include_objects` will be ignored. Example: Limiting coverage by object owner and name. -```sql +```sql linenums="1" begin ut.run( 'unit_test_schema', ut_coverage_html_reporter(), @@ -169,7 +289,7 @@ Executes all tests in schema `unit_test_schema`. Coverage will only be reported The `a_exclude_objects` can be used in the same way as `a_include_objects`. Example: Excluding objects from coverage report by providing a list of object owner/name to be excluded. -```sql +```sql linenums="1" begin ut.run( 'unit_test_schema.test_award_bonus', ut_coverage_html_reporter(), @@ -179,12 +299,13 @@ end; ``` Executes test `test_award_bonus` in schema `unit_test_schema`. Coverage will be reported on all objects in schema `ut3_user` except the `betwnstr` object. -**Note** -> Filtering using `a_include_objects` and `a_exclude_objects` is only applicable when gathering coverage for a schema. Those filters are not applied when reporting coverage on project files. +!!! note + Filtering using `a_include_objects` and `a_exclude_objects` is only applicable when gathering coverage for a schema. Those filters are not applied when reporting coverage on project files. + +!!! note + When running coverage on schema objects, all source code of package bodies, functions, procedures, type bodies and triggers that were not executed will be reported as having 0% code coverage and all source code lines will show as uncovered. + This is different from the behavior when gathering coverage on project files. -**Note** -> When running coverage on schema objects, all source code of package bodies, functions, procedures, type bodies and triggers that were not executed will be reported as having 0% code coverage and all source code lines will show as uncovered. -> This is different than the behavior when gathering coverage on project files. ### Project based Coverage @@ -196,6 +317,7 @@ They are abstracted from database, schema names, packages, procedures and functi To be able to effectively use reporters dedicated for those tools, utPLSQL provides functionality for mapping database object names to project files. There are a few significant differences when running coverage on project files compared to running coverage on schema(s). + - Coverage is only reported on objects that were successfully mapped to project files. - Project files (database objects) that were not executed at all are not reported as fully uncovered. It is up to the consumer (Sonar/Coveralls) to determine if project file should be considered as 0% coverage or just ignored. @@ -231,21 +353,23 @@ C: ``` By default, utPLSQL will convert file paths into database objects using the following regular expression `/(((\w|[$#])+)\.)?((\w|[$#])+)\.(\w{3})$` + - object owner (if it is present) is identified by the expression in the second set of brackets - object name is identified by the expression in the fourth set of brackets - object type is identified by the expression in the sixth set of brackets -**Note** -> utPLSQL will replace any '\\' with '/' for the purpose of mapping files to objects. The paths shown in the results will remain (contain '\' where it was present). -> This is done to simplify the syntax of regular expressions. Regular expression will always use '/' as a directory separator on a file path regardless of whether you're on a Windows or Unix system. +!!! note + utPLSQL will replace any '\\' with '/' for the purpose of mapping files to objects. The paths shown in the results will remain (contain '\' where it was present). + This is done to simplify the syntax of regular expressions. Regular expression will always use '/' as a directory separator on a file path regardless of whether you're on a Windows or Unix system. -**Note** -> Below examples assume that you have downloaded latest version of [utPLSQL-cli](https://github.com/utPLSQL/utPLSQL-cli/releases), extracted it into your projects root directory (my_project) and placed ojdbc8.jar and orai18n.jar files in utPLSQL-cli\lib directory. -> The examples assume that you run the utPLSQL-cli from `my_project` directory. +!!! note + Below examples assume that you have downloaded latest version of [utPLSQL-cli](https://github.com/utPLSQL/utPLSQL-cli/releases) + and extracted it into your projects root directory + and that you run the utPLSQL-cli from that directory. Windows: -``` +```pwsh utPLSQL-cli\bin\utplsql run test_runner/pass@db_host:db_port/db_service_name ^ -p=hr,hotel ^ -source_path=sources ^ @@ -265,6 +389,7 @@ utPLSQL-cli/bin/utplsql run test_runner/pass@db_host:db_port/db_service_name \ ``` The above commands will: + - connect as user `test_runner` - run all utPLSQL v3 tests for users `hr`, `hotel` - map database code to project files in `sources` directory and save code coverage results into `coverage.html` @@ -315,7 +440,7 @@ Note that the owner/name/type subexpressions don't need to be explicitly specifi In the below example, they were specified explicitly only for `source_path`, `test_path` doesn't have subexpressions specified and so they are default (2/3/4). Windows: -``` +```pwsh utPLSQL-cli\bin\utplsql run test_runner/pass@db_url ^ -p=hr,hotel ^ -source_path=sources ^ @@ -378,7 +503,7 @@ For the database objects mapped to `souces` directory user `code_owner` will be For the database objects mapped to `tests` directory user `tests_owner` will be used. Windows: -``` +```pwsh utPLSQL-cli\bin\utplsql run test_runner/pass@db_url ^ -p=tests_owner ^ -source_path=sources -owner=code_owner ^ @@ -397,9 +522,9 @@ utPLSQL-cli/bin/utplsql run test_runner/pass@db_url \ -f=ut_sonar_test_reporter -o=test_results.xml ``` -**Note** -> When the project folder structure does not provide any information about source code owner and test owner, you can specify the owner for tests and owner for code explicitly. -> Such project configuration supports only single-owner for source code and single owner for tests. +!!! note + When the project folder structure does not provide any information about source code owner and test owner, you can specify the owner for tests and owner for code explicitly. + Such project configuration supports only single-owner for source code and single owner for tests. Tested code is mapped to files in `coverage.html` @@ -476,7 +601,7 @@ C: Windows: -``` +```pwsh utPLSQL-cli\bin\utplsql run test_runner/pass@db_url ^ -p=hr,hotel ^ -source_path=sources ^ @@ -527,10 +652,11 @@ Unit test code is mapped to files in `test_results.xml` #### Object-file mapping rules -In order to allow deterministic and accurate mapping of database source-code into project files, the project directory and file structure needs to meet certain criteria. +In order to allow deterministic and accurate mapping of database source-code into project files, the project directory and file structure needs to meet certain criteria. + - Source code is kept separate from test code (separate directories) -- Each database (source-code) object is stored in individual file. Package/type specification is kept separate from it's body. -- File name (file path) contains name of database object +- Each database (source-code) object is stored in an individual file. Package/type specification is kept separate from its body. +- File name (file path) contains the name of database object - Each file-path clearly identifies object type (by file extension) - Each file contains representation of database object "as is". No extra commands (like `set echo off` `ALTER SESSION SET PLSQL_CCFLAGS = 'debug:TRUE';`) or blank lines are present before `CREATE TYPE`,`CREATE TYPE` etc. - When project is spanning across multiple database schemes, each file-path clearly and uniformly identifies object owner @@ -541,6 +667,7 @@ In order to allow deterministic and accurate mapping of database source-code int The `ut.run` command provides interface to map project into database objects when executing tests. While it is much easier to perform mapping directly from command line, it is possible to achieve similar functionality from any SQL client. The main differences when using the `ut.run(...)` command, will be: + - you can only use single reporter and therefore will get only one report from test execution - you need to provide fill list of project files rather than point to `sources` and `tests` directories @@ -592,7 +719,7 @@ C: To execute all tests and map database source code into source file names you could use the following command in any SQL client: -```sql +```sql linenums="1" begin ut.run( ut_varchar2_list('hr','hotel'), @@ -624,7 +751,7 @@ end; ``` To execute all tests and map database tests code into test file names you could use the following command in any SQL client: -```sql +```sql linenums="1" begin ut.run( ut_varchar2_list('hr','hotel'), @@ -657,3 +784,127 @@ begin end; ``` +## Reporting coverage outside utPLSQL and in parallel sessions + +utPSLQL allows fo standalone reporting code coverage across multiple database sessions. This functionality enables coverage reporting for external testing tools. + +Following API calls enable the standalone coverage reporting. + +- `ut_runner.coverage_start( coverage_run_id );` - initiates code coverage within a session +- `ut_runner.coverage_stop();` - stops gathering of code coverage within a session +- `.get_report( ... )` - coverage reporters function producing coverage report as pipelined data-set (to be used in SQL query) +- `.get_report_cursor( ... )` - coverage reporters function producing coverage report as ref-cursor + +Example: +```sql linenums="1" +--SESSION 1 +-- gather coverage on code using specific coverage_run_id value +declare + l_coverage_run_id raw(32); +begin + l_coverage_run_id := 'A6AA5B7361251CE6E053020011ACA055'; +-- l_coverage_run_id := sys_guid; + ut_runner.coverage_start(l_coverage_run_id); + + --The code to gather coverage on goes here + + ut_runner.coverage_stop(); +end; +/ +``` + +```sql linenums="1" +--SESSION 2 +-- alternative approach +-- gather coverage on code using specific coverage_run_id value +exec ut_runner.coverage_start('A6AA5B7361251CE6E053020011ACA055'); + +--The code to gather coverage on goes here + +exec ut_runner.coverage_stop(); +``` + + +```sql linenums="1" +--SESSION 1 or SESSION2 2 or SESSION 3 +-- run after calls in SESSION 1 & 2 are finished +-- retrieve coverage report in HTML format coverage_run_id value +select * + from table( + ut_coverage_html_reporter().get_report( + a_coverage_options => ut_coverage_options( + coverage_run_id => 'A6AA5B7361251CE6E053020011ACA055' + ) + ) + ); +``` + +```sql linenums="1" +--SESSION 1 or SESSION2 2 or SESSION 3 +-- run after calls in SESSION 1 & 2 are finished +declare + l_results_cursor sys_refcursor; +begin + l_results_cursor := ut_coverage_html_reporter().get_report_cursor( + a_coverage_options => ut_coverage_options( + coverage_run_id => 'A6AA5B7361251CE6E053020011ACA055' + ) + ); + --fetch and process the cursor results + close l_results_cursor; +end; +/ +``` + +Specification of parameters for `get_report` and `get_report_cursor` +```sql linenums="1" +function get_report( + a_coverage_options ut_coverage_options, + a_client_character_set varchar2 := null +) return ut_varchar2_rows pipelined +``` + +```sql linenums="1" +function get_report_cursor( + a_coverage_options ut_coverage_options, + a_client_character_set varchar2 := null +) return sys_refcursor +``` +```sql linenums="1" +ut_coverage_options( + coverage_run_id raw, + schema_names ut_varchar2_rows := null, + exclude_objects ut_varchar2_rows := null, + include_objects ut_varchar2_rows := null, + file_mappings ut_file_mappings := null + include_schema_expr varchar2(4000) := null, + include_object_expr varchar2(4000) := null, + exclude_schema_expr varchar2(4000) := null, + exclude_object_expr varchar2(4000) := null +); +``` + +The `a_client_character_set` is used to provide character set to the report. Coverage reports in XML and HTML format include this information to assure that HMTL/XML encoding tag is aligned with encoding of the report produced. +Use this parameter to provide encoding of your client application. + +The `a_coverage_options` parameter is used to control the scope and formatting of data returned by report. + +`ut_coverage_options` object accepts the following arguments + +- `coverage_run_id` - identifier of coverage run to generate report for - data-type `RAW(32)` +- `schema_names` - optional - list of schema names to include in coverage report - data-type `UT_VARCHAR2_ROWS` +- `exclude_objects` - optional - list of object names to exclude from report - data-type `UT_VARCHAR2_ROWS` +- `include_objects` - optional - list of object names to gather coverage on - data-type `UT_VARCHAR2_ROWS` +- `file_mappings` - optional - list of schema names to gather coverage on - data-type `UT_FILE_MAPPINGS` +- `include_schema_expr` - optional - regular expression to match against schema name to include in coverage - data-type `VARCHAR2(4000)` +- `include_object_expr` - optional - regular expression to match against object name to include in coverage - data-type `VARCHAR2(4000)` +- `exclude_schema_expr` - optional - regular expression to match against schema name to exclude in coverage - data-type `VARCHAR2(4000)` +- `exclude_object_expr` - optional - regular expression to match against object name to exclude in coverage - data-type `VARCHAR2(4000)` + +`coverage_run_id` parameter identifies a common coverage run. The valid value type for that parameter is RAW(32). +It is recommended to use `sys_guid()` to generate a common, unique identifier for a specific coverage run. +If the identifier is not unique, previous runs of coverage that used the same `coverage_run_id` will be aggregated to the resulting coverage report. + +For details on the meaning of `schema_names`, `exclude_objects`, `include_objects`, `file_mappings` see sections above. +Note that data-types of include/exclude/schema lists are different when calling `ut.run` vs. calling `get_report/get_report_cursor`. + diff --git a/docs/userguide/exception-reporting.md b/docs/userguide/exception-reporting.md index 852a3f426..824aaecd5 100644 --- a/docs/userguide/exception-reporting.md +++ b/docs/userguide/exception-reporting.md @@ -1,21 +1,28 @@ -# Exception handling and reporting +![version](https://img.shields.io/badge/version-v3.1.14.4206--develop-blue.svg) -The utPLSQL is responsible for handling exceptions wherever they occur in the test run. utPLSQL is trapping most of the exceptions so that the test execution is not affected by individual tests or test packages throwing an exception. -The framework provides a full stacktrace for every exception that was thrown. The stacktrace is clean and does not include any utPLSQL library calls in it. +utPLSQL is responsible for handling exceptions wherever they occur in the test run. The framework is trapping most of the exceptions so that the test execution is not affected by individual tests or test packages throwing an exception. +The framework provides a full stacktrace for every exception that was thrown. The reported stacktrace does not include any utPLSQL library calls in it. To achieve rerunability, the package state invalidation exceptions (ORA-04068, ORA-04061) are not handled and test execution will be interrupted if such exceptions are encountered. This is because of how Oracle behaves on those exceptions. Test execution can fail for different reasons. The failures on different exceptions are handled as follows: -* A test package without body - each `--%test` is reported as failed with exception, nothing is executed -* A test package with _invalid body_ - each `--%test` is reported as failed with exception, nothing is executed -* A test package with _invalid spec_ - package is not considered a valid unit test package and is excluded from execution. When trying to run a test package with invalid spec explicitly, exception is raised. Only valid specifications are parsed for annotations -* A test package that is raising an exception in `--%beforeall` - each `--%test` is reported as failed with exception, `--%test`, `--%beforeeach`, `--%beforetest`, `--%aftertest` and `--%aftereach` are not executed. `--%afterall` is executed to allow cleanup of whatever was done in `--%beforeall` -* A test package that is raising an exception in `--%beforeeach` - each `--%test` is reported as failed with exception, `--%test`, `--%beforetest` and `--%aftertest` is not executed. The `--%aftereach` and `--%afterall` blocks are getting executed to allow cleanup of whatever was done in `--%before...` blocks -* A test package that is raising an exception in `--%beforetest` - the `--%test` is reported as failed with exception, `--%test` is not executed. The `--%aftertest`, `--%aftereach` and `--%afterall` blocks are getting executed to allow cleanup of whatever was done in `--%before...` blocks -* A test package that is raising an exception in `--%test` - the `--%test` is reported as failed with exception. The execution of other blocks continues normally -* A test package that is raising an exception in `--%aftertest` - the `--%test` is reported as failed with exception. The execution of other blocks continues normally -* A test package that is raising an exception in `--%aftereach` - each `--%test` is reported as failed with exception. -* A test package that is raising an exception in `--%afterall` - all blocks of the package are executed, as the `--%afterall` is the last step of package execution. Exception in `--%afterall` is not affecting test results. A warning with exception stacktrace is displayed in the summary +| Problem / error | Framework behavior | +|----------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| A test package **without body** | each `--%test` is reported as failed with exception, nothing is executed | +| A test package with **invalid body** | each `--%test` is reported as failed with exception, nothing is executed | +| A test package with **invalid spec** | package is not considered a valid unit test package and is excluded from execution. When trying to run a test package with invalid spec explicitly, exception is raised. Only valid specifications are parsed for annotations | +| A test package that is raising an exception in `--%beforeall` | each `--%test` is reported as failed with exception, `--%test`, `--%beforeeach`, `--%beforetest`, `--%aftertest` and `--%aftereach` are not executed. `--%afterall` is executed to allow cleanup of whatever was done in `--%beforeall` | +| A test package that is raising an exception in `--%beforeeach` | each `--%test` is reported as failed with exception, `--%test`, `--%beforetest` and `--%aftertest` is not executed. The `--%aftereach` and `--%afterall` blocks are getting executed to allow cleanup of whatever was done in `--%before...` blocks | +| A test package that is raising an exception in `--%beforetest` | the `--%test` is reported as failed with exception, `--%test` is not executed. The `--%aftertest`, `--%aftereach` and `--%afterall` blocks are getting executed to allow cleanup of whatever was done in `--%before...` blocks | +| A test package that is raising an exception in `--%test` | the `--%test` is reported as failed with exception. The execution of other blocks continues normally | +| A test package that is raising an exception in `--%aftertest` | the `--%test` is reported as failed with exception. The execution of other blocks continues normally | +| A test package that is raising an exception in `--%aftereach` | each `--%test` is reported as failed with exception. | +| A test package that is raising an exception in `--%afterall` | all blocks of the package are executed, as the `--%afterall` is the last step of package execution. Exception in `--%afterall` is not affecting test results. A warning with exception stacktrace is displayed in the summary | + + +!!! warning + If an exception is thrown in an `afterall` procedure then **no failure reported by utPLSQL**.
+ Framework will only report a warning on the suite that the `afterall` belongs to. Example of reporting with exception thrown in `%beforetest`: ```` diff --git a/docs/userguide/expectations.md b/docs/userguide/expectations.md index 4c6f3aa68..54c204d58 100644 --- a/docs/userguide/expectations.md +++ b/docs/userguide/expectations.md @@ -1,95 +1,355 @@ -# Expectation concepts +![version](https://img.shields.io/badge/version-v3.1.14.4206--develop-blue.svg) + +## Expectation concepts + Validation of the code under test (the tested logic of procedure/function etc.) is performed by comparing the actual data against the expected data. -utPLSQL uses a combination of expectation and matcher to perform the check on the data. -Example of a unit test procedure body. -```sql +utPLSQL uses expectations and matchers to perform the check on the data. + +Example of an expectation +```sql linenums="1" begin - ut.expect( 'the tested value', 'optional custom failure message' ).to_( equal('the expected value') ); + ut.expect( 'the tested value' ).to_equal('the expected value'); end; +/ +``` + +Returns following output via DBMS_OUTPUT: +``` +FAILURE + Actual: 'the tested value' (varchar2) was expected to equal: 'the expected value' (varchar2) + at "anonymous block", line 2 ``` -Expectation is a set of the expected value(s), actual values(s) and the matcher(s) to run on those values. -You can also add a custom failure message for an expectation. +Expectation is a combination of: -Matcher defines the comparison operation to be performed on expected and actual values. +- the expected value +- optional custom message for the expectation +- the matcher used to perform comparison +- the matcher parameters (actual value), depending on the matcher type + + +Matcher defines the comparison operation to be performed on expected (and actual) value. Pseudo-code: -```sql +```sql linenums="1" ut.expect( a_actual {data-type} [, a_message {varchar2}] ).to_( {matcher} ); ut.expect( a_actual {data-type} [, a_message {varchar2}] ).not_to( {matcher} ); ``` -All matchers have shortcuts like below, sou you don't need to surround matcher with brackets, unless you want to pass it as parameter to the expectation. -```sql - ut.expect( a_actual {data-type} ).to_{matcher}; - ut.expect( a_actual {data-type} ).not_to_{matcher}; +Expectations provide two variants of syntax that you can use. Both variants are functionally-equal but give different usage flexibility. + +Syntax where matcher is passed as parameter to the expectation: +```sql linenums="1" + ut.expect( a_actual ).to_( {matcher} ); + ut.expect( a_actual ).not_to( {matcher} ); + -- example + ut.expect( 1 ).to_( be_null() ); ``` -## Providing a custom failure message -You can provide a custom failure message as second argument for the expectation. -````sql - -- Pseudocode - ut.expect( a_actual {data-type}, a_message {varchar2} ).to_{matcher}; - -- Example - ut.expect( 'supercat', 'checked superhero-animal was not a dog' ).to_( equal('superdog') ); -```` +Shortcut syntax, where matcher is directly part of expectation: +```sql linenums="1" + ut.expect( a_actual ).to_{matcher}; + ut.expect( a_actual ).not_to_{matcher}; + + --example + ut.expect( 1 ).to_be_null(); +``` -If the message is provided, it is being added to the normal failure message returned by the matcher. +When using shortcut syntax you don't need to surround matcher with brackets. Shortcut syntax is provided for convenience. -This is mostly useful when your expectations accept dynamic content, as you can provide additional context to make failing test results more readable. +If you would like to perform more dynamic checks in your code, you could pass the matcher into a procedure like in the below example: +```sql linenums="1" +declare + procedure do_check( p_actual varchar2, p_matcher ut_matcher ) is + begin + ut.expect(p_actual).to_( p_matcher ); + end; +begin + do_check( 'a', equal('b') ); + do_check( 'Alibaba', match('ali','i') ); +end; +/ +``` + +Returns following output via DBMS_OUTPUT: +``` +FAILURE + Actual: 'a' (varchar2) was expected to equal: 'b' (varchar2) + at "anonymous block", line 4 + at "anonymous block", line 7 +SUCCESS + Actual: 'Alibaba' (varchar2) was expected to match: 'ali' , modifiers 'i' +``` + +!!! note + In order to keep the document brief, the examples in the document are only using the standalone expectations syntax. + +## Using expectations -### Dynamic tests example -You have a bunch of tables and an archive functionality for them and you want to test if the things you put into live-tables are removed from live-tables and present in archive-tables. +There are two ways to use expectations: +- by invoking utPLSQL framework to execute suite(s) of utPLSQL tests +- without invoking the utPLSQL framework - running expectations standalone -````sql -procedure test_data_existance( i_tableName varchar2 ) - as - v_count_real integer; - v_count_archive integer; +## Running expectations within utPLSQL framework + +When expectations are run as a part of a test suite, the framework tracks: + +- status of each expectation +- outcomes (messages) produced by each expectation +- call stack to each expectation + +In this case: + +- expectation results of are not sent directly to `dbms_output` +- utPLSQL Reporters used when running suite decide on how the expectation results are formatted and displayed + +Example of test suite with an expectation: +```sql linenums="1" +create or replace package test_divide as + --%suite(Divide two numbers) + + --%test(Returns result when divisor is not zero) + procedure divide_6_by_2; + + --%test(Throws exception when divisor is zero) + --%throws(zero_divide) + procedure divide_by_0_throws; +end; +/ + +create or replace package body test_divide as + procedure divide_6_by_2 is begin + ut.expect(6/2).to_equal(3); + end; - execute immediate 'select count(*) from ' || i_tablename || '' into v_count_real; - execute immediate 'select count(*) from ' || i_tablename || '_ARCHIVE' into v_count_archive; + procedure divide_by_0_throws is + begin + ut.expect(6/0).to_be_not_null(); + end; +end; +/ - ut.expect( v_count_archive, 'failure checking entry-count of ' || i_tablename || '_archive' ).to_( equal(1) ); - ut.expect( v_count_real, 'failure checking entry-count of ' || i_tablename ).to_( equal(0) ); +exec ut.run('test_divide'); - end; +drop package test_divide; +``` - procedure test_archive_data - as - begin - -- Arrange - -- insert several data into real-tables here +Produces following outputs: +``` +Package TEST_DIVIDE compiled - -- Act - package_to_test.archive_data(); - -- Assert - test_data_existance('TABLE_A'); - test_data_existance('TABLE_B'); - test_data_existance('TABLE_C'); - test_data_existance('TABLE_D'); -end; -```` -A failed output will look like this: +Package Body TEST_DIVIDE compiled + +Divide two numbers + Returns result when divisor is not zero [.003 sec] + Throws exception when divisor is zero [.003 sec] + +Finished in .009774 seconds +2 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s) + + + +PL/SQL procedure successfully completed. + + +Package TEST_DIVIDE dropped. +``` + +Please read about different options for [running test suites](running-unit-tests.md). + +## Running expectations outside utPLSQL framework +When expectations are invoked outside of utPLSQL framework the outputs from expectations are redirected straight to `dbms_output`. + +!!! note + The output from expectation contains call stack trace only when expectation fails.
+ Source code of the line which called the expectation is only reported when the line is part of in-database code (package) and the user calling expectation has privileges to see that source code. + +!!! warning "**Important**" + Please do not use expectations as part of your production code. They are not designed to be used as part of your code. Expectations are meant to be used only as part of your day-to-day testing activities. + + +## Matchers +utPLSQL provides the following matchers to perform checks on the expected and actual values. + +- `be_between( a_upper_bound {data-type}, a_lower_bound {data-type} )` +- `be_empty()` +- `be_false()` +- `be_greater_than( a_expected {data-type} )` +- `be_greater_or_equal( a_expected {data-type} )` +- `be_less_or_equal( a_expected {data-type} )` +- `be_less_than( a_expected {data-type} )` +- `be_like( a_mask {varchar2} [, a_escape_char {varchar2}] )` +- `be_not_null()` +- `be_null()` +- `be_true()` +- `equal( a_expected {data-type} [, a_nulls_are_equal {boolean}] )` +- `contain( a_expected {data-type})` +- `have_count( a_expected {integer} )` +- `match( a_patter {varchar2} [, a_modifiers {varchar2}] )` + +## Providing a custom message +You can provide a custom failure message by passing it as the second parameter to the expectation. +`ut.expect( a_actual {data-type}, a_message {varchar2} ).to_{matcher}` + +Example: +````sql linenums="1" +exec ut.expect( 'supercat', 'checked superhero-animal was not a dog' ).to_equal('superdog'); ```` + +Returns following output via DBMS_OUTPUT: +``` +FAILURE + "checked superhero-animal was not a dog" + Actual: 'supercat' (varchar2) was expected to equal: 'superdog' (varchar2) + at "anonymous block", line 1 +``` +If the message is provided, it is being added to the normal failure message returned by the matcher. +This is mostly useful when your expectations accept dynamic content, as you can provide additional context to make failing test results more readable. + +In most cases, there is no need to provide custom message to expectation. This is because utPLSQL identifies: + +- The test used to execute the expectation +- The line number where the expectation is placed in your test code +- The line text of the expectation + +Custom message is useful, if your expectation is placed in a shared procedure to perform a check and your test is using the procedure multiple times. + +Example: +```sql linenums="1" +create or replace package shared_expectation_test is + --%suite + + --%test + procedure the_test; +end; +/ +create or replace package body shared_expectation_test is + procedure table_is_empty(p_table_name varchar2) is + l_count integer; + begin + execute immediate 'select count(*) from '||p_table_name into l_count; + ut.expect( l_count, 'Checking table '||p_table_name ).to_equal(0); + end; + + procedure the_test is + begin + table_is_empty('ALL_USERS'); + table_is_empty('ALL_TABLES'); + end; +end; +/ + +exec ut.run('shared_expectation_test'); +``` + +Returns following output via DBMS_OUTPUT: +``` +shared_expectation_test + the_test [.064 sec] (FAILED - 1) + Failures: - 1) test_archive_data - "failure checking entry-count of table_a_archive" - Actual: 2 (number) was expected to equal: 1 (number) - at "UT_TEST_PACKAGE.TEST_DATA_EXISTANCE", line 12 ut.expect( v_count_archive, 'failure checking entry-count of ' || i_tablename || '_archive' ).to_( equal(1) ); -```` + 1) the_test + "Checking table ALL_USERS" + Actual: 28 (number) was expected to equal: 0 (number) + at "UT3_USER.SHARED_EXPECTATION_TEST.TABLE_IS_EMPTY", line 6 ut.expect( l_count, 'Checking table '||p_table_name ).to_equal(0); + at "UT3_USER.SHARED_EXPECTATION_TEST.THE_TEST", line 11 + + "Checking table ALL_TABLES" + Actual: 55 (number) was expected to equal: 0 (number) + at "UT3_USER.SHARED_EXPECTATION_TEST.TABLE_IS_EMPTY", line 6 ut.expect( l_count, 'Checking table '||p_table_name ).to_equal(0); + at "UT3_USER.SHARED_EXPECTATION_TEST.THE_TEST", line 12 + +Finished in .066344 seconds +1 tests, 1 failed, 0 errored, 0 disabled, 0 warning(s) +``` + +In the tests results window you can see the list of failed expectations for a test as well as: -# Expecting exceptions +- the additional message for expectation +- the reason why the expectation failed +- the line number of the expectation +- the line text of the expectations +- the call stack for the expectation (in the example it's the lines that called the procedure `table_is_empty`) -Testing is not limited to checking for happy-path scenarios. When writing tests, you often want to check that in specific scenarios, an exception is thrown. +## Negating a matcher -Use the `--%throws` annotation, to test for expected exceptions +Expectations provide a very convenient way to perform a check on a negated matcher. + +Syntax to check for matcher evaluating to true: +```sql linenums="1" +begin + ut.expect( a_actual {data-type} ).to_{matcher}; + ut.expect( a_actual {data-type} ).to_( {matcher} ); +end; +``` + +Syntax to check for matcher evaluating to false: +```sql linenums="1" +begin + ut.expect( a_actual {data-type} ).not_to_{matcher}; + ut.expect( a_actual {data-type} ).not_to( {matcher} ); +end; +``` + +If a matcher evaluated to NULL, then both `to_` and `not_to` will cause the expectation to report failure. + +Example: +```sql linenums="1" +declare + l_actual boolean; +begin + ut.expect( l_actual ).to_be_true(); + ut.expect( l_actual ).not_to_be_true(); +end; +/ +``` + +Returns following output via DBMS_OUTPUT: +``` +FAILURE + Actual: NULL (boolean) was expected to be true + at "anonymous block", line 4 +FAILURE + Actual: NULL (boolean) was expected not to be true + at "anonymous block", line 5 +``` +Since NULL is neither *true* nor *false*, both expectations will report failure. + +## Supported data types + +The matrix below illustrates the data types supported by different matchers. + +| Matcher | blob | boolean | clob | date | number | timestamp | timestamp
with
timezone | timestamp
with
local
timezone | varchar2 | interval
year
to
month | interval
day
to
second | cursor | nested
table
/ varray | object | json | +| :-----------------------: | :--: | :-----: | :--: | :--: | :----: | :-------: | :---------------------------: | :------------------------------------: | :------: | :-----------------------------: | :-----------------------------: | :----: | :-------------------------: | :----: | :--: | +| **be_not_null** | X | X | X | X | X | X | X | X | X | X | X | X | X | X | X | +| **be_null** | X | X | X | X | X | X | X | X | X | X | X | X | X | X | X | +| **be_false** | | X | | | | | | | | | | | | | | +| **be_true** | | X | | | | | | | | | | | | | | +| **be_greater_than** | | | | X | X | X | X | X | | X | X | | | | | +| **be_greater_or_equal** | | | | X | X | X | X | X | | X | X | | | | | +| **be_less_or_equal** | | | | X | X | X | X | X | | X | X | | | | | +| **be_less_than** | | | | X | X | X | X | X | | X | X | | | | | +| **be_between** | | | | X | X | X | X | X | X | X | X | | | | | +| **equal** | X | X | X | X | X | X | X | X | X | X | X | X | X | X | X | +| **contain** | | | | | | | | | | | | X | X | X | | +| **match** | | | X | | | | | | X | | | | | | | +| **be_like** | | | X | | | | | | X | | | | | | | +| **be_empty** | X | | X | | | | | | | | | X | X | | X | +| **have_count** | | | | | | | | | | | | X | X | | X | +| **be_within().of_()** | | | | X | X | X | X | X | | | | | | | | +| **be_within_pct().of_()** | | | | | X | | | | | | | | | | | + +## Expecting exceptions + +Testing is not limited to checking for happy-path scenarios. When writing tests, you often want to validate that in specific scenarios, an exception is thrown. + +Use the `--%throws` annotation, to test for expected exceptions. Example: -```sql +```sql linenums="1" create or replace function divide(x varchar2, y varchar2) return number is begin return x/y; @@ -99,9 +359,6 @@ end; create or replace package test_divide as --%suite(Divide function) - --%test(Return divided numbers) - procedure divides_numbers; - --%test(Throws divisor equal) --%throws(-01476) procedure raises_divisor_exception; @@ -110,11 +367,6 @@ end; create or replace package body test_divide is - procedure divides_numbers is - begin - ut3.ut.expect(divide(6,2)).to_equal(3); - end; - procedure raises_divisor_exception is x integer; begin @@ -124,338 +376,865 @@ create or replace package body test_divide is end; / -exec ut3.ut.run('test_divide'); +exec ut.run('test_divide'); ``` -For details see documentation of the [`--%throws` annotation.](annotations.md#throws-annotation) +Returns following output via DBMS_OUTPUT: +``` +Divide function + Throws divisor equal [.007 sec] + +Finished in .009229 seconds +1 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s) +``` +For more details see documentation of the [`--%throws` annotation.](annotations.md#throws) + + +## Matchers + +You can choose different matchers to validate that your PL/SQL code is working as expected. -# Matchers -utPLSQL provides the following matchers to perform checks on the expected and actual values. -- `be_between` -- `be_empty` -- `be_false` -- `be_greater_than` -- `be_greater_or_equal` -- `be_less_or_equal` -- `be_less_than` -- `be_like` -- `be_not_null` -- `be_null` -- `be_true` -- `equal` -- `have_count` -- `match` - -## be_between +### be_between Validates that the actual value is between the lower and upper bound. Example: -```sql +```sql linenums="1" +declare + l_timestamp timestamp := current_timestamp; + l_timestamp_tz timestamp with time zone := systimestamp; + l_timestamp_ltz timestamp with local time zone := systimestamp; + l_interval_ds interval day to second := interval '1' second; + l_interval_ym interval year to month := interval '1' year; begin - ut.expect( a_actual => 3 ).to_be_between( a_lower_bound => 1, a_upper_bound => 3 ); ut.expect( 3 ).to_be_between( 1, 3 ); - --or - ut.expect( a_actual => 3 ).to_( be_between( a_lower_bound => 1, a_upper_bound => 3 ) ); - ut.expect( 3 ).to_( be_between( 1, 3 ) ); + ut.expect( 5 ).to_( be_between( 1, 3 ) ); + ut.expect( 3 ).not_to_be_between( 1, 3 ); + ut.expect( 5 ).not_to( be_between( 1, 3 ) ); + ut.expect( sysdate ).to_be_between( sysdate, sysdate + 1 ); + ut.expect( l_timestamp ).to_be_between( l_timestamp, l_timestamp ); + ut.expect( systimestamp ).to_be_between( l_timestamp_tz, systimestamp ); + ut.expect( systimestamp ).to_be_between( l_timestamp_ltz, l_timestamp_ltz ); + ut.expect( l_interval_ds ).to_be_between( interval '0.1' second, interval '1' day ); + ut.expect( l_interval_ym ).to_be_between( interval '12' month, interval '12' year ); + ut.expect( 'Abb' ).to_be_between( 'Aba', 'Abc' ); end; +/ +``` + +Returns following output via DBMS_OUTPUT: +``` +SUCCESS + Actual: 3 (number) was expected to be between: 1 and 3 +FAILURE + Actual: 5 (number) was expected to be between: 1 and 3 + at "anonymous block", line 9 +FAILURE + Actual: 3 (number) was expected not to be between: 1 and 3 + at "anonymous block", line 10 +SUCCESS + Actual: 5 (number) was expected not to be between: 1 and 3 +SUCCESS + Actual: 2019-07-07T21:25:27 (date) was expected to be between: 2019-07-07T21:25:27 and 2019-07-08T21:25:27 +SUCCESS + Actual: 2019-07-07T22:25:27.701546000 (timestamp) was expected to be between: 2019-07-07T22:25:27.701546000 and 2019-07-07T22:25:27.701546000 +SUCCESS + Actual: 2019-07-07T21:25:27.705768000 +00:00 (timestamp with time zone) was expected to be between: 2019-07-07T21:25:27.701596000 +00:00 and 2019-07-07T21:25:27.705808000 +00:00 +FAILURE + The matcher 'be between' cannot be used with data type (timestamp with time zone). + at "anonymous block", line 15 +SUCCESS + Actual: +000000000 00:00:01.000000000 (interval day to second) was expected to be between: +000000000 00:00:00.100000000 and +000000001 00:00:00.000000000 +SUCCESS + Actual: +000000001-00 (interval year to month) was expected to be between: +000000001-00 and +000000012-00 +SUCCESS + Actual: 'Abb' (varchar2) was expected to be between: 'Aba' and 'Abc' ``` -## be_empty +### be_empty Unary matcher that validates if the provided dataset is empty. Can be used with `BLOB`,`CLOB`, `refcursor` or `nested table`/`varray` passed as `ANYDATA` -**Note:** -BLOB/CLOB that is initialized is not NULL but it is actually equal to `empty_blob()`/`empty_clob()`. +!!! note + BLOB/CLOB that is initialized is not NULL but it is actually equal to `empty_blob()`/`empty_clob()`. -Usage: -```sql -procedure test_if_cursor_is_empty is +Example: +```sql linenums="1" +declare l_cursor sys_refcursor; begin - open l_cursor for select * from dual where 1 = 0; + open l_cursor for select * from dual where 0=1; ut.expect( l_cursor ).to_be_empty(); - --or - ut.expect( l_cursor ).to_( be_empty() ); + ut.expect( anydata.convertCollection(ut_varchar2_list()) ).to_( be_empty() ); + ut.expect( empty_clob() ).not_to_be_empty(); + ut.expect( empty_blob() ).not_to( be_empty() ); + ut.expect( 1 ).not_to( be_empty() ); end; +/ ``` -```sql -procedure test_if_cursor_is_empty is - l_data ut_varchar2_list; -begin - l_data := ut_varchar2_list(); - ut.expect( anydata.convertCollection( l_data ) ).to_be_empty(); - --or - ut.expect( anydata.convertCollection( l_data ) ).to_( be_empty() ); -end; +Returns following output via DBMS_OUTPUT: +``` +SUCCESS + Actual: (refcursor [ count = 0 ]) + Data-types: + VARCHAR2 + Data: + was expected to be empty +SUCCESS + Actual: (ut3.ut_varchar2_list [ count = 0 ]) + Data-types: + VARCHAR2 + Data: + was expected to be empty +FAILURE + Actual: EMPTY (clob) was expected not to be empty + at "anonymous block", line 7 +FAILURE + Actual: EMPTY (blob) was expected not to be empty + at "anonymous block", line 8 +FAILURE + The matcher 'be empty' cannot be used with data type (number). + at "anonymous block", line 9 ``` -## be_false +### be_false Unary matcher that validates if the provided value is false. Usage: -```sql +```sql linenums="1" begin ut.expect( ( 1 = 0 ) ).to_be_false(); - --or - ut.expect( ( 1 = 0 ) ).to_( be_false() ); + ut.expect( ( 1 = 1 ) ).to_( be_false() ); + ut.expect( ( 1 = 0 ) ).not_to_be_false(); + ut.expect( ( 1 = 1 ) ).not_to( be_false() ); end; +/ +``` + +Returns following output via DBMS_OUTPUT: +``` +SUCCESS + Actual: FALSE (boolean) was expected to be false +FAILURE + Actual: TRUE (boolean) was expected to be false + at "anonymous block", line 3 +FAILURE + Actual: FALSE (boolean) was expected not to be false + at "anonymous block", line 4 +SUCCESS + Actual: TRUE (boolean) was expected not to be false ``` -## be_greater_or_equal +### be_greater_or_equal Checks if the actual value is greater or equal than the expected. Usage: -```sql +```sql linenums="1" begin ut.expect( sysdate ).to_be_greater_or_equal( sysdate - 1 ); - --or - ut.expect( sysdate ).to_( be_greater_or_equal( sysdate - 1 ) ); + ut.expect( sysdate ).to_( be_greater_or_equal( sysdate + 1 ) ); + ut.expect( sysdate ).not_to_be_greater_or_equal( sysdate - 1 ); + ut.expect( sysdate ).not_to( be_greater_or_equal( sysdate + 1 ) ); end; +/ +``` + +Returns following output via DBMS_OUTPUT: +``` +SUCCESS + Actual: 2019-07-07T22:43:29 (date) was expected to be greater or equal: 2019-07-06T22:43:29 (date) +FAILURE + Actual: 2019-07-07T22:43:29 (date) was expected to be greater or equal: 2019-07-08T22:43:29 (date) + at "anonymous block", line 3 +FAILURE + Actual: 2019-07-07T22:43:29 (date) was expected not to be greater or equal: 2019-07-06T22:43:29 (date) + at "anonymous block", line 4 +SUCCESS + Actual: 2019-07-07T22:43:29 (date) was expected not to be greater or equal: 2019-07-08T22:43:29 (date) ``` -## be_greater_than +### be_greater_than Checks if the actual value is greater than the expected. Usage: -```sql +```sql linenums="1" begin ut.expect( 2 ).to_be_greater_than( 1 ); - --or - ut.expect( 2 ).to_( be_greater_than( 1 ) ); + ut.expect( 0 ).to_( be_greater_than( 1 ) ); + ut.expect( 2 ).not_to_be_greater_than( 1 ); + ut.expect( 0 ).not_to( be_greater_than( 1 ) ); end; +/ +``` + +Returns following output via DBMS_OUTPUT: +``` +SUCCESS + Actual: 2 (number) was expected to be greater than: 1 (number) +FAILURE + Actual: 0 (number) was expected to be greater than: 1 (number) + at "anonymous block", line 3 +FAILURE + Actual: 2 (number) was expected not to be greater than: 1 (number) + at "anonymous block", line 4 +SUCCESS + Actual: 0 (number) was expected not to be greater than: 1 (number) ``` -## be_less_or_equal +### be_less_or_equal Checks if the actual value is less or equal than the expected. Usage: -```sql +```sql linenums="1" begin ut.expect( 3 ).to_be_less_or_equal( 3 ); - --or - ut.expect( 3 ).to_( be_less_or_equal( 3 ) ); + ut.expect( 4 ).to_( be_less_or_equal( 3 ) ); + ut.expect( 3 ).not_to_be_less_or_equal( 3 ); + ut.expect( 4 ).not_to( be_less_or_equal( 3 ) ); end; +/ ``` -## be_less_than +Returns following output via DBMS_OUTPUT: +``` +SUCCESS + Actual: 3 (number) was expected to be less or equal: 3 (number) +FAILURE + Actual: 4 (number) was expected to be less or equal: 3 (number) + at "anonymous block", line 3 +FAILURE + Actual: 3 (number) was expected not to be less or equal: 3 (number) + at "anonymous block", line 4 +SUCCESS + Actual: 4 (number) was expected not to be less or equal: 3 (number) +``` + +### be_less_than Checks if the actual value is less than the expected. Usage: -```sql +```sql linenums="1" begin ut.expect( 3 ).to_be_less_than( 2 ); - --or - ut.expect( 3 ).to_( be_less_than( 2 ) ); + ut.expect( 0 ).to_( be_less_than( 2 ) ); + ut.expect( 3 ).not_to_be_less_than( 2 ); + ut.expect( 0 ).not_to( be_less_than( 2 ) ); end; +/ ``` +Returns following output via DBMS_OUTPUT: +``` +FAILURE + Actual: 3 (number) was expected to be less than: 2 (number) + at "anonymous block", line 2 +SUCCESS + Actual: 0 (number) was expected to be less than: 2 (number) +SUCCESS + Actual: 3 (number) was expected not to be less than: 2 (number) +FAILURE + Actual: 0 (number) was expected not to be less than: 2 (number) + at "anonymous block", line 5 +``` -## be_like +### be_like Validates that the actual value is like the expected expression. +Syntax: + +`ut.expect( a_actual ).to_be_like( a_mask [, a_escape_char] )` + +Parameters `a_mask` and `a_escape_char` represent valid parameters of the [Oracle LIKE condition](https://docs.oracle.com/database/121/SQLRF/conditions007.htm#SQLRF52142). + +If you use Oracle Database version 11.2.0.4, you may run into Oracle Bug 14402514: WRONG RESULTS WITH LIKE ON CLOB USING ESCAPE CHARACTER. In this case we recommend to use `match` instead of `be_like`. + Usage: -```sql +```sql linenums="1" begin - ut.expect( 'Lorem_impsum' ).to_be_like( a_mask => '%rem#_%', a_escape_char => '#' ); - ut.expect( 'Lorem_impsum' ).to_be_like( '%rem#_%', '#' ); - --or - ut.expect( 'Lorem_impsum' ).to_( be_like( a_mask => '%rem#_%', a_escape_char => '#' ) ); - ut.expect( 'Lorem_impsum' ).to_( be_like( '%rem#_%', '#' ) ); + ut.expect( 'Lorem_impsum' ).to_be_like( '%rem%'); + ut.expect( 'Lorem_impsum' ).to_be_like( '%rem\_i%', '\' ); + ut.expect( 'Lorem_impsum' ).to_( be_like( 'Lor_m%' ) ); + ut.expect( 'Lorem_impsum' ).not_to_be_like( '%rem%'); + ut.expect( 'Lorem_impsum' ).not_to( be_like( '%reM%') ); end; +/ ``` -Parameters `a_mask` and `a_escape_char` represent valid parameters of the [Oracle LIKE condition](https://docs.oracle.com/database/121/SQLRF/conditions007.htm#SQLRF52142) - +Returns following output via DBMS_OUTPUT: +``` +SUCCESS + Actual: 'Lorem_impsum' (varchar2) was expected to be like: '%rem%' +SUCCESS + Actual: 'Lorem_impsum' (varchar2) was expected to be like: '%rem\_i%' , escape '\' +SUCCESS + Actual: 'Lorem_impsum' (varchar2) was expected to be like: 'Lor_m%' +FAILURE + Actual: 'Lorem_impsum' (varchar2) was expected not to be like: '%rem%' + at "anonymous block", line 5 +SUCCESS + Actual: 'Lorem_impsum' (varchar2) was expected not to be like: '%reM%' +``` -## be_not_null +### be_not_null Unary matcher that validates if the actual value is not null. Usage: -```sql +```sql linenums="1" begin ut.expect( to_clob('ABC') ).to_be_not_null(); - --or - ut.expect( to_clob('ABC') ).to_( be_not_null() ); - --or - ut.expect( to_clob('ABC') ).not_to( be_null() ); + ut.expect( to_clob('') ).to_( be_not_null() ); + ut.expect( to_clob('ABC') ).not_to_be_not_null(); + ut.expect( '').not_to( be_not_null() ); end; +/ ``` -## be_null +Returns following output via DBMS_OUTPUT: +``` +SUCCESS + Actual: 'ABC' (clob) was expected to be not null +FAILURE + Actual: NULL (clob) was expected to be not null + at "anonymous block", line 3 +FAILURE + Actual: 'ABC' (clob) was expected not to be not null + at "anonymous block", line 4 +SUCCESS + Actual: NULL (varchar2) was expected not to be not null +``` + +### be_null Unary matcher that validates if the actual value is null. Usage: -```sql +```sql linenums="1" begin - ut.expect( cast(null as varchar2(100)) ).to_be_null(); - --or - ut.expect( cast(null as varchar2(100)) ).to_( be_null() ); + ut.expect( '' ).to_be_null(); + ut.expect( 0 ).to_( be_null() ); + ut.expect( '' ).not_to_be_null(); + ut.expect( 0 ).not_to( be_null() ); end; +/ ``` -## be_true +Returns following output via DBMS_OUTPUT: +``` +SUCCESS + Actual: NULL (varchar2) was expected to be null +FAILURE + Actual: 0 (number) was expected to be null + at "anonymous block", line 3 +FAILURE + Actual: NULL (varchar2) was expected not to be null + at "anonymous block", line 4 +SUCCESS + Actual: 0 (number) was expected not to be null +``` + +### be_true Unary matcher that validates if the provided value is true. -- `boolean` Usage: -```sql -begin - ut.expect( ( 1 = 1 ) ).to_be_true(); - --or +```sql linenums="1" +begin + ut.expect( ( 1 = 0 ) ).to_be_true(); ut.expect( ( 1 = 1 ) ).to_( be_true() ); + ut.expect( ( 1 = 0 ) ).not_to_be_true(); + ut.expect( ( 1 = 1 ) ).not_to( be_true() ); end; +/ +``` + +Returns following output via DBMS_OUTPUT: +``` +FAILURE + Actual: FALSE (boolean) was expected to be true + at "anonymous block", line 2 +SUCCESS + Actual: TRUE (boolean) was expected to be true +SUCCESS + Actual: FALSE (boolean) was expected not to be true +FAILURE + Actual: TRUE (boolean) was expected not to be true + at "anonymous block", line 5 ``` -## have_count +### have_count Unary matcher that validates if the provided dataset count is equal to expected value. -Can be used with `refcursor` or `table type` +Can be used with `refcursor`, `json` or `table type` Usage: -```sql -procedure test_if_cursor_is_empty is +```sql linenums="1" +declare l_cursor sys_refcursor; + l_collection ut_varchar2_list; begin open l_cursor for select * from dual connect by level <=10; ut.expect( l_cursor ).to_have_count(10); - --or + open l_cursor for select rownum from xmltable('1 to 5'); ut.expect( l_cursor ).to_( have_count(10) ); + l_collection := ut_varchar2_list( 'a', 'a', 'b' ); + ut.expect( anydata.convertCollection( l_collection ) ).not_to_have_count(10); + ut.expect( anydata.convertCollection( l_collection ) ).not_to( have_count(3) ); end; +/ ``` -## match +Returns following output via DBMS_OUTPUT: +``` +SUCCESS + Actual: (refcursor [ count = 10 ]) was expected to have [ count = 10 ] +FAILURE + Actual: (refcursor [ count = 5 ]) was expected to have [ count = 10 ] + at "anonymous block", line 8 +SUCCESS + Actual: ut3.ut_varchar2_list [ count = 3 ] was expected not to have [ count = 10 ] +FAILURE + Actual: ut3.ut_varchar2_list [ count = 3 ] was expected not to have [ count = 3 ] + at "anonymous block", line 11 +``` + +### match Validates that the actual value is matching the expected regular expression. +Syntax: + +`ut.expect( a_actual ).to_match( a_pattern [, a_modifiers] );` + +Parameters `a_pattern` and `a_modifiers` represent a valid regexp pattern accepted by [Oracle REGEXP_LIKE condition](https://docs.oracle.com/database/121/SQLRF/conditions007.htm#SQLRF00501) + Usage: -```sql +```sql linenums="1" begin - ut.expect( a_actual => '123-456-ABcd' ).to_match( a_pattern => '\d{3}-\d{3}-[a-z]', a_modifiers => 'i' ); - ut.expect( 'some value' ).to_match( '^some.*' ); - --or - ut.expect( a_actual => '123-456-ABcd' ).to_( match( a_pattern => '\d{3}-\d{3}-[a-z]', a_modifiers => 'i' ) ); - ut.expect( 'some value' ).to_( match( '^some.*' ) ); + ut.expect( '123-456-ABcd' ).to_match( '\d{3}-\d{3}-[a-z]{4}', 'i' ); + ut.expect( 'some value' ).to_( match( '^some.*' ) ) ; + ut.expect( '123-456-ABcd' ).not_to_match( '\d{3}-\d{3}-[a-z]{4}', 'i' ); + ut.expect( 'some value' ).not_to( match( '^some.*' ) ) ; end; +/ ``` -Parameters `a_pattern` and `a_modifiers` represent a valid regexp pattern accepted by [Oracle REGEXP_LIKE condition](https://docs.oracle.com/database/121/SQLRF/conditions007.htm#SQLRF00501) +Returns following output via DBMS_OUTPUT: +``` +SUCCESS + Actual: '123-456-ABcd' (varchar2) was expected to match: '\d{3}-\d{3}-[a-z]{4}' , modifiers 'i' +SUCCESS + Actual: 'some value' (varchar2) was expected to match: '^some.*' +FAILURE + Actual: '123-456-ABcd' (varchar2) was expected not to match: '\d{3}-\d{3}-[a-z]{4}' , modifiers 'i' + at "anonymous block", line 4 +FAILURE + Actual: 'some value' (varchar2) was expected not to match: '^some.*' + at "anonymous block", line 5 +``` -## equal -The equal matcher is very restrictive. Test using this matcher succeeds only when the compared data-types are exactly the same. -If you are comparing `varchar2` to a `number` will fail even if the text contains the same numeric value as the number. +### equal +The `equal` matcher is very restrictive. Test using this matcher succeeds only when the compared data-types are exactly the same. +If you are comparing a `varchar2` to a `number`, it will fail even if the text contains the same numeric value as the number. The matcher will also fail when comparing a `timestamp` to a `timestamp with timezone` data-type etc. -The matcher enables detection data-type changes. + +The matcher enables detection of data-type changes. If you expect your variable to be a number and it is now some other type, the test will fail and give you early indication of a potential problem. To keep it simple, the `equal` matcher will only succeed if you compare apples to apples. +Syntax: + +`ut.expect( a_actual ).to_equal( a_expected [, a_nulls_are_equal])[.advanced_options]` Example usage -```sql -function get_animal return varchar2 is +```sql linenums="1" +declare + l_actual varchar2(20); + l_expected varchar2(20); begin - return 'a dog'; + --Arrange + l_actual := 'a dog'; + --Assert + ut.expect( l_actual ).to_equal( 'other_dog' ); + ut.expect( l_actual ).to_equal( '' ); + ut.expect( l_actual ).to_equal( 1 ); + + l_actual := null; + ut.expect( l_actual ).to_equal( '' ); + ut.expect( l_actual ).to_equal( '', a_nulls_are_equal => false ); + ut.expect( l_actual ).not_to_equal( '' ); + ut.expect( sysdate ).to_equal( sysdate ); + ut.expect( sysdate ).to_equal( current_timestamp ); + ut.expect( current_timestamp ).to_equal( systimestamp ); + ut.expect( to_clob('varchar') ).to_equal( 'varchar' ); + ut.expect( to_blob('aa') ).to_equal( to_blob('aa') ); + ut.expect( to_clob('aa') ).to_equal( to_clob('aa') ); + ut.expect( to_blob('aa') ).to_equal( to_clob('aa') ); end; / +``` -create or replace package test_animals_getter is +Returns following output via DBMS_OUTPUT: +``` +FAILURE + Actual: 'a dog' (varchar2) was expected to equal: 'other_dog' (varchar2) + at "anonymous block", line 8 +FAILURE + Actual: 'a dog' (varchar2) was expected to equal: NULL (varchar2) + at "anonymous block", line 9 +FAILURE + Actual (varchar2) cannot be compared to Expected (number) using matcher 'equal'. + at "anonymous block", line 10 +SUCCESS + Actual: NULL (varchar2) was expected to equal: NULL (varchar2) +FAILURE + Actual: NULL (varchar2) was expected to equal: NULL (varchar2) + at "anonymous block", line 14 +FAILURE + Actual: NULL (varchar2) was expected not to equal: NULL (varchar2) + at "anonymous block", line 15 +SUCCESS + Actual: 2019-07-07T22:50:21 (date) was expected to equal: 2019-07-07T22:50:21 (date) +FAILURE + Actual (date) cannot be compared to Expected (timestamp with time zone) using matcher 'equal'. + at "anonymous block", line 17 +FAILURE + Actual: 2019-07-07T23:50:21.159268000 +01:00 (timestamp with time zone) was expected to equal: 2019-07-07T22:50:21.159296000 +00:00 (timestamp with time zone) + at "anonymous block", line 18 +FAILURE + Actual (clob) cannot be compared to Expected (varchar2) using matcher 'equal'. + at "anonymous block", line 19 +SUCCESS + Actual: 'AA' (blob) was expected to equal: 'AA' (blob) +SUCCESS + Actual: 'aa' (clob) was expected to equal: 'aa' (clob) +FAILURE + Actual (blob) cannot be compared to Expected (clob) using matcher 'equal'. + at "anonymous block", line 22 +``` - --%suite(Animals getter tests) - - --%test(get_animal - returns a dog) - procedure test_variant_1_get_animal; - --%test(get_animal - returns a dog) - procedure test_variant_2_get_animal; - --%test(get_animal - returns a dog) - procedure test_variant_3_get_animal; - --%test(get_animal - returns a dog) - procedure test_variant_4_get_animal; - --%test(get_animal - returns a dog) - procedure test_variant_5_get_animal; -end; -/ -create or replace package body test_animals_getter is - - --The below tests perform exactly the same check. - --They use different syntax to achieve the goal. - procedure test_variant_1_get_animal is - l_actual varchar2(100) := 'a dog'; - l_expected varchar2(100); - begin - --Arrange - l_actual := 'a dog'; - --Act - l_expected := get_animal(); - --Assert - ut.expect( l_actual ).to_equal( l_expected ); - end; - - procedure test_variant_2_get_animal is - l_expected varchar2(100); - begin - --Act - l_expected := get_animal(); - --Assert - ut.expect( l_expected ).to_equal( 'a dog' ); - end; - - procedure test_variant_3_get_animal is - begin - --Act / Assert - ut.expect( get_animal() ).to_equal( 'a dog' ); - end; - - procedure test_variant_4_get_animal is - begin - --Act / Assert - ut.expect( get_animal() ).to_equal( 'a dog', a_nulls_are_equal => true ); - end; - - procedure test_variant_5_get_animal is - begin - --Act / Assert - ut.expect( get_animal() ).to_( equal( 'a dog' ) ); - end; - - procedure test_variant_6_get_animal is - begin - --Act / Assert - ut.expect( get_animal() ).to_( equal( 'a dog', a_nulls_are_equal => true ) ); - end; -end; -``` - -**Comparing NULLs is by default a success!** -The `a_nulls_are_equal` parameter controls the behavior of a `null = null` comparison. -To change the behavior of `NULL = NULL` comparison pass the `a_nulls_are_equal => false` to the `equal` matcher. + +!!! note + **by default, comparing NULL to NULL gives success**
+ The `a_nulls_are_equal` parameter controls the behavior of a `null = null` comparison.
+ To change the behavior of `NULL = NULL` comparison pass the `a_nulls_are_equal => false` to the `equal` matcher. + +### contain + +This matcher supports only compound data-types comparison. It check if the actual set contains all values of expected subset. + +When comparing data using the `contain` matcher, the data-types of columns for compared compound types must be exactly the same. + +The matcher supports all advanced comparison options as `equal` like: `include` , `exclude`, `join_by` etc.. + +The matcher is successful when actual data set contains all of the values from expected results. + +The matcher will cause a test to fail if actual data set does not contain some of expected values. + +![included_set](../images/venn21.gif) + +**Example 1.** +```sql linenums="1" +declare + l_actual sys_refcursor; + l_expected sys_refcursor; +begin + --Arrange + open l_actual for select rownum as rn from dual a connect by level < 10; + open l_expected for select rownum as rn from dual a connect by level < 4 + union all select rownum as rn from dual a connect by level < 4; + + --Act + ut.expect(l_actual).to_contain(l_expected); +end; +/ +``` + +Returns following output via DBMS_OUTPUT: +``` +FAILURE + Actual: refcursor [ count = 9 ] was expected to contain: refcursor [ count = 6 ] + Diff: + Rows: [ 3 differences ] + Missing: 1 + Missing: 2 + Missing: 3 + at "anonymous block", line 11 +``` + + +When duplicate rows are present in expected data set, actual data set must also include the same amount of duplicates. + +**Example 2.** +```sql linenums="1" +declare + l_actual ut_varchar2_list; + l_expected ut_varchar2_list; +begin + l_actual := ut_varchar2_list( 1, 2, 3, 4, 5, 6, 7, 8, 1 ); + l_expected := ut_varchar2_list( 1, 2, 1, 2 ); + ut.expect( anydata.convertCollection( l_actual ) ).to_contain( anydata.convertCollection( l_expected ) ); +end; +/ +``` + +Returns following output via DBMS_OUTPUT: +``` +FAILURE + Actual: ut3.ut_varchar2_list [ count = 9 ] was expected to contain: ut3.ut_varchar2_list [ count = 4 ] + Diff: + Rows: [ 1 differences ] + Missing: 2 + at "anonymous block", line 7 +``` + +The negated version of `contain` ( `not_to_contain` ) is successful only when all values from expected set are not part of actual (they are disjoint and there is no overlap). + + +![not_overlapping_set](../images/venn22.gif) + +**Example 3.** +```sql linenums="1" +declare + l_actual ut_varchar2_list; + l_expected ut_varchar2_list; +begin + l_actual := ut_varchar2_list( 'A', 'B', 'C' ); + l_expected := ut_varchar2_list( 'A', 'B', 'E' ); + ut.expect( anydata.convertCollection( l_actual ) ).to_contain( anydata.convertCollection( l_expected ) ); + ut.expect( anydata.convertCollection( l_actual ) ).not_to_contain( anydata.convertCollection( l_expected ) ); +end; +/ +``` + +Returns following output via DBMS_OUTPUT: +``` +FAILURE + Actual: ut3.ut_varchar2_list [ count = 3 ] was expected to contain: ut3.ut_varchar2_list [ count = 3 ] + Diff: + Rows: [ 1 differences ] + Missing: E + at "anonymous block", line 7 +FAILURE + Actual: (ut3.ut_varchar2_list [ count = 3 ]) + Data-types: + VARCHAR2 + Data: + ABC + was expected not to contain:(ut3.ut_varchar2_list [ count = 3 ]) + Data-types: + VARCHAR2 + Data: + ABE + at "anonymous block", line 8 +``` + +**Example 4.** + +```sql linenums="1" +declare + l_actual ut_varchar2_list; + l_expected ut_varchar2_list; +begin + l_actual := ut_varchar2_list( 'A', 'B', 'C', 'D' ); + l_expected := ut_varchar2_list( 'A', 'B', 'D' ); + ut.expect( anydata.convertCollection( l_actual ) ).to_contain( anydata.convertCollection( l_expected ) ); + ut.expect( anydata.convertCollection( l_actual ) ).not_to_contain( anydata.convertCollection( l_expected ) ); +end; +/ +``` + +Returns following output via DBMS_OUTPUT: +``` +SUCCESS + Actual: ut3.ut_varchar2_list [ count = 4 ] was expected to contain: ut3.ut_varchar2_list [ count = 3 ] +FAILURE + Actual: (ut3.ut_varchar2_list [ count = 4 ]) + Data-types: + VARCHAR2 + Data: + ABCD + was expected not to contain:(ut3.ut_varchar2_list [ count = 3 ]) + Data-types: + VARCHAR2 + Data: + ABD + at "anonymous block", line 8 +``` + +**Example 5.** + +```sql linenums="1" +declare + l_actual ut_varchar2_list; + l_expected ut_varchar2_list; +begin + l_actual := ut_varchar2_list( 'A', 'B', 'C' ); + l_expected := ut_varchar2_list( 'D', 'E', 'F' ); + ut.expect( anydata.convertCollection( l_actual ) ).to_contain( anydata.convertCollection( l_expected ) ); + ut.expect( anydata.convertCollection( l_actual ) ).not_to_contain( anydata.convertCollection( l_expected ) ); +end; +/ +``` + +Returns following output via DBMS_OUTPUT: +``` +FAILURE + Actual: ut3.ut_varchar2_list [ count = 3 ] was expected to contain: ut3.ut_varchar2_list [ count = 3 ] + Diff: + Rows: [ 3 differences ] + Missing: D + Missing: E + Missing: F + at "anonymous block", line 7 +SUCCESS + Actual: (ut3.ut_varchar2_list [ count = 3 ]) + Data-types: + VARCHAR2 + Data: + ABC + was expected not to contain:(ut3.ut_varchar2_list [ count = 3 ]) + Data-types: + VARCHAR2 + Data: + DEF +``` + +### to_be_within of + +Determines whether expected value is within range (tolerance) from another value. + +The logical formual used for calcuating the matcher is: +``` + result := ( abs( expected - actual ) <= distance ) +``` +The actual formula used for calculation is more complex to handle different data-types of expected/actual values as well as differnet types of distance value. +The matcher will fail if the `expected` and `actual` are more than `distance` apart from each other. +The matcher will fail if the dataypes of `expected` and `actual` are not the same. + +The matcher works with data-types: `number`, `date`, `timestamp`, `timestamp with time zone`, `timestamp with local time zone` +The data-types of compared values must match exactly and if type does not match, the expectation will fail. + +| expected/actual
data-type | distance data-type | +|:------------------------------:|:----------------------:| +| number | number | +| date | interval day to second | +| date | interval year to month | +| timestamp | interval day to second | +| timestamp | interval year to month | +| timestamp with time zone | interval day to second | +| timestamp with time zone | interval year to month | +| timestamp with local time zone | interval day to second | +| timestamp with local time zone | interval year to month | + + +The distance must be expressed as a non-negative number or non-negative interval. + +>Note: +> Interval year-to-moth as a distance is giving sucess if the distance between the given dates/timestamps evaluates to value less or equal of the specified interval +> Keep in mind that a checking for distance of `interval '0-1' year to month` will actuall be successful if the distance is less than a month and 15 days. +> This is due to how oracle evaluates conversion between timestamp difference converted to `year to month interval`. +> The behavior is similar to a call to `months_between()` function with results rounded to full monts ie. round(months_between(date, date)) + +**Example 1.** +```sql linenums="1" +begin + ut.expect(3).to_be_within(1).of_(4); +end; +/ +``` + +**Example 2.** +```sql linenums="1" +begin + ut.expect(3).to_be_within(1).of_(5); +end; +/ +``` + +Returns following output via DBMS_OUTPUT: +``` +Failures: + + 1) wihtin_test + Actual: 3 (number) was expected to be within 1 of 5 (number) + at "UT3_DEVELOP.UT_BE_WITHIN.OF_", line 48 l_result.expectation.to_(l_result ); + at "UT3_DEVELOP.TEST_BETWNSTR.WIHTIN_TEST", line 5 +``` + +**Example 3.** +```sql linenums="1" +begin + ut.expect(sysdate).to_be_within(interval '1' day).of_(sysdate+2); +end; +/ +``` + +Returns following output via DBMS_OUTPUT: +``` +Failures: + + 1) wihtin_test + Actual: 2020-06-07T13:32:58 (date) was expected to be within 1 day of 2020-06-09T13:32:58 (date) + at "UT3_DEVELOP.UT_BE_WITHIN.OF_", line 55 l_result.expectation.to_(l_result ); + at "UT3_DEVELOP.TEST_BETWNSTR.WIHTIN_TEST", line 5 +``` + + +### to_be_within_pct of + +Determines whether actual value is within percentage range of expected value. +The matcher only works with `number` data-type. + +The percentage deviation (distance) must be expressed as a non-negative number. +The formula used for calcuation of expectation is: +``` + result := ( ( distance ) * expected >= abs( expected - actual ) * 100 ) +``` + +**Example 1.** +```sql linenums="1" +begin + ut.expect(9).to_be_within_pct(10).of_(10); +end; +/ +``` + +``` +SUCCESS + Actual: 9 (number) was expected to be within 10 % of 10 (number) +``` ## Comparing cursors, object types, nested tables and varrays utPLSQL is capable of comparing compound data-types including: + - ref cursors - object types - nested table/varray types ### Notes on comparison of compound data -- Compound data can contain elements of any data-type. This includes blob, clob, object type, nested table, varray or even a nested-cursor within a cursor. -- Cursors, nested table and varray types are compared as **ordered lists of elements**. If order of elements differ, expectation will fail. + +- Compound data can contain elements of any data-type. This includes blob, clob, object type, nested table, varray or even a nested-cursor within a cursor. +- Attributes in nested table and array types are compared as **ordered lists of elements**. If order of attributes in nested table and array differ, expectation will fail. +- Columns in compound data are compared as **ordered list of elements** by default. Use `unordered_columns` option when order of columns in cursor is not relevant - Comparison of compound data is data-type aware. So a column `ID NUMBER` in a cursor is not the same as `ID VARCHAR2(100)`, even if they both hold the same numeric values. - Comparison of cursor columns containing `DATE` will only compare date part **and ignore time** by default. See [Comparing cursor data containing DATE fields](#comparing-cursor-data-containing-date-fields) to check how to enable date-time comparison in cursors. +- Comparison of cursor returning `TIMESTAMP` **columns** against cursor returning `TIMESTAMP` **bind variables** requires variables to be cast to proper precision. This is an Oracle SQL - PLSQL compatibility issue and usage of CAST is the only known workaround for now. See [Comparing cursor data containing TIMESTAMP bind variables](#comparing-cursor-data-containing-timestamp-bind-variables) for examples. - To compare nested table/varray type you need to convert it to `anydata` by using `anydata.convertCollection()` - To compare object type you need to convert it to `anydata` by using `anydata.convertObject()` - It is possible to compare PL/SQL records, collections, varrays and associative arrays. To compare this types of data, use cursor comparison feature of utPLSQL and TABLE operator in SQL query - On Oracle 11g Release 2 - pipelined table functions are needed (see section [Implicit (Shadow) Types in this artcile](https://oracle-base.com/articles/misc/pipelined-table-functions)) - On Oracle 12c and above - use [TABLE function on nested tables/varrays/associative arrays of PL/SQL records](https://oracle-base.com/articles/12c/using-the-table-operator-with-locally-defined-types-in-plsql-12cr1) - +- utPLSQL is not able to distinguish between NULL and whitespace-only column/attribute value when comparing compound data. This is due to Oracle limitation on of XMLType. + See [issue #880](https://github.com/utPLSQL/utPLSQL/issues/880) for details. *Note: This behavior might be fixed in future releases, when utPLSQL is no longer depending on XMLType for compound data comparison.* utPLSQL offers advanced data-comparison options, for comparing compound data-types. The options allow you to: + - define columns/attributes to exclude from comparison - define columns/attributes to include in comparison -- and more +- and more ... For details on available options and how to use them, read the [advanced data comparison](advanced_data_comparison.md) guide. @@ -463,6 +1242,7 @@ For details on available options and how to use them, read the [advanced data co When comparing compound data, utPLSQL will determine the difference between the expected and the actual data. The diff includes: + - differences in column names, column positions and column data-type for cursor data - only data in columns/rows that differ @@ -472,9 +1252,9 @@ Consider the following expected cursor data | ID (NUMBER)| FIRST_NAME (VARCHAR2) | LAST_NAME (VARCHAR2) | SALARY (NUMBER) | |:----------:|:----------------------:|:----------------------:|:---------------:| -| 1 | JACK | SPARROW | 10000 | -| 2 | LUKE | SKYWALKER | 1000 | -| 3 | TONY | STARK | 1000000 | +| 1 | JACK | SPARROW | 10000 | +| 2 | LUKE | SKYWALKER | 1000 | +| 3 | TONY | STARK | 1000000 | And the actual cursor data: @@ -486,7 +1266,8 @@ And the actual cursor data: | M | LUKE | SKYWALKER | 1000 | 2 | -The two datasets above have the following differences: +The two data-sets above have the following differences: + - column ID is misplaced (should be first column but is last) - column SALARY has data-type VARCHAR2 but should be NUMBER - column GENDER exists in actual but not in the expected (it is an Extra column) @@ -498,83 +1279,61 @@ The two datasets above have the following differences: utPLSQL will report all of the above differences in a readable format to help you identify what is not correct in the compared dataset. Below example illustrates, how utPLSQL will report such differences. -```sql -create or replace package test_cursor_compare as - --%suite - - --%test - procedure do_test; -end; -/ - -create or replace package body test_cursor_compare as - procedure do_test is - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - open l_expected for - select 1 as ID, 'JACK' as FIRST_NAME, 'SPARROW' AS LAST_NAME, 10000 AS SALARY - from dual union all - select 2 as ID, 'LUKE' as FIRST_NAME, 'SKYWALKER' AS LAST_NAME, 1000 AS SALARY - from dual union all - select 3 as ID, 'TONY' as FIRST_NAME, 'STARK' AS LAST_NAME, 100000 AS SALARY - from dual; - open l_actual for - select 'M' AS GENDER, 'JACK' as FIRST_NAME, 'SPARROW' AS LAST_NAME, 1 as ID, '25000' AS SALARY - from dual union all - select 'M' AS GENDER, 'TONY' as FIRST_NAME, 'STARK' AS LAST_NAME, 3 as ID, '100000' AS SALARY - from dual union all - select 'F' AS GENDER, 'JESSICA' as FIRST_NAME, 'JONES' AS LAST_NAME, 4 as ID, '2345' AS SALARY - from dual union all - select 'M' AS GENDER, 'LUKE' as FIRST_NAME, 'SKYWALKER' AS LAST_NAME, 2 as ID, '1000' AS SALARY - from dual; - ut.expect(l_actual).to_equal(l_expected); - end; +```sql linenums="1" +declare + l_actual sys_refcursor; + l_expected sys_refcursor; +begin + open l_expected for + select 1 as ID, 'JACK' as FIRST_NAME, 'SPARROW' AS LAST_NAME, 10000 AS SALARY + from dual union all + select 2 as ID, 'LUKE' as FIRST_NAME, 'SKYWALKER' AS LAST_NAME, 1000 AS SALARY + from dual union all + select 3 as ID, 'TONY' as FIRST_NAME, 'STARK' AS LAST_NAME, 100000 AS SALARY + from dual; + open l_actual for + select 'M' AS GENDER, 'JACK' as FIRST_NAME, 'SPARROW' AS LAST_NAME, 1 as ID, '25000' AS SALARY + from dual union all + select 'M' AS GENDER, 'TONY' as FIRST_NAME, 'STARK' AS LAST_NAME, 3 as ID, '100000' AS SALARY + from dual union all + select 'F' AS GENDER, 'JESSICA' as FIRST_NAME, 'JONES' AS LAST_NAME, 4 as ID, '2345' AS SALARY + from dual union all + select 'M' AS GENDER, 'LUKE' as FIRST_NAME, 'SKYWALKER' AS LAST_NAME, 2 as ID, '1000' AS SALARY + from dual; + ut.expect(l_actual).to_equal(l_expected); end; / ``` -When the test package is executed using: - -```sql -set serverout on -exec ut.run('test_cursor_compare'); +Returns following output via DBMS_OUTPUT: ``` -We get the following report: -``` -test_cursor_compare - do_test [.052 sec] (FAILED - 1) - -Failures: - - 1) do_test - Actual: refcursor [ count = 4 ] was expected to equal: refcursor [ count = 3 ] - Diff: - Columns: - Column is misplaced. Expected position: 1, actual position: 4. - Column data-type is invalid. Expected: NUMBER, actual: VARCHAR2. - Column [position: 1, data-type: CHAR] is not expected in results. - Rows: [ 4 differences ] - Row No. 1 - Actual: 25000 - Row No. 1 - Expected: 10000 - Row No. 2 - Actual: TONYSTARK3100000 - Row No. 2 - Expected: 2LUKESKYWALKER1000 - Row No. 3 - Actual: JESSICAJONES42345 - Row No. 3 - Expected: 3TONYSTARK100000 - Row No. 4 - Extra: MLUKESKYWALKER21000 - at "UT3.TEST_CURSOR_COMPARE", line 22 ut.expect(l_actual).to_equal(l_expected); - - -Finished in .053553 seconds -1 tests, 1 failed, 0 errored, 0 disabled, 0 warning(s) +FAILURE + Actual: refcursor [ count = 4 ] was expected to equal: refcursor [ count = 3 ] + Diff: + Columns: + Column is misplaced. Expected position: 1, actual position: 4. + Column data-type is invalid. Expected: NUMBER, actual: VARCHAR2. + Column [position: 1, data-type: CHAR] is not expected in results. + Rows: [ 4 differences ] + Row No. 1 - Actual: 25000 + Row No. 1 - Expected: 10000 + Row No. 2 - Actual: TONYSTARK3100000 + Row No. 2 - Expected: 2LUKESKYWALKER1000 + Row No. 3 - Actual: JESSICAJONES42345 + Row No. 3 - Expected: 3TONYSTARK100000 + Row No. 4 - Extra: MLUKESKYWALKER21000 + Row No. 4 - Extra: MLUKESKYWALKER21000 + at "anonymous block", line 21 ``` utPLSQL identifies and reports on columns: + - column misplacement - column data-type mismatch - extra/missing columns When comparing rows utPLSQL: + - reports only mismatched columns when rows match - reports columns existing in both data-sets when whole row is not matching - reports whole extra (not expected) row from actual when actual has extra rows @@ -584,6 +1343,7 @@ When comparing rows utPLSQL: ### Object and nested table data-type comparison examples When comparing object type / nested table / varray, utPLSQL will check: + - if data-types match - if data in the compared elements is the same. @@ -593,42 +1353,35 @@ When diffing, utPLSQL will not check name and data-type of individual attribute Below examples demonstrate how to compare object and nested table data-types. Object type comparison. -```sql +```sql linenums="1" create type department as object(name varchar2(30)) / + create or replace function get_dept return department is begin return department('IT'); end; / -create or replace package demo_dept as - --%suite(demo) - --%test(demo of object to object comparison) - procedure test_department; -end; -/ -create or replace package body demo_dept as - procedure test_department is - v_actual department; - begin - --Act/ Assert - ut.expect( anydata.convertObject( get_dept() ) ).to_equal( anydata.convertObject( department('HR') ) ); - end; -end; -/ -begin - ut.run('demo_dept'); -end; -/ +exec ut.expect( anydata.convertObject( get_dept() ) ).to_equal( anydata.convertObject( department('HR') ) ); -drop package demo_dept; drop function get_dept; drop type department; ``` +Returns following output via DBMS_OUTPUT: +``` +FAILURE + Actual: ut3.department was expected to equal: ut3.department + Diff: + Rows: [ 1 differences ] + Row No. 1 - Actual: IT + Row No. 1 - Expected: HR + at "anonymous block", line 1 +``` + Table type comparison. -```sql +```sql linenums="1" create type department as object(name varchar2(30)) / create type departments as table of department @@ -638,169 +1391,545 @@ begin return departments( department('IT'), department('HR') ); end; / -create or replace package demo_depts as - --%suite(demo) - --%test(demo of collection comparison) - procedure test_departments; -end; -/ -create or replace package body demo_depts as - procedure test_departments is - v_expected departments; - v_actual departments; - begin - v_expected := departments(department('HR'), department('IT') ); - ut.expect( anydata.convertCollection( get_depts() ) ).to_equal( anydata.convertCollection( v_expected ) ); - end; -end; -/ +declare + v_expected departments; begin - ut.run('demo_depts'); + v_expected := departments(department('HR'), department('IT') ); + ut.expect( anydata.convertCollection( get_depts() ) ).to_equal( anydata.convertCollection( v_expected ) ); end; / -drop package demo_dept; drop type function get_depts; drop type departments; drop type department; ``` +Returns following output via DBMS_OUTPUT: +``` +FAILURE + Actual: ut3.departments [ count = 2 ] was expected to equal: ut3.departments [ count = 2 ] + Diff: + Rows: [ 2 differences ] + Row No. 1 - Actual: IT + Row No. 1 - Expected: HR + Row No. 2 - Actual: HR + Row No. 2 - Expected: IT + at "anonymous block", line 5 +``` + +Some of the possible combinations of anydata and their results: +```sql linenums="1" +clear screen +set serverout on +set feedback off + +create or replace type t_tab_varchar is table of varchar2(1) +/ +create or replace type dummy_obj as object ( + id number, + "name" varchar2(30), + "Value" varchar2(30) +) +/ +create or replace type dummy_obj_lst as table of dummy_obj +/ +create or replace type t_varray is varray(1) of number +/ + +exec ut.expect( anydata.convertObject( dummy_obj( 1, 'A', '0' ) ) ).to_equal( anydata.convertObject( dummy_obj(1, 'A', '0') ) ); +exec ut.expect( anydata.convertCollection( t_tab_varchar('A') ) ).to_equal( anydata.convertCollection( t_tab_varchar('A') ) ); +exec ut.expect( anydata.convertCollection( t_tab_varchar('A') ) ).to_equal( anydata.convertCollection( t_tab_varchar('B') ) ); +exec ut.expect( anydata.convertCollection( t_tab_varchar() ) ).to_be_null(); +exec ut.expect( anydata.convertCollection( t_tab_varchar() ) ).to_equal( anydata.convertCollection( t_tab_varchar() ) ); +exec ut.expect( anydata.convertCollection( t_tab_varchar() ) ).to_equal( anydata.convertCollection( t_tab_varchar('A') ) ); +exec ut.expect( anydata.convertCollection( t_tab_varchar() ) ).to_have_count(0); +exec ut.expect( anydata.convertCollection( t_tab_varchar() ) ).to_equal( anydata.convertCollection( t_tab_varchar() ) ); +exec ut.expect( anydata.convertCollection( t_tab_varchar() ) ).to_equal( anydata.convertCollection( t_tab_varchar('A') ) ); +exec ut.expect( anydata.convertCollection( dummy_obj_lst( dummy_obj( 1, 'A', '0' ) ) ) ).to_equal( anydata.convertCollection( dummy_obj_lst( dummy_obj( 1, 'A', '0' ) ) ) ); +exec ut.expect( anydata.convertCollection( dummy_obj_lst( dummy_obj( 1, 'A', '0' ) ) ) ).to_equal( anydata.convertCollection( dummy_obj_lst( dummy_obj( 2, 'A', '0' ) ) ) ); +exec ut.expect( anydata.convertCollection( dummy_obj_lst() ) ).to_equal( anydata.convertCollection( dummy_obj_lst( dummy_obj( 1, 'A', '0' ) ) ) ); +exec ut.expect( anydata.convertCollection( dummy_obj_lst() ) ).to_be_null(); +exec ut.expect( anydata.convertCollection( dummy_obj_lst() ) ).to_equal( anydata.convertCollection( dummy_obj_lst() ) ); +exec ut.expect( anydata.convertCollection( dummy_obj_lst() ) ).to_have_count(0); +exec ut.expect( anydata.convertCollection( dummy_obj_lst() ) ).to_equal( anydata.convertCollection( dummy_obj_lst(dummy_obj(1, 'A', '0') ) ) ); +exec ut.expect( anydata.convertCollection( dummy_obj_lst() ) ).to_equal( anydata.convertCollection( dummy_obj_lst() ) ); +exec ut.expect( anydata.convertCollection( t_varray() ) ).to_be_null(); +exec ut.expect( anydata.convertCollection( t_varray() ) ).to_equal( anydata.convertCollection( t_varray() ) ); +exec ut.expect( anydata.convertCollection( t_varray() ) ).to_equal( anydata.convertCollection( t_varray(1) ) ); +exec ut.expect( anydata.convertCollection( t_varray() ) ).to_have_count(0); +exec ut.expect( anydata.convertCollection( t_varray() ) ).to_equal( anydata.convertCollection( t_varray() ) ); +exec ut.expect( anydata.convertCollection( t_varray() ) ).to_equal( anydata.convertCollection( t_varray(1) ) ); +exec ut.expect( anydata.convertCollection( t_varray(1) ) ).to_equal( anydata.convertCollection( t_varray(1) ) ); +exec ut.expect( anydata.convertCollection( t_varray(1) ) ).to_equal( anydata.convertCollection( t_varray(2) ) ); + +drop type t_varray; +drop type dummy_obj_lst; +drop type dummy_obj; +drop type t_tab_varchar; +``` + +Returns following output via DBMS_OUTPUT: +``` +SUCCESS + Actual: ut3.dummy_obj was expected to equal: ut3.dummy_obj + +SUCCESS + Actual: ut3.t_tab_varchar [ count = 1 ] was expected to equal: ut3.t_tab_varchar [ count = 1 ] + +FAILURE + Actual: ut3.t_tab_varchar [ count = 1 ] was expected to equal: ut3.t_tab_varchar [ count = 1 ] + Diff: + Rows: [ 1 differences ] + Row No. 1 - Actual: A + Row No. 1 - Expected: B + at "anonymous block", line 1 + +FAILURE + Actual: (ut3.t_tab_varchar [ count = 0 ]) + Data-types: + VARCHAR2 + Data: + was expected to be null + at "anonymous block", line 1 + +SUCCESS + Actual: ut3.t_tab_varchar [ count = 0 ] was expected to equal: ut3.t_tab_varchar [ count = 0 ] + +FAILURE + Actual: ut3.t_tab_varchar [ count = 0 ] was expected to equal: ut3.t_tab_varchar [ count = 1 ] + Diff: + Rows: [ 1 differences ] + Row No. 1 - Missing: A + at "anonymous block", line 1 + +SUCCESS + Actual: (ut3.t_tab_varchar [ count = 0 ]) was expected to have [ count = 0 ] + +SUCCESS + Actual: ut3.t_tab_varchar [ count = 0 ] was expected to equal: ut3.t_tab_varchar [ count = 0 ] + +FAILURE + Actual: ut3.t_tab_varchar [ count = 0 ] was expected to equal: ut3.t_tab_varchar [ count = 1 ] + Diff: + Rows: [ 1 differences ] + Row No. 1 - Missing: A + at "anonymous block", line 1 + +SUCCESS + Actual: ut3.dummy_obj_lst [ count = 1 ] was expected to equal: ut3.dummy_obj_lst [ count = 1 ] + +FAILURE + Actual: ut3.dummy_obj_lst [ count = 1 ] was expected to equal: ut3.dummy_obj_lst [ count = 1 ] + Diff: + Rows: [ 1 differences ] + Row No. 1 - Actual: 1 + Row No. 1 - Expected: 2 + at "anonymous block", line 1 + +FAILURE + Actual: ut3.dummy_obj_lst [ count = 0 ] was expected to equal: ut3.dummy_obj_lst [ count = 1 ] + Diff: + Rows: [ 1 differences ] + Row No. 1 - Missing: 1A0 + at "anonymous block", line 1 + +FAILURE + Actual: (ut3.dummy_obj_lst [ count = 0 ]) + Data-types: + DUMMY_OBJ + Data: + was expected to be null + at "anonymous block", line 1 + +SUCCESS + Actual: ut3.dummy_obj_lst [ count = 0 ] was expected to equal: ut3.dummy_obj_lst [ count = 0 ] + +SUCCESS + Actual: (ut3.dummy_obj_lst [ count = 0 ]) was expected to have [ count = 0 ] + +FAILURE + Actual: ut3.dummy_obj_lst [ count = 0 ] was expected to equal: ut3.dummy_obj_lst [ count = 1 ] + Diff: + Rows: [ 1 differences ] + Row No. 1 - Missing: 1A0 + at "anonymous block", line 1 + +SUCCESS + Actual: ut3.dummy_obj_lst [ count = 0 ] was expected to equal: ut3.dummy_obj_lst [ count = 0 ] + +FAILURE + Actual: (ut3.t_varray [ count = 0 ]) + Data-types: + NUMBER + Data: + was expected to be null + at "anonymous block", line 1 + +SUCCESS + Actual: ut3.t_varray [ count = 0 ] was expected to equal: ut3.t_varray [ count = 0 ] + +FAILURE + Actual: ut3.t_varray [ count = 0 ] was expected to equal: ut3.t_varray [ count = 1 ] + Diff: + Rows: [ 1 differences ] + Row No. 1 - Missing: 1 + at "anonymous block", line 1 + +SUCCESS + Actual: (ut3.t_varray [ count = 0 ]) was expected to have [ count = 0 ] + +SUCCESS + Actual: ut3.t_varray [ count = 0 ] was expected to equal: ut3.t_varray [ count = 0 ] + +FAILURE + Actual: ut3.t_varray [ count = 0 ] was expected to equal: ut3.t_varray [ count = 1 ] + Diff: + Rows: [ 1 differences ] + Row No. 1 - Missing: 1 + at "anonymous block", line 1 + +SUCCESS + Actual: ut3.t_varray [ count = 1 ] was expected to equal: ut3.t_varray [ count = 1 ] + +FAILURE + Actual: ut3.t_varray [ count = 1 ] was expected to equal: ut3.t_varray [ count = 1 ] + Diff: + Rows: [ 1 differences ] + Row No. 1 - Actual: 1 + Row No. 1 - Expected: 2 + at "anonymous block", line 1 +``` + ### Comparing cursor data containing DATE fields -**Important note** +!!! warning "Important" -utPLSQL uses XMLType internally to represent rows of the cursor data. This is by far the most flexible method and allows comparison of cursors containing LONG, CLOB, BLOB, user defined types and even nested cursors. -Due to the way Oracle handles DATE data type when converting from cursor data to XML, utPLSQL has no control over the DATE formatting. -The NLS_DATE_FORMAT setting from the moment the cursor was opened determines the formatting of dates used for cursor data comparison. -By default, Oracle NLS_DATE_FORMAT is timeless, so data of DATE datatype, will be compared ignoring the time component. + utPLSQL uses XMLType internally to represent rows of the cursor data. This is by far the most flexible method and allows comparison of cursors containing LONG, CLOB, BLOB, user defined types and even nested cursors.
+ Due to the way Oracle handles DATE data type when converting from cursor data to XML, utPLSQL has no control over the DATE formatting.
+ The NLS_DATE_FORMAT setting from the moment the cursor was opened determines the formatting of dates used for cursor data comparison.
+ By default, Oracle NLS_DATE_FORMAT is timeless, so data of DATE datatype, will be compared ignoring the time component.
-You should use procedures `ut.set_nls`, `ut.reset_nls` around cursors that you want to compare in your tests. +You should surround cursors and expectations with procedures `ut.set_nls`, `ut.reset_nls`. This way, the DATE data in cursors will be properly formatted for comparison using date-time format. The example below makes use of `ut.set_nls`, `ut.reset_nls`, so that the date in `l_expected` and `l_actual` is compared using date-time formatting. -```sql +```sql linenums="1" +clear screen +alter session set nls_date_format='yyyy-mm-dd'; +set serverout on +set feedback off create table events ( description varchar2(4000), event_date date ) / -create or replace function get_events return sys_refcursor is - l_result sys_refcursor; +declare + c_description constant varchar2(30) := 'Test event'; + c_event_date constant date := to_date('2016-09-08 06:51:22','yyyy-mm-dd hh24:mi:ss'); + c_second constant number := 1/24/60/60; + l_actual sys_refcursor; + l_expected sys_refcursor; begin - open l_result for select description, event_date from events; - return l_result; + --Arrange + insert into events (description, event_date) values (c_description, c_event_date); + + begin + -- Change the NLS settings for date to be ISO date-time 'YYYY-MM-DD HH24:MI:SS' + ut.set_nls(); + --Act + open l_expected for select c_description as description, c_event_date + c_second as event_date from dual; + open l_actual for select description, event_date from events; + --Assert + ut.expect( l_actual ).not_to_equal( l_expected ); + -- Reset the NLS settings to their default values after cursor data was processed + ut.reset_nls(); + end; + + begin + --Act + open l_expected for select c_description as description, c_event_date + c_second as event_date from dual; + open l_actual for select description, event_date from events; + --Assert + ut.expect( l_actual ).not_to_equal( l_expected ); + end; + --Cleanup + rollback; end; / -create or replace package test_get_events is - --%suite(get_events) +drop table events; +``` - --%beforeall - procedure setup_events; - --%test(returns event within date range) - procedure get_events_for_date_range; -end; -/ +In the above example: -create or replace package body test_get_events is +- The first expectation is successful, as the `l_expected` cursor contains different date-time then the cursor returned by `get_events` function call +- The second expectation fails, as the column `event_date` will get compared as DATE without TIME (using default current session NLS date format) - gc_description constant varchar2(30) := 'Test event'; - gc_event_date constant date := to_date('2016-09-08 06:51:22','yyyy-mm-dd hh24:mi:ss'); - gc_second constant number := 1/24/60/60; - procedure setup_events is - begin - insert into events (description, event_date) values (gc_description, gc_event_date); - end; +Output via DBMS_OUTPUT from the above example: +``` +SUCCESS + Actual: (refcursor [ count = 1 ]) + Data-types: + VARCHAR2DATE + Data: + Test event2016-09-08T06:51:22 + was expected not to equal: (refcursor [ count = 1 ]) + Data-types: + VARCHAR2DATE + Data: + Test event2016-09-08T06:51:23 +FAILURE + Actual: (refcursor [ count = 1 ]) + Data-types: + VARCHAR2DATE + Data: + Test event2016-09-08 + was expected not to equal: (refcursor [ count = 1 ]) + Data-types: + VARCHAR2DATE + Data: + Test event2016-09-08 + at "anonymous block", line 28 +``` + +### Comparing cursor data containing TIMESTAMP bind variables + +To properly compare `timestamp` column data returned by cursor against bind variable data from another cursor, a conversion needs to be done. + +This applies to `timestamp`,`timestamp with timezone`, `timestamp with local timezone` data types. + +Example below illustrates usage of `cast` operator to assure appropriate precision is applied on timestamp bind-variables in cursor result-set + +```sql linenums="1" +clear screen +set serverout on +set feedback off + +create table timestamps ( + ts3 timestamp (3), + ts6 timestamp (6), + ts9 timestamp (9) +); + +declare + l_time timestamp(9); + l_expected sys_refcursor; + l_actual sys_refcursor; +begin + --Arrange + l_time := systimestamp; + + insert into timestamps (ts3, ts6, ts9) values (l_time, l_time, l_time); - procedure get_events_for_date_range is - l_actual sys_refcursor; - l_expected_bad_date sys_refcursor; begin - --Arrange - ut.set_nls(); -- Change the NLS settings for date to be ISO date-time 'YYYY-MM-DD HH24:MI:SS' - open l_expected_bad_date for select gc_description as description, gc_event_date + gc_second as event_date from dual; --Act - l_actual := get_events(); - ut.reset_nls(); -- Change the NLS settings after cursors were opened + open l_expected for + select + cast(l_time as timestamp(3)) as ts3, + cast(l_time as timestamp(6)) as ts6, + cast(l_time as timestamp(9)) as ts9 + from dual; + + open l_actual for select ts3, ts6, ts9 from timestamps; + --Assert - ut.expect( l_actual ).not_to_equal( l_expected_bad_date ); + ut.expect (l_actual).to_equal (l_expected); end; - - procedure bad_test is - l_expected_bad_date sys_refcursor; begin - --Arrange - open l_expected_bad_date for select gc_description as description, gc_event_date + gc_second as event_date from dual; - --Act / Assert - ut.expect( get_events() ).not_to_equal( l_expected_bad_date ); + open l_expected for + select l_time as ts3, l_time as ts6, l_time as ts9 from dual; + + open l_actual for select ts3, ts6, ts9 from timestamps; + + --Assert + ut.expect (l_actual).to_equal (l_expected); end; - end; / -begin - ut.run('test_get_events'); -end; -/ +drop table timestamps; +``` -drop table events; -drop function get_events; -drop package test_get_events; +Returns following output via DBMS_OUTPUT: +``` +SUCCESS + Actual: refcursor [ count = 1 ] was expected to equal: refcursor [ count = 1 ] +FAILURE + Actual: refcursor [ count = 1 ] was expected to equal: refcursor [ count = 1 ] + Diff: + Rows: [ 1 differences ] + Row No. 1 - Actual: 2019-07-08T22:08:41.8992019-07-08T22:08:41.899319 + Row No. 1 - Expected: 2019-07-08T22:08:41.8993190002019-07-08T22:08:41.899319000 + at "anonymous block", line 32 ``` -In the above example: -- The test `get_events_for_date_range` will succeed, as the `l_expected_bad_date` cursor contains different date-time then the cursor returned by `get_events` function call. -- The test `bad_test` will fail, as the column `event_date` will get compared as DATE without TIME. +## Comparing Json objects -# Negating a matcher -Expectations provide a very convenient way to perform a check on a negated matcher. +utPLSQL is capable of comparing json data-types of `json_element_t` **on Oracle 12.2 and above**, and also `json` **on Oracle 21 and above** -Syntax to check for matcher evaluating to true: -```sql -begin - ut.expect( a_actual {data-type} ).to_{matcher}; - ut.expect( a_actual {data-type} ).to_( {matcher} ); -end; -``` +!!! note + Whenever a database is upgraded to compatible version the utPLSQL needs to be reinstalled to pick up json changes. E.g. upgrade from 18c to 21c to enable `json` type compare. -Syntax to check for matcher evaluating to false: -```sql -begin - ut.expect( a_actual {data-type} ).not_to_{matcher}; - ut.expect( a_actual {data-type} ).not_to( {matcher} ); -end; -``` -If a matcher evaluated to NULL, then both `to_` and `not_to` will cause the expectation to report failure. +### Notes on comparison of json data -Example: -```sql +- Json data can contain objects, scalar or arrays. +- During comparison of json objects the order doesn't matter. +- During comparison of json arrays the index of element is taken into account +- To compare json you have to make sure its type of `json_element_t` or its subtypes +- From version 21 and above a native `json` type is supported. + + + +Compare JSON example using `json_element_t`: +```sql linenums="1" +declare + l_expected json_element_t; + l_actual json_element_t; begin - ut.expect( null ).to_( be_true() ); - ut.expect( null ).not_to( be_true() ); + l_expected := json_element_t.parse(' + { + "Actors": [ + { + "name": "Tom Cruise", + "age": 56, + "Birthdate": "July 3, 1962", + "hasChildren": true, + "children": [ + "Connor" + ] + }, + { + "name": "Robert Downey Jr.", + "age": 53, + "Birthdate": "April 4, 1965", + "hasChildren": true, + "children": [ + "Exton Elias" + ] + } + ] + }' + ); + + l_actual := json_element_t.parse(' + { + "Actors": [ + { + "name": "Tom Cruise", + "age": 56, + "Birthdate": "1962.07.03", + "hasChildren": true, + "children": [ + "Suri", + "Isabella Jane", + "Connor" + ] + }, + { + "name": "Jr., Robert Downey", + "age": 53, + "Birthdate": "April 4, 1965", + "hasChildren": true, + "children": [ + "Indio Falconer", + "Avri Roel", + "Exton Elias" + ] + } + ] + }' + ); + + ut.expect( l_actual ).to_equal( l_expected ); + end; ``` -Since NULL is neither *true* nor *false*, both expectations will report failure. -# Supported data types - -The matrix below illustrates the data types supported by different matchers. - -| Matcher |blob |boolean|clob |date |number|timestamp|timestamp
with
timezone|timestamp
with
local
timezone|varchar2|interval
year
to
month|interval
day
to
second|cursor|nested
table
/ varray|object| -|:----------------------|:---:|:-----:|:---:|:---:|:----:|:-------:|:---------------------------:|:------------------------------------:|:------:|:-----------------------------:|:-----------------------------:|:----:|:-------------------------:|:----:| -|**be_not_null** | X | X | X | X | X | X | X | X | X | X | X | X | X | X | -|**be_null** | X | X | X | X | X | X | X | X | X | X | X | X | X | X | -|**be_false** | | X | | | | | | | | | | | | | -|**be_true** | | X | | | | | | | | | | | | | -|**be_greater_than** | | | | X | X | X | X | X | | X | X | | | | -|**be_greater_or_equal**| | | | X | X | X | X | X | | X | X | | | | -|**be_less_or_equal** | | | | X | X | X | X | X | | X | X | | | | -|**be_less_than** | | | | X | X | X | X | X | | X | X | | | | -|**be_between** | | | | X | X | X | X | X | X | X | X | | | | -|**equal** | X | X | X | X | X | X | X | X | X | X | X | X | X | X | -|**match** | | | X | | | | | | X | | | | | | -|**be_like** | | | X | | | | | | X | | | | | | -|**be_empty** | X | | X | | | | | | | | | X | X | | -|**have_count** | | | | | | | | | | | | X | X | | - +Returns following output via DBMS_OUTPUT: +``` +FAILURE + Actual: json was expected to equal: json + Diff: 8 differences found + 4 unequal values, 4 missing properties + Extra property: "Avri Roel" on path: $."Actors"[1]."children"[1] + Extra property: "Isabella Jane" on path: $."Actors"[0]."children"[1] + Extra property: "Connor" on path: $."Actors"[0]."children"[2] + Extra property: "Exton Elias" on path: $."Actors"[1]."children"[2] + Actual value: "Robert Downey Jr." was expected to be: "Jr., Robert Downey" on path: $."Actors"[1]."name" + Actual value: "July 3, 1962" was expected to be: "1962.07.03" on path: $."Actors"[0]."Birthdate" + Actual value: "Connor" was expected to be: "Suri" on path: $."Actors"[0]."children"[0] + Actual value: "Exton Elias" was expected to be: "Indio Falconer" on path: $."Actors"[1]."children"[0] + at "anonymous block", line 59 +``` +Comparing parts of JSON example using `json_element_t` subtypes: +```sql linenums="1" +declare + l_actual json_object_t; + l_actual_extract json_array_t; + l_expected json_array_t; +begin + -- Arrange + l_expected := json_array_t.parse(' + [ + "Indio Falconer", + "Avri Roel", + "Exton Elias" + ]' + ); + + l_actual := json_object_t.parse(' + { + "Actors": [ + { + "name": "Tom Cruise", + "age": 56, + "Born At": "Syracuse, NY", + "Birthdate": "July 3, 1962", + "photo": "https://jsonformatter.org/img/tom-cruise.jpg", + "wife": null, + "weight": 67.5, + "hasChildren": true, + "hasGreyHair": false, + "children": [ + "Suri", + "Isabella Jane", + "Connor" + ] + }, + { + "name": "Robert Downey Jr.", + "age": 53, + "Born At": "New York City, NY", + "Birthdate": "April 4, 1965", + "photo": "https://jsonformatter.org/img/Robert-Downey-Jr.jpg", + "wife": "Susan Downey", + "weight": 77.1, + "hasChildren": true, + "hasGreyHair": false, + "children": [ + "Indio Falconer", + "Exton Elias" + ] + } + ] + }' + ); + + l_actual_extract := json_array_t(json_query(l_actual.stringify,'$.Actors[1].children')); + --Act + ut.expect(l_actual_extract).to_equal(l_expected); +end; +/ +``` +Returns following output via DBMS_OUTPUT: +``` +FAILURE + Actual: json was expected to equal: json + Diff: 2 differences found + 1 unequal values, 1 missing properties + Missing property: "Exton Elias" on path: $[2] + Actual value: "Avri Roel" was expected to be: "Exton Elias" on path: $[1] + at "anonymous block", line 55 +``` diff --git a/docs/userguide/getting-started.md b/docs/userguide/getting-started.md index c5f69ad20..1ff54a7d6 100644 --- a/docs/userguide/getting-started.md +++ b/docs/userguide/getting-started.md @@ -1,3 +1,5 @@ +![version](https://img.shields.io/badge/version-v3.1.14.4206--develop-blue.svg) + # Getting started with TDD and utPLSQL utPLSQL is designed in a way that allows you to follow @@ -5,7 +7,7 @@ utPLSQL is designed in a way that allows you to follow Below is an example of building a simple function with TDD. -# Gather requirements +## Gather requirements We have a requirement to build a function that will return a substring of a string that is passed to the function. @@ -15,14 +17,14 @@ The function should accept three parameters: - start_position - end_position -# Create a test +## Create a test We will start from the bare minimum and move step by step, executing tests every time we make minimal progress. This way, we assure we don't jump ahead too much and produce code that is untested or untestable. -## Create test package +### Create test package -```sql +```sql linenums="1" create or replace package test_betwnstr as --%suite(Between string function) @@ -41,9 +43,9 @@ Finished in .451423 seconds 0 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s) ``` -## Define specification for the test +### Define specification for the test -```sql +```sql linenums="1" create or replace package test_betwnstr as --%suite(Between string function) @@ -74,9 +76,9 @@ Finished in .509673 seconds Well our test is failing as the package specification requires a body. -## Define body of first test +### Define body of first test -```sql +```sql linenums="1" create or replace package body test_betwnstr as procedure basic_usage is @@ -108,11 +110,11 @@ Finished in .415851 seconds Our test is failing as the test suite package body is invalid. Looks like we need to define the function we want to test. -# Implement code to fulfill the requirement +## Implement code to fulfill the requirement -## Define tested function +### Define tested function -```sql +```sql linenums="1" create or replace function betwnstr( a_string varchar2, a_start_pos integer, a_end_pos integer ) return varchar2 is begin @@ -141,11 +143,11 @@ Finished in .375178 seconds So now we see that our test works but the function does not return the expected results. Let us fix this and continue from here. -## Fix the tested function +### Fix the tested function The function returned a string one character short, so we need to add 1 to the substr parameter. -```sql +```sql linenums="1" create or replace function betwnstr( a_string varchar2, a_start_pos integer, a_end_pos integer ) return varchar2 is begin @@ -167,14 +169,14 @@ Finished in .006077 seconds So our test is now passing, great! -# Refactor +## Refactor Once our tests are passing, we can safely refactor (restructure) the code as we have a safety harness in place to ensure that after the restructuring and cleanup of the code, everything is still working. One thing worth mentioning is that refactoring of tests is as important as refactoring of code. Maintainability of both is equally important. -# Further requirements +## Further requirements It seems like our work is done. We have a function that returns a substring from start position to end position. As we move through the process of adding tests, it's very important to think about edge cases. @@ -193,12 +195,12 @@ Here is a list of edge cases for our function: We should define expected behavior for each of these edge cases. Once defined we can start implementing tests for those behaviors and adjust the tested function to meet the requirements specified in the tests. -## Add test for additional requirement +### Add test for additional requirement A new requirement was added: Start position zero - should be treated as start position one -```sql +```sql linenums="1" create or replace package test_betwnstr as --%suite(Between string function) @@ -248,11 +250,11 @@ Finished in .232584 seconds Looks like our function does not work as expected for zero start position. -## Implementing the requirement +### Implementing the requirement Let's fix our function so that the new requirement is met -```sql +```sql linenums="1" create or replace function betwnstr( a_string varchar2, a_start_pos integer, a_end_pos integer ) return varchar2 is begin @@ -279,14 +281,14 @@ Finished in .012718 seconds Great! We have made some visible progress. -## Refactoring +### Refactoring When all tests are passing we can proceed with a safe cleanup of our code. The function works well, but we use the `return` twice, which is not the best coding practice. An alternative implementation could be cleaner. -```sql +```sql linenums="1" create or replace function betwnstr( a_string varchar2, a_start_pos integer, a_end_pos integer ) return varchar2 is begin @@ -306,7 +308,7 @@ Finished in .013739 seconds 2 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s) ``` -# Remaining requirements +## Remaining requirements You may continue on with the remaining edge cases from here. diff --git a/docs/userguide/install.md b/docs/userguide/install.md index ef0bef2bd..9d8167739 100644 --- a/docs/userguide/install.md +++ b/docs/userguide/install.md @@ -1,13 +1,69 @@ -# Downloading latest version of utPLSQL +![version](https://img.shields.io/badge/version-v3.1.14.4206--develop-blue.svg) -To download latest version of utPLSQL from github on both Unix/Linux as well as Windows machines use the below smippets. +## Supported database versions -## Unix/Linux +utPLSQL is continuously tested against following versions of Oracle databases + +* 11g R2 +* 12c +* 12c R2 +* 18c +* 19c + +We do our best to assure full compatibility with supported versions of Oracle databases [See](http://www.oracle.com/us/support/library/lifetime-support-technology-069183.pdf#page=6) + +## Requirements + +utPLSQL will run on any Oracle Database version 11g relase 2 or above. + +### Licensed features required + +utPLSQL doesn't require any extra licensed features of Oracle database. It can be installed on any Standard Edition Oracle Database. + +In fact, it even supports Oracle 11g XE which is a free Oracle Database version with minimal features and storage limits. + +### Storage requirements + +utPLSQL will use tablespace for the following: +- storage of annotation cache +- storage of suite cache +- storage of profiler results +- storage for staging utPLSQL reports outputs + + +utPLSQL purges the staging storage for reports while fetching reports to screen / saving reports to files. + +Suite and annotation cache storage requirements are minimal and unless you have hundreds of thousands of tests, you'll probably not even notice the space used. + +Profiler results may require regular purging to assure low space consumption. +utPLSQl does not purge profiler tables as those tables can can be shared with other tools. + + +## Downloading utPLSQL + +### Manual download + +- Go to GitHub releases page for utPLSQL [`https://github.com/utPLSQL/utPLSQL/releases`](https://github.com/utPLSQL/utPLSQL/releases) +- Choose the version to download - latest is always greatest +- Download one of files + - utPLSQL.tar.gz + - utPLSQL.zip + +The files have identical content but use different compression (tar / zip ) so choose whichever you prefer depending on your platform (Win/Mac/Unix/Linux). + + +### Scripted download of latest utPLSQL version + +The below snippets can be used to download latest version of utPLSQL from github releases. + +After downloading follow the installation instructions in next sections of this document. + +#### Unix/Linux ```bash #!/bin/bash # Get the url to latest release "zip" file -UTPLSQL_DOWNLOAD_URL=$(curl --silent https://api.github.com/repos/utPLSQL/utPLSQL/releases/latest | awk '/browser_download_url/ { print $2 }' | grep ".zip" | sed 's/"//g') +UTPLSQL_DOWNLOAD_URL=$(curl --silent https://api.github.com/repos/utPLSQL/utPLSQL/releases/latest | awk '/browser_download_url/ { print $2 }' | grep ".zip\"" | sed 's/"//g') # Download the latest release "zip" file curl -Lk "${UTPLSQL_DOWNLOAD_URL}" -o utPLSQL.zip # Extract downloaded "zip" file @@ -17,10 +73,10 @@ unzip -q utPLSQL.zip You may download with a one-liner if that is more convenient. ```bash #!/bin/bash -curl -LOk $(curl --silent https://api.github.com/repos/utPLSQL/utPLSQL/releases/latest | awk '/browser_download_url/ { print $2 }' | grep ".zip" | sed 's/"//g') +curl -LOk $(curl --silent https://api.github.com/repos/utPLSQL/utPLSQL/releases/latest | awk '/browser_download_url/ { print $2 }' | grep ".zip\"" | sed 's/"//g') ``` -## Windows +#### Windows To run the script on windows you will need [PowerShell 3.0](https://blogs.technet.microsoft.com/heyscriptingguy/2013/06/02/weekend-scripter-install-powershell-3-0-on-windows-7/) or above. You will also need .NET 4.0 Framework or above. @@ -49,22 +105,33 @@ foreach ($i in $urlList) { } ``` -# Supported database versions - -The utPLSQL may be installed on any supported version of Oracle Database [see](http://www.oracle.com/us/support/library/lifetime-support-technology-069183.pdf#page=6) -* 11g R2 -* 12c -* 12c R2 -* 18c - -# Headless installation +## Headless installation -To install the utPLSQL into a new database schema and grant it to public, execute the script `install_headless.sql` as SYSDBA. +utPLSQL can be installed with DDL trigger, to enable tracking of DDL changes to your unit test packages. +This is the recommended installation approach, when you want to compile and run unit test packages in a schema containing huge amount of database packages (for example Oracle EBS installation schema). +The reason for having DDL trigger is to enable in-time annotation parsing for utPLSQL. +Without DDL trigger, utPLSQL needs to investigate your schema objects last_ddl_timestamp each time tests are executed to check if any of DB packages were changed in given schema and if they need scanning for annotation changes. +This process can be time-consuming if DB schema is large. -The script accepts three optional parameters that define: +The headless scripts accept three optional parameters that define: - username to create as owner of utPLSQL (default `ut3`) - password for owner of utPLSQL (default `XNtxj8eEgA6X6b6f`) -- tablespace to use for storage of profiler data (default `users`) +- tablespace to use for storage of profiler and utPLSQL cache data (default `users`) + +The scripts need to be executed by `SYSDBA`, in order to grant access to `DBMS_LOCK` and `DBMS_CRYPTO` system packages. + +!!! warning "Important" + - `DBMS_LOCK` is required for session synchronization between main session and session consuming realtime reports.
+ - The user performing the installation must have the `ADMINISTER DATABASE TRIGGER` privilege. This is required for installation of trigger that is responsible for parsing annotations at at compile-time of a package.
+ - When installed with DDL trigger, utPLSQL will not be registering unit tests for any of oracle-maintained schemas.
+ - For Oracle 11g following users are excluded:
+ ANONYMOUS, APPQOSSYS, AUDSYS, DBSFWUSER, DBSNMP, DIP, GGSYS, GSMADMIN_INTERNAL, GSMCATUSER, GSMUSER, ORACLE_OCM, OUTLN, REMOTE_SCHEDULER_AGENT, SYS, SYS$UMF, SYSBACKUP, SYSDG, SYSKM, SYSRAC, SYSTEM, WMSYS, XDB, XS$NULL
+ - For Oracle 12c and above the users returned by below query are excluded by utPLSQL:
+ `select username from all_users where oracle_maintained='Y';`
+ +### Installation without DDL trigger + +To install the utPLSQL into a new database schema and grant it to public, execute the script `install_headless.sql` as SYSDBA. Example invocation of the script from command line: ```bash @@ -78,14 +145,27 @@ cd source sqlplus sys/sys_pass@db as sysdba @install_headless.sql utp3 my_verySecret_password utp3_tablespace ``` -The script needs to be executed by `SYSDBA`, in order to grant access to `DBMS_LOCK` and `DBMS_CRYPTO` system packages. +### Installation with DDL trigger + +To install the utPLSQL into a new database schema and grant it to public, execute the script `install_headless_with_trigger.sql` as SYSDBA. + +Example invocation of the script from command line: +```bash +cd source +sqlplus sys/sys_pass@db as sysdba @install_headless_with_trigger.sql +``` +Invoking script with parameters: +```bash +cd source +sqlplus sys/sys_pass@db as sysdba @install_headless_with_trigger.sql utp3 my_verySecret_password utp3_tablespace +``` -# Recommended Schema +## Recommended Schema It is highly recommended to install utPLSQL in it's own schema. You are free to choose any name for this schema. -Installing uPLSQL into shared schema is really not recommended as you loose isolation of framework. +Installing uPLSQL into a shared schema is really not recommended as you loose isolation of framework. -If the installation and utPLSQL owner user is one and the same, the user must have the following Oracle system permissions before you can proceed with the installation. +If the installing user and utPLSQL owner is one and the same, the user must have the following Oracle system permissions before you can proceed with the installation. - CREATE SESSION - CREATE PROCEDURE @@ -95,15 +175,15 @@ If the installation and utPLSQL owner user is one and the same, the user must ha - CREATE VIEW - CREATE SYNONYM - ALTER SESSION + - CREATE TRIGGER -In addition the user must be granted the execute privilege on `DBMS_LOCK` and `DBMS_CRYPTO` packages. +In addition, the user must be granted the execute privilege on `DBMS_LOCK` and `DBMS_CRYPTO` packages. utPLSQL is using [DBMS_PROFILER tables](https://docs.oracle.com/cd/E18283_01/appdev.112/e16760/d_profil.htm#i999476) for code coverage. The tables required by DBMS_PROFILER will be created in the installation schema unless they already exist. -The uninstall process will **not** drop profiler tables, as they can potentially be shared and reused for profiling PLSQL code. It is up to DBA to maintain the storage of the profiler tables. -# Manual installation procedure +## Manual installation procedure ### Creating schema for utPLSQL To create the utPLSQL schema and grant all the required privileges execute script `create_utplsql_owner.sql` from the `source` directory with parameters: @@ -119,7 +199,7 @@ sqlplus sys/sys_password@database as sysdba @create_utPLSQL_owner.sql ut3 ut3 us ``` ### Installing utPLSQL -To install the utPLSQL framework into your database run the `/source/install.sql` script and provide `schema_name` where utPLSQL is to be installed. +To install the utPLSQL framework into your database, go to `source` directory, run the `install.sql` providing the `schema_name` for utPLSQL as parameter. Schema must be created prior to calling the `install` script. You may install utPLSQL from any account that has sufficient privileges to create objects in other users schema. @@ -129,6 +209,25 @@ cd source sqlplus admin/admins_password@database @install.sql ut3 ``` +### Installing DDL trigger +To minimize startup time of utPLSQL framework (especially on a database with large schema) it is recommended to install utPLSQL DDL trigger to enable utPLSQL annotation to be updated at compile-time. + +It's recommended to install DDL trigger when connected as `SYSDBA` user. Trigger is created in utPLSQL schema. +If using the owner schema of utPLSQL to install trigger, the owner needs to have `ADMINISTER DATABASE TRIGGER` and `CREATE TRIGGER` system privileges. +If using different user to install trigger, the user needs to have `ADMINISTER DATABASE TRIGGER` and `CREATE ANY TRIGGER` system privileges. + +To install DDL trigger go to `source` directory, run the `install_ddl_trigger.sql` providing the `schema_name` for utPLSQL as parameter. + +Example invocation: +```bash +cd source +sqlplus admin/admins_password@database @install_ddl_trigger.sql ut3 +``` + +!!! note + Trigger can be installed ant any point in time after the utPLSQL installation. The framework will detect the presence of DDL trigger and act accordingly. + + ### Allowing other users to access the utPLSQL framework In order to allow other users to access utPLSQL, synonyms must be created and privileges granted. You have two options: @@ -148,7 +247,7 @@ To grant utPLSQL to an individual user, execute scripts `source/create_user_gran Example invocation: ```bash cd source -sqlplus ut3_user/ut3_password@database @create_user_grants.sql ut3 hr +sqlplus ut3_owner_schema/ut3_password@database @create_user_grants.sql ut3 hr sqlplus user/user_password@database @create_user_synonyms.sql ut3 hr ``` @@ -158,7 +257,21 @@ The following tools that support the SQL*Plus commands can be used to run the in - [SQLcl](http://www.oracle.com/technetwork/developer-tools/sqlcl/overview/index.html) - [Oracle SQL Developer](http://www.oracle.com/technetwork/developer-tools/sql-developer/overview/index.html) -# Additional requirements +## Checking environment and utPLSQL version + +To check the framework version execute the following query: +```sql linenums="1" +select substr(ut.version(),1,60) as ut_version from dual; +``` + +Additionally you may retrieve more information about your environment by executing the following query: +```sql linenums="1" +select + xmlserialize( content xmltype(ut_run_info()) as clob indent size = 2 ) + from dual; +``` + +## Additional requirements In order to use the Code Coverage functionality of utPLSQL, users executing the tests must have the CREATE privilege on the PLSQL code that the coverage is gathered on. This is a requirement of [DBMS_PROFILER package](https://docs.oracle.com/cd/E18283_01/appdev.112/e16760/d_profil.htm#i999476). @@ -166,7 +279,7 @@ This is a requirement of [DBMS_PROFILER package](https://docs.oracle.com/cd/E182 In practice, user running tests for PLSQL code that he does not own, needs to have CREATE ANY PROCEDURE/CREATE ANY TRIGGER privileges. Running code coverage on objects that the user does not own will **not produce any coverage information** without those privileges. -# Uninstalling utPLSQL +## Uninstalling utPLSQL To uninstall run `uninstall.sql` and provide `schema_name` where utPLSQL is installed. @@ -176,21 +289,23 @@ cd source sqlplus admin/admins_password@database @uninstall.sql ut3 ``` -The uninstall script will remove all the objects installed by the install script. +The uninstall script will remove all the objects installed by the installation script. Additionally, all the public and private synonyms pointing to the objects in the utPLSQL schema will be removed. If you have extended any utPLSQL types such as a custom reporter, these will need to be dropped before the uninstall, otherwise the uninstall script might fail. The uninstall script does not drop the schema. -In order for the uninstall to be successful, you need to use the uninstall script that was provided with the exact utPLSQL version installed on your database. -i.e. the uninstall script provided with version 3.0.1 will probably not work if you want to remove version 3.0.0 from your database. +**In order for the uninstall to be successful, you need to use the uninstall script that was provided with the exact utPLSQL version installed on your database.** +i.e. the uninstall script provided with version 3.1.11 will not work correctly if you want to remove version 3.0.0 from your database. + +Alternatively you can drop the user that owns utPLSQL and re-create it using headless install. -# Version upgrade +## Version upgrade Currently, the only way to upgrade version of utPLSQL v3.0.0 and above is to remove the previous version and install the new version. -# Working with utPLSQL v2 +## Working with utPLSQL v2 If you are using utPLSQL v2, you can still install utPLSQL v3. The only requirement is that utPLSQL v3 needs to be installed in a different schema than utPLSQL v2. diff --git a/docs/userguide/querying_suites.md b/docs/userguide/querying_suites.md new file mode 100644 index 000000000..24159fede --- /dev/null +++ b/docs/userguide/querying_suites.md @@ -0,0 +1,93 @@ +![version](https://img.shields.io/badge/version-v3.1.14.4206--develop-blue.svg) + +## 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 +- `tags` - tags associated with suites + +To get list of all test suites in current schema +```sql linenums="1" +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 linenums="1" +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 linenums="1" +select * from table(ut_runner.get_suites_info(USER, 'TEST_STUFF')) where item_type = 'UT_TEST'; +``` + +To get a full information about suites that have a path like `ut3:tests.test_package_*` including suite description, all contexts and tests in a suite +```sql linenums="1" +select * from table(ut_runner.get_suites_info('ut3:tests.test_package_*') where item_type = 'UT_TEST'; +``` + +To get a full information about suites that have object name like `test_package_*` including suite description, all contexts and tests in a suite +```sql linenums="1" +select * from table(ut_runner.get_suites_info('test_package_*')); +``` + +## Checking if schema contains tests + +Function `ut_runner.has_suites(a_owner)` returns boolean value indicating if given schema contains test suites. + +Example: +```sql linenums="1" +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 linenums="1" +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 linenums="1" +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/reporters.md b/docs/userguide/reporters.md index 2fddbbfd7..24d1065fe 100644 --- a/docs/userguide/reporters.md +++ b/docs/userguide/reporters.md @@ -1,6 +1,8 @@ -utPLSQL provides the following reporting formats. +![version](https://img.shields.io/badge/version-v3.1.14.4206--develop-blue.svg) -# Documentation reporter +utPLSQL provides several reporting formats. The sections below describe most of them. + +## Documentation reporter The `ut_documentation_reporter` is the default reporting format used by the framework. It provides a human readable test results. @@ -15,7 +17,8 @@ Example outputs from documentation reporter. ![doc_reporter_outputs](../images/documentation_reporter.png) -The documentation report provides the following information. +Documentation reporter provides the following information. + - Test suite name or test package name (nested with suitepath if suitepath is used) - Test description name or test procedure name - Information about test failing `(FAILED - n)` @@ -24,7 +27,7 @@ The documentation report provides the following information. - Summary with total number of tests, number of tests with status and timing for the execution -## Color output from documentation reporter +### Color output from documentation reporter When invoking tests with documentation reporter and your command line supports ANSICONSOLE (default on Unix) [available for Windows](http://adoxa.altervista.org/ansicon/), you can obtain the coloured outputs from the documentation reporter. @@ -39,10 +42,10 @@ Example outputs from documentation reporter. ![doc_reporter_outputs](../images/documentation_reporter_color.png) -# JUnit reporter +## JUnit reporter Most of continuous integration servers (like Jenkins) are capable of consuming unit test execution results in [JUnit](https://en.wikipedia.org/wiki/JUnit) format. -The `ut_junit_reporter` in earlier version referred as ut_xunit_reporter is producing outcomes as JUnit-compatible XML unit test report, that can be used by CI servers to display their custom reports and provide metrics (like tests execution trends). +The `ut_junit_reporter` in earlier version referred as `ut_xunit_reporter` is producing outcomes as JUnit-compatible XML unit test report, that can be used by CI servers to display their custom reports and provide metrics (like tests execution trends). Please note that in previous versions it was called ut_xunit_reporter and for backward compatibility that name still exists. Invocation of tests with JUnit reporter. @@ -61,9 +64,9 @@ Example of failure report details -# Teamcity reporter +## Teamcity reporter -[Teamcity](https://www.jetbrains.com/teamcity/) is a CI server by Jetbrains. It supports XUnit reporting and additionally has it's own format of reporting that allows tracking of progress of a CI step/task as it executes. +[Teamcity](https://www.jetbrains.com/teamcity/) is a CI server by Jetbrains. It supports JUnit reporting and additionally has it's own format of reporting that allows tracking of progress of a CI step/task as it executes. The TeamCity format developed by Jetbrains is supported by utPLSQL with `ut_teamcity_reporter`. Invocation of tests with Teamcity reporter. @@ -74,16 +77,19 @@ The `ut_teamcity_reporter` doesn't accept any arguments. Example of unit test report from Teamcity CI server. -![xunit_reporter_outputs](../images/teamcity_report_example.png) +![junit_reporter_outputs](../images/teamcity_report_example.png) Example of failure report details -![xunit_reporter_outputs](../images/teamcity_report_example_errors.png) +![junit_reporter_outputs_errors](../images/teamcity_report_example_errors.png) + +## Sonar test reporter -# Sonar test reporter -If you are using [SonarQube](https://about.sonarqube.com/) to do static code analysis for you PLSQL projects, your code analysis can benefit from code coverage and test results. +If you are using [SonarQube](https://www.sonarqube.org/) or [SonarCloud](https://about.sonarcloud.io/) to do static code analysis for you PLSQL projects, +your code analysis can benefit from code coverage and test results. utPLSQL provides two reporters to for SonarQube: + - `ut_sonar_test_reporter` - provides an XML output of each test executed per each project test file (package) - `ut_coverage_sonar_reporter` - provides XML output of code coverage per each project source file @@ -95,15 +101,15 @@ The paths to files can be relative to the project root directory (recommended) o Providing invalid paths or paths to non-existing files will result in failure when publishing test results/coverage results to sonar server. -For details on how to invoke reporter with paths, see the **Coverage reporters** section. +For details on how to invoke reporter with paths, see the [Code coverage](coverage.md) section. -# TFS / VSTS Reporter -If you are using [TFS](https://www.visualstudio.com/tfs/) or [VSTS](https://www.visualstudio.com/team-services/) to do static code analysis for you PLSQL projects and run builds, your code analysis can benefit from code coverage and test results. TFS reporter is designed specifically to [work with Microsoft Team Fundation Server](https://docs.microsoft.com/en-us/vsts/build-release/tasks/test/publish-test-results?view=vsts) report format which is very old version of [JUnit](https://github.com/windyroad/JUnit-Schema/blob/master/JUnit.xsd). -Main diffrence between standard JUnit is that elements cannot be nested and attribute skipped is not present. +## TFS / VSTS Reporter -utPLSQL provides test reporter to for TFS / VSTS server: -- `ut_tfs_junit_reporter` - provides an XML output of each test executed per each project test file (package) +If you are using [TFS](https://www.visualstudio.com/tfs/) or [VSTS](https://www.visualstudio.com/team-services/) to do static code analysis for you PLSQL projects and run builds, +your code analysis can benefit from code coverage and test results. TFS reporter is designed specifically to [work with Microsoft Team Fundation Server](https://docs.microsoft.com/en-us/vsts/build-release/tasks/test/publish-test-results?view=vsts) report format which is very old version of [JUnit](https://github.com/windyroad/JUnit-Schema/blob/master/JUnit.xsd). +Main difference between standard JUnit is that elements cannot be nested and attribute skipped is not present. +utPLSQL provides a dedicated `ut_tfs_junit_reporter` reporter to for TFS / VSTS servers. The reporter provides an XML output of each test executed per each project test file (package). Example of test report from TFS CI server. Summary: @@ -115,6 +121,76 @@ Details: ![tfs_junit_reporter_outputs](../images/tfs_details.png) -# Coverage reporters +## Coverage reporters + +utPLSQL comes with a set of build-in coverage reporters. +[Code coverage](coverage.md) section describes in details how to use configure and use code coverage. + +## Debug reporter + +The `ut_debug_reporter` provides a highly verbose output containing thorough details about framework and test execution. + +Use this reporter only when you need to investigate framework issues or raise a bug report to utPLSQL team. + +Usage of this reporter might have impact on performance of test-suite execution. + +Amongst others, reporter provides the following information: + +- framework version +- database version +- database OS +- database, instance and session NLS settings +- timing of each event +- time between events logged +- time from start of the run +- stack trace +- information about input parameters for the run including + - run paths + - source file mappings + - test file mappings + - coverage schemas + - coverage exclusions and inclusions + - client character set +- information about every step of the run including + - every suite and context + - every before/after procedure + - every test + - every expectation and it's result + +Some information in debug log might be redundant. + +!!! note + Some information in debug log may be sensitive. In particular:
+ - expectation results and messages (logged even for successful runs)
+ - test structure
+ - db object names
+ - etc. + +## Custom reporters + +It is possible to add your own reporters by creating an appropriate object type. +In principle, it has to be a subtype of `ut_reporter_base`. However, if the reporter is expected to produce output consumable by a client oustside of the database (e.g. the data has to be reported to the screen or to a file), then you should base it on `ut_output_reporter_base` (which is a subtype of `ut_reporter_base`). In contrast, if you would like to create a reporter that, for example, saves the data to a database table, then it should be based directly on `ut_reporter_base`. (Currently, all reporters in the utPLSQL framework are based on `ut_output_reporter_base`.) Coverage reporters are based on `ut_coverage_reporter_base` (a subtype of `ut_output_reporter_base`). + +If you need to produce a colored text output from the custom reporter, then you can build it basing on `ut_console_reporter_base` (a subtype of `ut_output_reporter_base`). In many cases it may also be more convenient to create the custom reporter type under a more specialized type, like `ut_documentation_reporter` or `ut_junit_reporter`, and override just some of the functionality. + +It is recommended to create the reporter type in the schema where utPLSQL is installed (by default it is the `UT3` schema). Note that before running the utPLSQL uninstall scripts, all custom reporters should be dropped (cf. [the installation documentation](install.md)). In particular, when upgrading to a newer version of utPLSQL, one has to drop the custom reporters and recreate them after the upgrade. + +!!! note + Please make sure that grants have been added and synonyms created for the custom reporter in order for reporter to be accessible the same way as other reporters. + Assuming that reporter with name `customer_reporter` was created in schema `UT3` +```sql + grant execute on ut3.custom_reporter to public; + create or replace public synonym custom_reporter for ut3.custom_reporter; +``` + + + +!!! note + It is possible, but cumbersome, to use another schema for storing the custom reporters. This requires to create a synonym for the base reporter type in the schema that is going to own the custom reporter, and to provide appropriate grants both to the owner of the custom reporter and to the user running the reporter. After upgrading or reinstalling utPLSQL, the extra privileges need to be recreated. This approach is not recommended. + +Assuming that the custom reporter type is created in the `UT3` schema, to run the tests using a custom reporter just call: `exec ut.run(ut3.custom_reporter_name());`, optionally providing parameter values to the `custom_reporter_name` constructor. + +One may get acquainted with the source code of the standard reporters bundled with utPLSQL (including the coverage reporters) by browsing the [`source/reporters/`](https://github.com/utPLSQL/utPLSQL/tree/develop/source/reporters) directory. The base reporter types `ut_reporter_base`, `ut_output_reporter_base` and `ut_console_reporter_base` are defined in [`source/core/types`](https://github.com/utPLSQL/utPLSQL/tree/develop/source/core/types). The base coverage reporter type `ut_coverage_reporter_base` is in [`source/core/coverage`](https://github.com/utPLSQL/utPLSQL/tree/develop/source/core/coverage). There are also two examples of custom reporters in [`examples/custom_reporters/`](https://github.com/utPLSQL/utPLSQL/tree/develop/examples/custom_reporters), both extending the functionality of `ut_documentation_reporter`: -utPLSQL comes with a set of build-in coverage reporters. Have a look into the [coverage documentation](coverage.md) to learn more about them. +* `ut_custom_reporter` accepts an integer parameter `a_tab_size`; it alters the behaviour of `ut_documentation_reporter` by changing the size of the indentation according to the parameter value (by default the indentation is increased). +* `ut_expectations_reporter` accepts a `varchar2` parameter `a_report_all_expectations`; if its value is `'Y'` (which is the default), then the reporter shows the results of all expectations that are run. This stays in contrast with `ut_documentation_reporter`, which shows the results of all tests that are run, but only of the expectations that failed (keep in mind that a single test may consist of several expectations). diff --git a/docs/userguide/running-unit-tests.md b/docs/userguide/running-unit-tests.md index 54116cf65..375a05125 100644 --- a/docs/userguide/running-unit-tests.md +++ b/docs/userguide/running-unit-tests.md @@ -1,14 +1,14 @@ -# Running tests +![version](https://img.shields.io/badge/version-v3.1.14.4206--develop-blue.svg) -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 +## Running from CI servers and command line The best way to run your tests from CI server or command line is to use the [utPLSQL-cli](https://github.com/utPLSQL/utPLSQL-cli) command line client. @@ -22,14 +22,15 @@ You may download the latest release of the command line client from [here](https ```bash #!/bin/bash # Get the url to latest release "zip" file -DOWNLOAD_URL=$(curl --silent https://api.github.com/repos/utPLSQL/utPLSQL-cli/releases/latest | awk '/zipball_url/ { print $2 }' | sed -r 's/"|,//g') +DOWNLOAD_URL=$(curl --silent https://api.github.com/repos/utPLSQL/utPLSQL-cli/releases/latest | awk '/browser_download_url/ { print $2 }' | grep ".zip\"" | sed 's/"//g') # Download the latest release "zip" file curl -Lk "${DOWNLOAD_URL}" -o utplsql-cli.zip # Extract downloaded "zip" file unzip -q utplsql-cli.zip ``` -# ut.run + +## ut.run The `ut` package contains overloaded `run` procedures and functions. The `run` API is designed to be called directly by a developer when using an IDE/SQL console to execute unit tests. @@ -39,12 +40,16 @@ A single line call is enough to execute a set of tests from one or more schemes. The **procedures** execute the specified tests and produce output to DBMS_OUTPUT using the specified reporter. The **functions** can only be used in SELECT statements. They execute the specified tests and produce outputs as a pipelined data stream to be consumed by a select statement. -## ut.run procedures +### ut.run procedures The examples below illustrate different ways and options to invoke `ut.run` procedures. +You can use a wildcard character `*` to call tests by part of their name or to call tests that are located on paths matched by part of path string. +Wildcard character can be placed anywhere on the path and can occur mutliple times. +Schema name cannot contain a wildcard character whether is in a suitepath call or call by object name. -```sql +```sql linenums="1" alter session set current_schema=hr; +set serveroutput on begin ut.run(); end; @@ -52,7 +57,8 @@ end; Executes all tests in current schema (_HR_). -```sql +```sql linenums="1" +set serveroutput on begin ut.run('HR'); end; @@ -60,7 +66,8 @@ end; Executes all tests in specified schema (_HR_). -```sql +```sql linenums="1" +set serveroutput on begin ut.run('hr:com.my_org.my_project'); end; @@ -69,8 +76,26 @@ end; Executes all tests from all packages that are on the _com.my_org.my_project_ suitepath. Check the [annotations documentation](annotations.md) to find out about suitepaths and how they can be used to organize test packages for your project. +```sql linenums="1" +set serveroutput on +begin + ut.run('hr:com*'); +end; +``` + +Executes all tests in schema `hr` from all packages that are on suitepath starting with `com`. + +```sql linenums="1" +set serveroutput on +begin + ut.run('hr:co*.my_*.my_*'); +end; +``` + +Executes all tests in schema `hr` from all packages that starting with `my_` and all tests starting with `my_*` that are on suitepath starting with `co` . -```sql +```sql linenums="1" +set serveroutput on begin ut.run('hr.test_apply_bonus'); end; @@ -78,7 +103,8 @@ end; Executes all tests from package _hr.test_apply_bonus_. -```sql +```sql linenums="1" +set serveroutput on begin ut.run('hr.test_apply_bonus.bonus_cannot_be_negative'); end; @@ -86,33 +112,53 @@ end; Executes single test procedure _hr.test_apply_bonus.bonus_cannot_be_negative_. -```sql +```sql linenums="1" +set serveroutput on begin ut.run(ut_varchar2_list('hr.test_apply_bonus','cust')); end; ``` -Executes all tests from package _hr.test_apply_bonus_ and all tests from schema _cust_. +Executes all tests from package _hr.test_apply_bonus_ and all tests from schema _cust_ (passing individual items to be executed as elements of the ut_varchar2_list table type). + -```sql +```sql linenums="1" +set serveroutput on begin - ut.run(ut_varchar2_list('hr.test_apply_bonus,cust)'); + ut.run(ut_varchar2_list('hr.test_apply_bonus,cust')); end; ``` +Executes all tests from package _hr.test_apply_bonus_ and all tests from schema _cust_ (passing all items as a comma-separated-list of values into a single element of the ut_varchar2_list table type). -Executes all tests from package _hr.test_apply_bonus_ and all tests from schema _cust_. -```sql +```sql linenums="1" +set serveroutput on begin ut.run('hr.test_apply_bonus,cust'); end; ``` -Executes all tests from package _hr.test_apply_bonus_ and all tests from schema _cust_. +Executes all tests from package _hr.test_apply_bonus_ and all tests from schema _cust_ (no explicit ut_varchar2_list table type). Using a list of items to execute allows you to execute a fine-grained set of tests. List can be passed as a comma separated list or a list of *ut_varchar2_list objects* or as a list within ut_varchar2_list. +```sql linenums="1" +set serveroutput on +begin + ut.run('hr.test*'); +end; +``` +Executes all tests in schema `hr` located in packages starting with name `test`. + +```sql linenums="1" +set serveroutput on +begin + ut.run('hr.test_apply_bonus.bonus_*'); +end; +``` +Executes test procedures with names starting with `bonus` in package `hr.test_apply_bonus` . + **Note:** @@ -121,29 +167,34 @@ List can be passed as a comma separated list or a list of *ut_varchar2_list obje The `ut.run` procedures and functions accept `a_reporter` attribute that defines the reporter to be used in the run. You can execute any set of tests with any of the predefined reporters. -```sql +```sql linenums="1" +set serveroutput on begin - ut.run('hr.test_apply_bonus', ut_xunit_reporter()); + ut.run('hr.test_apply_bonus', ut_junit_reporter()); end; ``` -Executes all tests from package _HR.TEST_APPLY_BONUS_ and provide outputs to DBMS_OUTPUT using the XUnit reporter. +Executes all tests from package _HR.TEST_APPLY_BONUS_ and provide outputs to DBMS_OUTPUT using the JUnit reporter. For details on build-in reporters look at [reporters documentation](reporters.md). -## ut.run functions +### ut.run functions The `ut.run` functions provide exactly the same functionality as the `ut.run` procedures. You may use the same sets of parameters with both functions and procedures. The only difference is the output of the results. Functions provide output as a pipelined stream and therefore need to be executed as select statements. +**Note:** +>When running tests with `ut.run` functions, whole test run is executed as autonomous transaction. +At the end of the run, the transaction is automatically rolled-back and all uncommitted changes are reverted. + Example. -```sql -select * from table(ut.run('hr.test_apply_bonus', ut_xunit_reporter())); +```sql linenums="1" +select * from table(ut.run('hr.test_apply_bonus', ut_junit_reporter())); ``` -# ut_runner.run procedures +## ut_runner.run procedures The `ut_runner` package provides an API for integrating utPLSQL with other products. Maven, Jenkins, SQL Develper, PL/SQL Developer, TOAD and others can leverage this API to call utPLSQL. @@ -152,9 +203,368 @@ The main difference compared to the `ut.run` API is that `ut_runner.run` does no `ut_runner.run` accepts multiple reporters. Each reporter pipes to a separate output (uniquely identified by output_id). Outputs of multiple reporters can be consumed in parallel. This allows for live reporting of test execution progress with threads and several database sessions. -The concept is pretty simple. +`ut_runner.run` API is used by utPLSQL-cli, utPLSQL-SQLDeveloper extension and utPLSQL-maven-plugin and allows for: +- deciding on the scope of test run (by schema names, object names, suite paths or tags ) +- running tests with several concurrent reporters +- real-time reporting of test execution progress +- controlling colored text output to the screen +- controlling scope of code coverage reports +- mapping of database source code to project files +- controlling behavior on test-failures +- controlling client character set for HTML and XML reports +- controlling rollback behavior of test-run +- controlling random order of test execution + +Running with multiple reporters. - in the main thread (session), define the reporters to be used. Each reporter has it's output_id and so you need to extract and store those output_ids. - as a separate thread, start `ut_runner.run` and pass reporters with previously defined output_ids. -- for each reporter start a separate thread and read outputs from the `ut_output_buffer.get_lines` table function by providing the output_id defined in the main thread. +- for each reporter start a separate thread and read outputs from the `reporter.get_lines` table function or from `reporter.get_lines_cursor()` by providing the `reporter_id` defined in the main thread. +- each reporter for each test-run must have a unique `reporter_id`. The `reporter_id` is used between two sessions to identify the data stream + +Example: +```sql linenums="1" +--main test run ( session 1 ) +declare + l_reporter ut_realtime_reporter := ut_realtime_reporter(); +begin + l_reporter.set_reporter_id( 'd8a79e85915640a6a4e1698fdf90ba74' ); + l_reporter.output_buffer.init(); + ut_runner.run (ut_varchar2_list ('ut3_tester','ut3_user'), ut_reporters( l_reporter ) ); +end; +/ +``` + +```sql linenums="1" +--report consumer ( session 2 ) +set arraysize 1 +set pagesize 0 + +select * + from table( + ut_realtime_reporter() + .set_reporter_id('d8a79e85915640a6a4e1698fdf90ba74') + .get_lines() + ); +``` + +```sql linenums="1" +--alternative version of report consumer ( session 2 ) +set arraysize 1 +set pagesize 0 + +select + ut_realtime_reporter() + .set_reporter_id('d8a79e85915640a6a4e1698fdf90ba74') + .get_lines_cursor() + from dual; +``` + +## Order of test execution + +### Default order + +When unit tests are executed without random order, they are ordered by: +- schema name +- suite path or test package name if `--%suitepath` was not specified for that package +- `--%test` line number in package + +### Random order + +You can force a test run to execute tests in random order by providing one of options to `ut.run`: +- `a_random_test_order` - true/false for procedures and 1/0 for functions +- `a_random_test_order_seed` - positive number in range of 1 .. 1 000 000 000 + +When tests are executed with random order, randomization is applied to single level of suitepath hierarchy tree. +This is needed to maintain visibility and accessibility of common setup/cleanup `beforeall`/`afterall` in tests. + +Example: +```sql linenums="1" +set serveroutput on +begin + ut.run('hr.test_apply_bonus', a_random_test_order => true); +end; +``` + +```sql linenums="1" +select * from table(ut.run('hr.test_apply_bonus', a_random_test_order => 1)); +``` + +When running with random order, the default report (`ut_documentation_reporter`) will include information about the random test run seed. +Example output: +``` +... +Finished in .12982 seconds +35 tests, 0 failed, 0 errored, 1 disabled, 0 warning(s) +Tests were executed with random order seed '302980531'. +``` + +If you want to re-run tests using previously generated seed, you may do so by running them with parameter `a_random_test_order_seed` +Example: +```sql linenums="1" +set serveroutput on +begin + ut.run('hr.test_apply_bonus', a_random_test_order_seed => 302980531); +end; +``` + +```sql linenums="1" +select * from table(ut.run('hr.test_apply_bonus', a_random_test_order_seed => 302980531)); +``` + +**Note** +>Random order seed must be a positive number within range of 1 .. 1 000 000 000. + +## Run by Tags + +In addition to the path, you can filter the tests to be run by specifying tags. Tags are defined in the test / context / suite with the `--%tags`-annotation ([Read more](annotations.md#tags)). +Multiple tags are separated by comma. + + +### Tag Expressions + +Tag expressions are boolean expressions created by combining tags with the `!`, `&`, `|` operators. Tag expressions can be grouped using `(` and `)` braces. Grouping tag expressions affects operator precedence. + +Two reserved keywords, `any` and `none`, can be used when creating a tag expression to run tests. +- `any` keyword represents tests and suites with any tags +- `none` keyword represents tests and suites without tags + +These keywords may be combined with other expressions just like normal tags. + +!!! note + When specifying `none`, be aware that it will exclude any tests/suites/contexts contained within a tagged suite. + +| Operator | Meaning | +| -------- | --------| +| ! | not | +| & | and | +| \| | or | + +If you are tagging your tests across multiple dimensions, tag expressions help you to select which tests to execute. When tagging by test type (e.g., micro, integration, end-to-end) and feature (e.g., product, catalog, shipping), the following tag expressions can be useful. + + +| Tag Expression | Selection | +| -------- | --------| +| product | all tests for product | +| catalog \| shipping | all tests for catalog plus all tests for shipping | +| catalog & shipping | all tests that are tagged with both `catalog` and `shipping` tags | +| product & !end-to-end | all tests tagged `product`, except the tests tagged `end-to-end` | +| (micro \| integration) & (product \| shipping) | all micro or integration tests for product or shipping | + + +Taking the last expression above `(micro | integration) & (product | shipping)` + +| --%tags |included in run | +| -------- | --------| +| micro | no | +| integration | no | +| micro | no | +| product | no | +| shipping | no | +| micro | no | +| micro, integration | no | +| product, shipping | no | +| micro, product | yes | +| micro, shipping | yes | +| integration, product | yes | +| integration, shipping | yes | +| integration, micro, shipping | yes | +| integration, micro, product | yes | +| integration, shipping ,product | yes | +| micro, shipping ,product | yes | +| integration, micro, shipping ,product | yes | + + +### Sample execution of test with tags. + +Execution of the test with tag expressions is done using the parameter `a_tags`. +Given a test package `ut_sample_test` defined below + +```sql linenums="1" +create or replace package ut_sample_test is + + --%suite(Sample Test Suite) + --%tags(api) + + --%test(Compare Ref Cursors) + --%tags(complex,fast) + procedure ut_refcursors1; + + --%test(Run equality test) + --%tags(simple,fast) + procedure ut_test; + +end ut_sample_test; +/ + +create or replace package body ut_sample_test is + + procedure ut_refcursors1 is + v_actual sys_refcursor; + v_expected sys_refcursor; + begin + open v_expected for select 1 as test from dual; + open v_actual for select 2 as test from dual; + + ut.expect(v_actual).to_equal(v_expected); + end; + + procedure ut_test is + begin + ut.expect(1).to_equal(0); + end; + +end ut_sample_test; +/ +``` + +```sql linenums="1" +select * from table(ut.run(a_path => 'ut_sample_test',a_tags => 'api')); +``` +The above call will execute all tests from `ut_sample_test` package as the whole suite is tagged with `api` + +```sql linenums="1" +select * from table(ut.run(a_tags => 'fast&complex')); +``` +The above call will execute only the `ut_sample_test.ut_refcursors1` test, as only the test `ut_refcursors1` is tagged with `complex` and `fast` + +```sql linenums="1" +select * from table(ut.run(a_tags => 'fast')); +``` +The above call will execute both `ut_sample_test.ut_refcursors1` and `ut_sample_test.ut_test` tests, as both tests are tagged with `fast` + +### Excluding tests/suites by tags + +It is possible to exclude parts of test suites with tags. +In order to do so, prefix the tag name to exclude with a `!` (exclamation) sign when invoking the test run which is equivalent of `-` (dash) in legacy notation. +Examples (based on above sample test suite) + +```sql linenums="1" +select * from table(ut.run(a_tags => '(api|fast)&!complex')); +``` + +or + +```sql linenums="1" +select * from table(ut.run(a_tags => '(api|fast)&!complex&!test1')); +``` + +which is equivalent of exclusion on whole expression + +```sql linenums="1" +select * from table(ut.run(a_tags => '(api|fast)&!(complex|test1)')); +``` + +The above calls will execute all suites/contexts/tests that are marked with any of tags `api` or `fast` except those suites/contexts/tests that are marked as `complex` and except those suites/contexts/tests that are marked as `test1`. +Given the above example package `ut_sample_test`, only `ut_sample_test.ut_test` will be executed. + + +### Sample execution with `any` and `none` + +Given a sample test package: + +```sql linenums="1" +create or replace package ut_sample_test is + + --%suite(Sample Test Suite) + + --%test(Compare Ref Cursors) + --%tags(complex,fast) + procedure ut_refcursors1; + + --%test(Run equality test) + --%tags(simple,fast) + procedure ut_test; + + --%test(Run equality test no tag) + procedure ut_test_no_tag; + +end ut_sample_test; +/ + +create or replace package body ut_sample_test is + + procedure ut_refcursors1 is + v_actual sys_refcursor; + v_expected sys_refcursor; + begin + open v_expected for select 1 as test from dual; + open v_actual for select 2 as test from dual; + + ut.expect(v_actual).to_equal(v_expected); + end; + + procedure ut_test is + begin + ut.expect(1).to_equal(0); + end; + + procedure ut_test_no_tag is + begin + ut.expect(1).to_equal(0); + end; + +end ut_sample_test; +/ +``` + +```sql linenums="1" +select * from table(ut.run(a_path => 'ut_sample_test',a_tags => 'none')); +``` + +The above call will execute tests `ut_test_no_tag` + +```sql linenums="1" +select * from table(ut.run(a_path => 'ut_sample_test',a_tags => 'any')); +``` + +The above call will execute tests `ut_test` and `ut_refcursors1` + +```sql linenums="1" +select * from table(ut.run(a_path => 'ut_sample_test',a_tags => 'none|simple')); +``` + +The above call will execute tests `ut_test_no_tag` and `ut_test` + +```sql linenums="1" +select * from table(ut.run(a_tags => 'none|!simple')); +``` + +The above call will execute tests `ut_test_no_tag` and `ut_refcursors1` + +## Keeping uncommitted data after test-run + +utPLSQL by default runs tests in autonomous transaction and performs automatic rollback to assure that tests do not impact one-another and do not have impact on the current session in your IDE. + +If you would like to keep your uncommitted data persisted after running tests, you can do so by using `a_force_manual_rollback` flag. +Setting this flag to true has following side-effects: + +- test execution is done in current transaction - if while running tests commit or rollback is issued your current session data will get commited too. +- automatic rollback is forced to be disabled in test-run even if it was explicitly enabled by using annotation `--%rollback(manual) + +Example invocation: +```sql linenums="1" +set serveroutput on +begin + ut.run('hr.test_apply_bonus', a_force_manual_rollback => true); +end; +``` + +**Note:** +>This option is not available when running tests using `ut.run` as a table function. + +## Reports character-set encoding + +To get properly encoded reports, when running utPLSQL with HTML/XML reports on data containing national characters you need to provide your client character set when calling `ut.run` functions and procedures. + +If you run your tests using `utPLSQL-cli`, this is done automatically and no action needs to be taken. + +To make sure that the reports will display your national characters properly when running from IDE like SQLDeveloper/TOAD/SQLPlus or sqlcl you need to provide the charaterset manualy to `ut.run`. + +Example call with characterset provided: +```sql linenums="1" +begin + ut.run('hr.test_apply_bonus', ut_junit_reporter(), a_client_character_set => 'Windows-1251'); +end; +``` diff --git a/docs/userguide/upgrade.md b/docs/userguide/upgrade.md index 3da76e1f8..6fdaa6a48 100644 --- a/docs/userguide/upgrade.md +++ b/docs/userguide/upgrade.md @@ -1,3 +1,5 @@ +![version](https://img.shields.io/badge/version-v3.1.14.4206--develop-blue.svg) + # Upgrading from version 2 utPLSQL v3 is a total rewrite of the framework. diff --git a/examples/RunAllExamples.sql b/examples/RunAllExamples.sql index 75ac59a9d..faa3388cf 100644 --- a/examples/RunAllExamples.sql +++ b/examples/RunAllExamples.sql @@ -1,6 +1,6 @@ PROMPT Run all examples -set echo off -set feedback off +set echo on +set feedback on set linesize 1000 declare diff --git a/examples/RunAllExamplesAsTests.sql b/examples/RunAllExamplesAsTests.sql index 458f11091..d089ba447 100644 --- a/examples/RunAllExamplesAsTests.sql +++ b/examples/RunAllExamplesAsTests.sql @@ -3,3 +3,7 @@ whenever oserror exit failure rollback @@RunAllExamples.sql +prompt ******************************************************************************* +prompt All examples completed successfully +prompt ******************************************************************************* +prompt diff --git a/examples/RunCustomReportersExamples.sql b/examples/RunCustomReportersExamples.sql new file mode 100644 index 000000000..730946662 --- /dev/null +++ b/examples/RunCustomReportersExamples.sql @@ -0,0 +1,10 @@ +prompt ******************************************************************************* +prompt Running custom reporters examples +prompt ******************************************************************************* +Clear Screen +set echo off +set feedback on +set linesize 1000 + +@@custom_reporters/run_ut_custom_reporter.sql +@@custom_reporters/run_ut_expectations_reporter.sql diff --git a/examples/RunDeveloperExamples.sql b/examples/RunDeveloperExamples.sql index ec4301e88..2f4ca13e3 100644 --- a/examples/RunDeveloperExamples.sql +++ b/examples/RunDeveloperExamples.sql @@ -1,15 +1,11 @@ PROMPT Run developer examples Clear Screen -set echo off -set feedback off +set echo on +set feedback on 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 @@developer_examples/RunExampleTestAnnotationsParsingTimeHugePackage.sql prompt RunExampleTestSuite diff --git a/examples/RunExpectations.sql b/examples/RunExpectations.sql index aeb5c40bc..eed123e72 100644 --- a/examples/RunExpectations.sql +++ b/examples/RunExpectations.sql @@ -11,7 +11,7 @@ set echo off @@demo_expectations.pck begin - ut_coverage.coverage_start(); + ut_coverage.coverage_start(sys_guid()); ut_coverage.set_develop_mode(true); ut.run(); ut_coverage.set_develop_mode(false); diff --git a/examples/RunUserExamples.sql b/examples/RunUserExamples.sql index 5323a07aa..702ccbce8 100644 --- a/examples/RunUserExamples.sql +++ b/examples/RunUserExamples.sql @@ -1,6 +1,6 @@ PROMPT Run user examples -set echo off -set feedback off +set echo on +set feedback on set linesize 1000 prompt Common examples from web diff --git a/examples/between_string/run_betwnstr_test.sql b/examples/between_string/run_betwnstr_test.sql index 120645410..31edc52cf 100644 --- a/examples/between_string/run_betwnstr_test.sql +++ b/examples/between_string/run_betwnstr_test.sql @@ -1,5 +1,6 @@ @@betwnstr.sql -@@test_betwnstr.pkg +@@test_betwnstr.pks +@@test_betwnstr.pkb set serveroutput on size unlimited format truncated diff --git a/examples/between_string/run_betwnstr_test_coverage.sql b/examples/between_string/run_betwnstr_test_coverage.sql index efbbb20fe..098445cae 100644 --- a/examples/between_string/run_betwnstr_test_coverage.sql +++ b/examples/between_string/run_betwnstr_test_coverage.sql @@ -4,14 +4,15 @@ set pagesize 0 set long 200000000 set longchunksize 1000000 @@betwnstr.sql -@@test_betwnstr.pkg +@@test_betwnstr.pks +@@test_betwnstr.pkb set serveroutput on size unlimited format truncated set feedback off set termout off spool coverage.html -exec ut.run(user, ut_coverage_html_reporter(a_project_name=>'Demo of between string function tests', a_include_object_list=>ut_varchar2_list('ut3.betwnstr'))); +exec ut.run(user, ut_coverage_html_reporter(a_project_name=>'Demo of between string function tests', a_include_object_list=>ut_varchar2_list('betwnstr'))); spool off diff --git a/examples/between_string/test_betwnstr.pkg b/examples/between_string/test_betwnstr.pkb similarity index 52% rename from examples/between_string/test_betwnstr.pkg rename to examples/between_string/test_betwnstr.pkb index 84f153ecc..f872f6447 100644 --- a/examples/between_string/test_betwnstr.pkg +++ b/examples/between_string/test_betwnstr.pkb @@ -1,25 +1,3 @@ -create or replace package test_betwnstr as - - -- %suite(Between string function) - - -- %test(Returns substring from start position to end position) - procedure normal_case; - - -- %test(Returns substring when start position is zero) - procedure zero_start_position; - - -- %test(Returns string until end if end position is greater than string length) - procedure big_end_position; - - -- %test(Returns null for null input string value) - procedure null_string; - - -- %test(Demo of a disabled test) - -- %disabled - procedure disabled_test; - -end; -/ create or replace package body test_betwnstr as procedure normal_case is diff --git a/examples/between_string/test_betwnstr.pks b/examples/between_string/test_betwnstr.pks new file mode 100644 index 000000000..7b98d0005 --- /dev/null +++ b/examples/between_string/test_betwnstr.pks @@ -0,0 +1,22 @@ +create or replace package test_betwnstr as + + -- %suite(Between string function) + + -- %test(Returns substring from start position to end position) + procedure normal_case; + + -- %test(Returns substring when start position is zero) + procedure zero_start_position; + + -- %test(Returns string until end if end position is greater than string length) + procedure big_end_position; + + -- %test(Returns null for null input string value) + procedure null_string; + + -- %test(Demo of a disabled test) + -- %disabled + procedure disabled_test; + +end; +/ diff --git a/examples/custom_reporters/run_ut_custom_reporter.sql b/examples/custom_reporters/run_ut_custom_reporter.sql new file mode 100644 index 000000000..dbb142ce1 --- /dev/null +++ b/examples/custom_reporters/run_ut_custom_reporter.sql @@ -0,0 +1,16 @@ +prompt ******************************************************************************* +prompt Runnign tests with UT_CUSTOM_REPORTER on top of UT_DOCUMENTATION_REPROTER +prompt ******************************************************************************* + +set echo off +--install the example unit test packages +@demo_of_expectations/demo_equal_matcher.sql +@@ut_custom_reporter.tps +@@ut_custom_reporter.tpb + +set serveroutput on size unlimited format truncated + +exec ut.run('demo_equal_matcher', ut_custom_reporter()); + +@demo_of_expectations/drop_demo_equal_matcher.sql +drop type ut_custom_reporter; diff --git a/examples/custom_reporters/run_ut_expectations_reporter.sql b/examples/custom_reporters/run_ut_expectations_reporter.sql new file mode 100644 index 000000000..90b1ff9ff --- /dev/null +++ b/examples/custom_reporters/run_ut_expectations_reporter.sql @@ -0,0 +1,16 @@ +prompt ******************************************************************************* +prompt Runnign tests with UT_CUSTOM_REPORTER on top of UT_DOCUMENTATION_REPROTER +prompt ******************************************************************************* + +set echo off +--install the example unit test packages +@demo_of_expectations/demo_equal_matcher.sql +@@ut_expectations_reporter.tps +@@ut_expectations_reporter.tpb + +set serveroutput on size unlimited format truncated + +exec ut.run('demo_equal_matcher', ut_expectations_reporter()); + +@demo_of_expectations/drop_demo_equal_matcher.sql +drop type ut_expectations_reporter; diff --git a/examples/developer_examples/ut_custom_reporter.tpb b/examples/custom_reporters/ut_custom_reporter.tpb similarity index 93% rename from examples/developer_examples/ut_custom_reporter.tpb rename to examples/custom_reporters/ut_custom_reporter.tpb index 09991107c..48e8f4a96 100644 --- a/examples/developer_examples/ut_custom_reporter.tpb +++ b/examples/custom_reporters/ut_custom_reporter.tpb @@ -16,9 +16,9 @@ create or replace type body ut_custom_reporter is return tab_str; end tab; - overriding member procedure print_text(a_text varchar2) is + overriding member procedure print_text(a_text varchar2, a_item_type varchar2 := null) is begin - (self as ut_documentation_reporter).print_text(tab || a_text); + (self as ut_documentation_reporter).print_text(tab || a_text, a_item_type); end; overriding member procedure before_calling_suite(self in out nocopy ut_custom_reporter, a_suite ut_logical_suite) as diff --git a/examples/developer_examples/ut_custom_reporter.tps b/examples/custom_reporters/ut_custom_reporter.tps similarity index 62% rename from examples/developer_examples/ut_custom_reporter.tps rename to examples/custom_reporters/ut_custom_reporter.tps index aa68c03ad..0cc3d67ed 100644 --- a/examples/developer_examples/ut_custom_reporter.tps +++ b/examples/custom_reporters/ut_custom_reporter.tps @@ -4,8 +4,14 @@ create or replace type ut_custom_reporter under ut_documentation_reporter -- Member functions and procedures constructor function ut_custom_reporter(a_tab_size integer default 4) return self as result, + + /* The reporter is using base functions of parent type ( UT_DOCUMENTATION_REPORTER ) + It is altering the behavior of the base functions by change of the indentation. + So the custom reporter is same as documentation reporter except that the tab size is bigger. + Additionally, the reporter constructor accepts parameter to indicate the indentation size + */ overriding member function tab(self in ut_custom_reporter) return varchar2, - overriding member procedure print_text(a_text varchar2), + overriding member procedure print_text(a_text varchar2, a_item_type varchar2 := null), overriding member procedure before_calling_suite(self in out nocopy ut_custom_reporter, a_suite ut_logical_suite), overriding member procedure before_calling_test(self in out nocopy ut_custom_reporter, a_test ut_test), overriding member procedure after_calling_test(self in out nocopy ut_custom_reporter, a_test ut_test), diff --git a/examples/custom_reporters/ut_expectations_reporter.tpb b/examples/custom_reporters/ut_expectations_reporter.tpb new file mode 100644 index 000000000..af9cceb28 --- /dev/null +++ b/examples/custom_reporters/ut_expectations_reporter.tpb @@ -0,0 +1,149 @@ +create or replace type body ut_expectations_reporter is + /* + utPLSQL - Version 3 + Copyright 2016 - 2020 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + constructor function ut_expectations_reporter(a_report_all_expectations varchar2 := 'Y')return self as result is + begin + self.init($$plsql_unit); + self.lvl := 0; + self.report_all_expectations := substr(a_report_all_expectations,1,1); + self.failed_test_running_count := 0; + return; + end; + + /* The reporter procedure after_calling_test from ut_documentation_reporter is overriden here so that: + - the test name is printed + - the test staus is printed + - test duration is printed + - all expectation results from the test are printed (default) or only the failing ones + - error stack trace is printed + - dbms_output from test run is always printed + */ + overriding member procedure after_calling_test(a_test ut_test) as + l_message varchar2(4000); + + procedure print_expectation(a_expectation ut_expectation_result) is + l_lines ut_varchar2_list; + l_failed boolean := a_expectation.status > ut_utils.gc_success; + begin + if l_failed or self.report_all_expectations = 'Y' then + l_lines := a_expectation.get_result_lines(); + for i in 1 .. l_lines.count loop + if l_failed then + self.print_red_text(l_lines(i)); + else + self.print_green_text(l_lines(i)); + end if; + end loop; + self.print_cyan_text(a_expectation.caller_info); + self.print_text(' '); + end if; + end; + + procedure print_results_for_test(a_test ut_test) is + begin + self.lvl := self.lvl + 3; + self.print_red_text(ut_utils.table_to_clob( a_test.get_error_stack_traces() )); + for j in 1 .. a_test.all_expectations.count loop + print_expectation(a_test.all_expectations(j)); + end loop; + self.lvl := self.lvl - 3; + end; + begin + l_message := coalesce(a_test.description, a_test.name)||' ['||round(a_test.execution_time,3)||' sec]'; + --if test failed, then add it to the failures list, print failure with number + if a_test.result = ut_utils.gc_disabled then + self.print_yellow_text(l_message || ' (DISABLED)'); + elsif a_test.result = ut_utils.gc_success then + self.print_green_text(l_message); + elsif a_test.result > ut_utils.gc_success then + self.failed_test_running_count := self.failed_test_running_count + 1; + self.print_red_text(l_message || ' (FAILED - ' || failed_test_running_count || ')'); + end if; + + print_results_for_test(a_test); + -- reproduce the output from before/after procedures and the test + self.print_clob(a_test.get_serveroutputs); + end; + + overriding member procedure after_calling_run(a_run in ut_run) as + l_summary_text varchar2(4000); + l_warning_index pls_integer := 0; + -- make all warning indexes uniformly indented + c_warnings_lpad constant integer := length(to_char(a_run.results_count.warnings_count)); + + procedure print_item_warnings(a_item in ut_suite_item) is + l_items ut_suite_items; + begin + if a_item is of (ut_logical_suite) then + l_items := treat(a_item as ut_logical_suite).items; + for i in 1 .. l_items.count loop + print_item_warnings(l_items(i)); + end loop; + end if; + + if a_item.warnings is not null and a_item.warnings.count > 0 then + for i in 1 .. a_item.warnings.count loop + l_warning_index := l_warning_index + 1; + self.print_text(' ' || lpad(l_warning_index, c_warnings_lpad) || ') ' || a_item.path); + self.lvl := self.lvl + 3; + self.print_red_text(a_item.warnings(i)); + self.lvl := self.lvl - 3; + end loop; + self.print_text(' '); + end if; + end; + + procedure print_warnings(a_run in ut_run) is + begin + if a_run.results_count.warnings_count > 0 then + self.print_text(' '); + self.print_text('Warnings:'); + self.print_text(' '); + for i in 1 .. a_run.items.count loop + print_item_warnings(treat(a_run.items(i) as ut_suite_item)); + end loop; + end if; + end; + + begin + print_warnings(a_run); + self.print_text('Finished in ' || a_run.execution_time || ' seconds'); + + l_summary_text := + a_run.results_count.total_count || ' tests, ' + || a_run.results_count.failure_count || ' failed, ' || a_run.results_count.errored_count || ' errored, ' + || a_run.results_count.disabled_count ||' disabled, ' || a_run.results_count.warnings_count || ' warning(s)'; + if a_run.results_count.failure_count + a_run.results_count.errored_count + a_run.results_count.warnings_count > 0 then + self.print_red_text(l_summary_text); + else + self.print_green_text(l_summary_text); + end if; + if a_run.random_test_order_seed is not null then + self.print_text('Tests were executed with random order seed '''||a_run.random_test_order_seed||'''.'); + end if; + self.print_text(' '); + (self as ut_reporter_base).after_calling_run(a_run); + end; + + overriding member function get_description return varchar2 as + begin + return 'A custom reporter for pretty-printing all expectation results directly under the test'; + end; + +end; +/ diff --git a/examples/custom_reporters/ut_expectations_reporter.tps b/examples/custom_reporters/ut_expectations_reporter.tps new file mode 100644 index 000000000..a4238c302 --- /dev/null +++ b/examples/custom_reporters/ut_expectations_reporter.tps @@ -0,0 +1,30 @@ +create or replace type ut_expectations_reporter under ut_documentation_reporter( + /* + utPLSQL - Version 3 + Copyright 2016 - 2020 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. + */ + report_all_expectations varchar2(1), + + + constructor function ut_expectations_reporter(a_report_all_expectations varchar2 := 'Y') return self as result, + + overriding member procedure after_calling_test(a_test ut_test), + overriding member procedure after_calling_run(a_run in ut_run), + + overriding member function get_description return varchar2 + +) +not final +/ diff --git a/examples/demo_of_expectations/demo_equal_matcher.sql b/examples/demo_of_expectations/demo_equal_matcher.sql index 0836eeb52..f7b20581f 100644 --- a/examples/demo_of_expectations/demo_equal_matcher.sql +++ b/examples/demo_of_expectations/demo_equal_matcher.sql @@ -18,7 +18,7 @@ create or replace package demo_equal_matcher as -- %suitepath(org.utplsql.v3.demo.matchers) -- TODO this should go into context(compare_objects, Comparing objects) - -- %context(compare_objects, Comparing objects) + -- %context(Comparing objects) -- %test -- %displayname(Gives success when comparing identical objects containing identical data) @@ -48,7 +48,7 @@ create or replace package demo_equal_matcher as -- %displayname(Gives failure when comparing different objects containing identical data) procedure object_compare_different_type; - -- %end_context + -- %endcontext end; / diff --git a/examples/demo_of_expectations/drop_demo_equal_matcher.sql b/examples/demo_of_expectations/drop_demo_equal_matcher.sql new file mode 100644 index 000000000..8ec8cfa83 --- /dev/null +++ b/examples/demo_of_expectations/drop_demo_equal_matcher.sql @@ -0,0 +1,5 @@ +drop package demo_equal_matcher; +drop type demo_departments; +drop type demo_department_new; +drop type demo_department; + diff --git a/examples/demo_of_expectations/run.sql b/examples/demo_of_expectations/run.sql index a5f93a05f..42a43400c 100644 --- a/examples/demo_of_expectations/run.sql +++ b/examples/demo_of_expectations/run.sql @@ -4,8 +4,5 @@ set serveroutput on size unlimited format truncated exec ut.run(user||'.demo_equal_matcher'); -drop package demo_equal_matcher; -drop type demo_departments; -drop type demo_department_new; -drop type demo_department; +@@drop_demo_equal_matcher.sql 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..e713fa02d 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; @@ -20,18 +20,21 @@ begin ut_event_manager.initialize(); ut_event_manager.add_listener(l_doc_reporter); ut_event_manager.add_listener(l_tc_reporter); + ut_event_manager.trigger_event(ut_event_manager.gc_initialize, l_run); - 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); + ut_event_manager.trigger_event(ut_event_manager.gc_finalize, l_run); l_doc_reporter.lines_to_dbms_output(0,0); l_tc_reporter.lines_to_dbms_output(0,0); end; diff --git a/examples/developer_examples/RunExampleTestSuiteWithCustomReporter.sql b/examples/developer_examples/RunExampleTestSuiteWithCustomReporter.sql deleted file mode 100644 index 59fe15662..000000000 --- a/examples/developer_examples/RunExampleTestSuiteWithCustomReporter.sql +++ /dev/null @@ -1,54 +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 ---http://stackoverflow.com/questions/2584492/how-to-prevent-dbms-output-put-line-from-trimming-leading-whitespace -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_suite ut_logical_suite; - l_test ut_test; - l_reporter ut_output_reporter_base; - l_run ut_run; -begin - ut_event_manager.initialize(); - -- Install ut_custom_reporter first from example folder - - 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_test := ut_test(user, 'UT_EXAMPLETEST2','ut_exAmpletest'); - 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); - - -- provide a reporter to process results tabbing each hierarcy level by tab_size - l_reporter := ut_custom_reporter(a_tab_size => 2); - ut_event_manager.add_listener(l_reporter); - l_run := ut_run(ut_suite_items(l_suite)); - l_run.do_execute(); - ut_event_manager.trigger_event(ut_utils.gc_finalize, l_run); - l_reporter.lines_to_dbms_output(0,0); -end; -/ - - ---FIXME this drop is causing issues when executing script several times within single session -drop type ut_custom_reporter; -drop package ut_exampletest; -drop package ut_exampletest2; -exec dbms_session.reset_package; diff --git a/mkdocs.yml b/mkdocs.yml index 7bffe0c71..713722620 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,29 +1,103 @@ # Format documented here # http://www.mkdocs.org/user-guide/configuration/ +# https://squidfunk.github.io/mkdocs-material/getting-started/ +# See this document for list of plugins to disable for offline (local) documentation +# https://squidfunk.github.io/mkdocs-material/setup/building-for-offline-usage/ -site_name: utPLSQL -site_description: utPLSQL Ultimate Unit Testing Framework for Oracle PL/SQL -copyright: Copyright © 2016 - 2018 utPLSQL Team +edit_uri: "" +site_url: http://utPLSQL.org/ +site_name: utPLSQL-framework +site_description: utPLSQL Ultimate Testing Framework for Oracle PL/SQL & SQL +copyright: Copyright © 2016 - 2022 utPLSQL Team repo_url: https://github.com/utPLSQL/utPLSQL -theme: mkdocs +extra_css: + - stylesheets/extra.css +theme: + name: material + palette: + # Palette toggle for light mode + - media: "(prefers-color-scheme: light)" + scheme: default + toggle: + icon: material/lightbulb-outline + name: Switch to dark mode + # Palette toggle for dark mode + - media: "(prefers-color-scheme: dark)" + scheme: slate + toggle: + icon: material/lightbulb + name: Switch to light mode + logo: assets/icon-transparent.png + favicon: assets/favicon.png + features: + - navigation.instant # disable for offline docs +# - navigation.indexes + - navigation.tabs + - navigation.tracking + - toc.follow + - toc.integrate + - search.suggest + - search.highlight +extra: +# homepage: http://jgebal.github.io/ +# homepage: http://utPLSQL.org/ + social: + - icon: fontawesome/brands/twitter + link: https://twitter.com/utPLSQL + - icon: fontawesome/brands/slack + link: https://join.slack.com/t/utplsql/shared_invite/zt-xwm68udy-4cF_3PNEyczYEbWr38W5ww + - icon: fontawesome/brands/github + link: https://github.com/utPLSQL + - icon: fontawesome/solid/envelope + link: mailto:utPLSQL@utPLSQL.org + consent: + title: Cookie consent + description: >- + We use cookies to recognize your repeated visits and preferences, as well + as to measure the effectiveness of our documentation and whether users + find what they're searching for. With your consent, you're helping us to + make our documentation better. + version: # disable for offline docs + provider: mike # disable for offline docs +markdown_extensions: + - admonition + - pymdownx.details + - pymdownx.superfences + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.caret + - pymdownx.mark + - pymdownx.tilde + - toc: + permalink: true use_directory_urls: false strict: true +plugins: + - search + - mike + - git-revision-date-localized: # disable for offline docs + enable_creation_date: true # disable for offline docs + type: datetime # disable for offline docs + nav: - - Home: index.md - User Guide: + - index.md - Installation: userguide/install.md - Getting Started: userguide/getting-started.md - Annotations: userguide/annotations.md - Expectations: userguide/expectations.md - Advanced data comparison: userguide/advanced_data_comparison.md - Running unit tests: userguide/running-unit-tests.md - - Testing best pracitces: userguide/best-practices.md + - Querying for test suites: userguide/querying_suites.md + - Testing best practices: userguide/best-practices.md - Upgrade utPLSQL: userguide/upgrade.md - Reporting: - Using reporters: userguide/reporters.md - - Reporting errors: userguide/exception-reporting.md - Code coverage: userguide/coverage.md + - Error handling and reporting: userguide/exception-reporting.md - About: - Project Details: about/project-details.md - License: about/license.md diff --git a/mkdocs_offline.yml b/mkdocs_offline.yml new file mode 100644 index 000000000..31c90615e --- /dev/null +++ b/mkdocs_offline.yml @@ -0,0 +1,105 @@ +# Format documented here +# http://www.mkdocs.org/user-guide/configuration/ +# https://squidfunk.github.io/mkdocs-material/getting-started/ +# See this document for list of plugins to disable for offline (local) documentation +# https://squidfunk.github.io/mkdocs-material/setup/building-for-offline-usage/ + +edit_uri: "" +site_url: http://utPLSQL.org/ +site_name: utPLSQL-framework +site_description: utPLSQL Ultimate Testing Framework for Oracle PL/SQL & SQL +copyright: Copyright © 2016 - 2022 utPLSQL Team +#repo_url: https://github.com/utPLSQL/utPLSQL # disable for offline docs +extra_css: + - stylesheets/extra.css +theme: + name: material + palette: + # Palette toggle for light mode + - media: "(prefers-color-scheme: light)" + scheme: default + toggle: + icon: material/lightbulb-outline + name: Switch to dark mode + # Palette toggle for dark mode + - media: "(prefers-color-scheme: dark)" + scheme: slate + toggle: + icon: material/lightbulb + name: Switch to light mode + logo: assets/icon-transparent.png + favicon: assets/favicon.png + features: +# - navigation.instant # disable for offline docs +# - navigation.indexes + - navigation.tabs + - navigation.tracking + - toc.follow + - toc.integrate + - search.suggest + - search.highlight +extra: +# homepage: http://jgebal.github.io/ +# homepage: http://utPLSQL.org/ + social: + - icon: fontawesome/brands/twitter + link: https://twitter.com/utPLSQL + - icon: fontawesome/brands/slack + link: https://join.slack.com/t/utplsql/shared_invite/zt-xwm68udy-4cF_3PNEyczYEbWr38W5ww + - icon: fontawesome/brands/github + link: https://github.com/utPLSQL + - icon: fontawesome/solid/envelope + link: mailto:utPLSQL@utPLSQL.org + consent: + title: Cookie consent + description: >- + We use cookies to recognize your repeated visits and preferences, as well + as to measure the effectiveness of our documentation and whether users + find what they're searching for. With your consent, you're helping us to + make our documentation better. +# version: # disable for offline docs +# provider: mike # disable for offline docs +markdown_extensions: + - admonition + - pymdownx.details + - pymdownx.superfences + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.caret + - pymdownx.mark + - pymdownx.tilde + - toc: + permalink: true +use_directory_urls: false +strict: true + +plugins: +# - search # disable for offline docs + - mike +# - git-revision-date-localized: # disable for offline docs +# enable_creation_date: true # disable for offline docs +# type: datetime # disable for offline docs + +nav: + - User Guide: + - index.md + - Installation: userguide/install.md + - Getting Started: userguide/getting-started.md + - Annotations: userguide/annotations.md + - 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 practices: userguide/best-practices.md + - Upgrade utPLSQL: userguide/upgrade.md + - Reporting: + - Using reporters: userguide/reporters.md + - Code coverage: userguide/coverage.md + - Error handling and reporting: userguide/exception-reporting.md + - About: + - Project Details: about/project-details.md + - License: about/license.md + - Support: about/support.md + - Authors: about/authors.md diff --git a/old_tests/RunAll.sql b/old_tests/RunAll.sql deleted file mode 100644 index f785aabc1..000000000 --- a/old_tests/RunAll.sql +++ /dev/null @@ -1,423 +0,0 @@ -set trimspool on -set echo off -set feedback off -set verify off -Clear Screen -set linesize 32767 -set pagesize 0 -set long 200000000 -set longchunksize 1000000 -set serveroutput on size unlimited format truncated -@@lib/RunVars.sql - -@@lib/mystats/mystats_pkg.sql -exec mystats_pkg.ms_start; - -spool RunAll.log - ---Global setup -@@helpers/ut_example_tests.pks -@@helpers/ut_example_tests.pkb ---@@helpers/cre_tab_ut_test_table.sql -create table ut$test_table (val varchar2(1)); -@@helpers/department.tps -@@helpers/department1.tps -@@helpers/test_package_3.pck -@@helpers/test_package_1.pck -@@helpers/test_package_2.pck -@@helpers/utplsql_test_reporter.typ -@@helpers/test_reporters.pks -@@helpers/test_reporters.pkb -@@helpers/html_coverage_test.pck -@@helpers/test_reporters_1.pks -@@helpers/test_reporters_1.pkb - ---Start coverage in develop mode (coverage for utPLSQL framework) ---Regular coverage excludes the framework -exec ut_coverage.coverage_start(); -exec ut_coverage.set_develop_mode(true); - -@@lib/RunTest.sql ut_expectations/ut_expectation_processor.nulls_are_equal.raisesExceptionWhenTryingToSetNullValue.sql -@@lib/RunTest.sql ut_expectations/ut_expectation_processor.stackOnFailedTest.sql -@@lib/RunTest.sql ut_expectations/ut_expectation_processor.stackOnUtFail.sql - -@@lib/RunTest.sql ut_metadata/ut_metadata.form_name.TrimStandaloneProgramName.sql - -@@lib/RunTest.sql ut_reporters/ut_documentation_reporter.providesCorrectLineFromStacktrace.sql -@@lib/RunTest.sql ut_reporters/ut_documentation_reporter.reportMultipleWarnings.sql -@@lib/RunTest.sql ut_reporters/ut_documentation_reporter.reportTestTiming.sql -@@lib/RunTest.sql ut_reporters/ut_html_reporter.DefaultSchemaCoverage.sql -@@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 -@@lib/RunTest.sql ut_utils/ut_utils.test_result_to_char.RunsWithInvalidValues.sql -@@lib/RunTest.sql ut_utils/ut_utils.test_result_to_char.RunsWithNullValue.sql -@@lib/RunTest.sql ut_utils/ut_utils.test_result_to_char.Success.sql - ---Finally -@@lib/RunSummary - -spool off - ---Global cleanup ---removing objects that should not be part of coverage report -drop package ut_example_tests; -drop table ut$test_table; -drop type department$; -drop type department1$; -drop package test_package_1; -drop package test_package_2; -drop package test_package_3; -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 termout on -spool stats.log -exec mystats_pkg.ms_stop(1000); -spool off - ---can be used by CI to check for tests status -exit :failures_count diff --git a/old_tests/helpers/department.tps b/old_tests/helpers/department.tps deleted file mode 100644 index b2c76a343..000000000 --- a/old_tests/helpers/department.tps +++ /dev/null @@ -1,4 +0,0 @@ -create or replace type department$ as object( - dept_name varchar2(30) -) -/ diff --git a/old_tests/helpers/department1.tps b/old_tests/helpers/department1.tps deleted file mode 100644 index 2450f7b74..000000000 --- a/old_tests/helpers/department1.tps +++ /dev/null @@ -1,4 +0,0 @@ -create or replace type department1$ as object( - dept_name varchar2(30) -) -/ diff --git a/old_tests/helpers/html_coverage_test.pck b/old_tests/helpers/html_coverage_test.pck deleted file mode 100644 index 58b80e7b2..000000000 --- a/old_tests/helpers/html_coverage_test.pck +++ /dev/null @@ -1,25 +0,0 @@ -create or replace package ut3$user#.html_coverage_test is - - -- Author : LUW07 - -- Created : 23/05/2017 09:37:29 - -- Purpose : Supporting html coverage procedure - - -- Public type declarations - procedure run_if_statment(o_result out number); -end html_coverage_test; -/ -create or replace package body ut3$user#.html_coverage_test is - - -- Private type declarations - procedure run_if_statment(o_result out number) is - l_testedvalue number := 1; - l_success number := 0; - begin - if l_testedvalue = 1 then - l_success := 1; - end if; - - o_result := l_success; - end run_if_statment; -end html_coverage_test; -/ diff --git a/old_tests/helpers/test_package_1.pck b/old_tests/helpers/test_package_1.pck deleted file mode 100644 index 8b221f354..000000000 --- a/old_tests/helpers/test_package_1.pck +++ /dev/null @@ -1,71 +0,0 @@ -create or replace package test_package_1 is - - --%suite - --%displayname(test_package_1) - --%suitepath(tests) - - gv_glob_val number; - - --%beforeeach - procedure global_setup; - - --%aftereach - procedure global_teardown; - - --%test - --%displayname(Test1 from test package 1) - procedure test1; - - --%test(Test2 from test package 1) - --%beforetest(test2_setup) - --%aftertest(test2_teardown) - procedure test2; - - procedure test2_setup; - - procedure test2_teardown; - -end test_package_1; -/ -create or replace package body test_package_1 is - - gv_var_1 number; - - gv_var_1_temp number; - - procedure global_setup is - begin - gv_var_1 := 1; - gv_glob_val := 1; - end; - - procedure global_teardown is - begin - gv_var_1 := 0; - gv_glob_val := 0; - end; - - procedure test1 is - begin - ut.expect(gv_var_1,'Some expectation').to_equal(1); - end; - - procedure test2 is - begin - ut.expect(gv_var_1,'Some expectation').to_equal(2); - end; - - procedure test2_setup is - begin - gv_var_1_temp := gv_var_1; - gv_var_1 := 2; - end; - - procedure test2_teardown is - begin - gv_var_1 := gv_var_1_temp; - gv_var_1_temp := null; - end; - -end test_package_1; -/ diff --git a/old_tests/helpers/test_package_2.pck b/old_tests/helpers/test_package_2.pck deleted file mode 100644 index 871a4f2a8..000000000 --- a/old_tests/helpers/test_package_2.pck +++ /dev/null @@ -1,69 +0,0 @@ -create or replace package test_package_2 is - - --%suite - --%suitepath(tests.test_package_1) - - gv_glob_val varchar2(1); - - --%beforeeach - procedure global_setup; - - --%aftereach - procedure global_teardown; - - --%test - procedure test1; - - --%test - --%beforetest(test2_setup) - --%aftertest(test2_teardown) - procedure test2; - - procedure test2_setup; - - procedure test2_teardown; - -end test_package_2; -/ -create or replace package body test_package_2 is - - gv_var_1 varchar2(1); - - gv_var_1_temp varchar2(1); - - procedure global_setup is - begin - gv_var_1 := 'a'; - gv_glob_val := 'z'; - end; - - procedure global_teardown is - begin - gv_var_1 := 'n'; - gv_glob_val := 'n'; - end; - - procedure test1 is - begin - ut.expect(gv_var_1).to_equal('a'); - end; - - procedure test2 is - begin - ut.expect(gv_var_1).to_equal('b'); - end; - - procedure test2_setup is - begin - gv_var_1_temp := gv_var_1; - gv_var_1 := 'b'; - end; - - procedure test2_teardown is - begin - gv_var_1 := gv_var_1_temp; - gv_var_1_temp := null; - end; - -end test_package_2; -/ diff --git a/old_tests/helpers/test_package_3.pck b/old_tests/helpers/test_package_3.pck deleted file mode 100644 index 11352369e..000000000 --- a/old_tests/helpers/test_package_3.pck +++ /dev/null @@ -1,80 +0,0 @@ -create or replace package test_package_3 is - - --%suite - --%suitepath(tests2) - --%rollback(auto) - - gv_glob_val number; - - --%beforeeach - procedure global_setup; - - --%aftereach - procedure global_teardown; - - --%test - --%rollback(auto) - procedure test1; - - --%test - --%beforetest(test2_setup) - --%aftertest(test2_teardown) - procedure test2; - - procedure test2_setup; - - procedure test2_teardown; - - --%test - --%disabled - procedure disabled_test; - -end test_package_3; -/ -create or replace package body test_package_3 is - - gv_var_1 number; - - gv_var_1_temp number; - - procedure global_setup is - begin - gv_var_1 := 1; - gv_glob_val := 1; - end; - - procedure global_teardown is - begin - gv_var_1 := 0; - gv_glob_val := 0; - end; - - procedure test1 is - begin - ut.expect(gv_var_1).to_equal(1); - end; - - procedure test2 is - begin - ut.expect(gv_var_1).to_equal(2); - end; - - procedure test2_setup is - begin - gv_var_1_temp := gv_var_1; - gv_var_1 := 2; - end; - - procedure test2_teardown is - begin - gv_var_1 := gv_var_1_temp; - gv_var_1_temp := null; - end; - - procedure disabled_test is - begin - null; - end; - -end test_package_3; -/ diff --git a/old_tests/helpers/test_reporters.pkb b/old_tests/helpers/test_reporters.pkb deleted file mode 100644 index 774690d06..000000000 --- a/old_tests/helpers/test_reporters.pkb +++ /dev/null @@ -1,67 +0,0 @@ -create or replace package body test_reporters -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 passing_test - is - begin - dbms_output.put_line(''); - ut.expect(1,'Test 1 Should Pass').to_equal(1); - end; - - procedure failing_test - is - begin - dbms_output.put_line(''); - ut.expect(1,'Fails as values are different').to_equal(2); - end; - - procedure erroring_test - is - l_variable integer; - begin - dbms_output.put_line(''); - l_variable := 'a string'; - ut.expect(l_variable).to_equal(1); - end; - - procedure disabled_test - is - begin - dbms_output.put_line(''); - ut.expect(1,'this should not execute').to_equal(1); - end; - - procedure beforeall is - begin - dbms_output.put_line(''); - end; - - procedure afterall is - begin - dbms_output.put_line(''); - end; - -end; -/ - diff --git a/old_tests/helpers/test_reporters.pks b/old_tests/helpers/test_reporters.pks deleted file mode 100644 index ae040bbef..000000000 --- a/old_tests/helpers/test_reporters.pks +++ /dev/null @@ -1,38 +0,0 @@ -create or replace package test_reporters -as - --%suite(A suite for testing different outcomes from reporters) - --%suitepath(org.utplsql.utplsql.test) - - --%beforeall - procedure beforeall; - - --%beforeeach - procedure beforeeach; - - --%test - --%beforetest(beforetest) - --%aftertest(aftertest) - procedure passing_test; - - procedure beforetest; - - procedure aftertest; - - --%test(a test with failing assertion) - procedure failing_test; - - --%test(a test raising unhandled exception) - procedure erroring_test; - - --%test(a disabled test) - --%disabled - procedure disabled_test; - - --%aftereach - procedure aftereach; - - --%afterall - procedure afterall; - -end; -/ diff --git a/old_tests/helpers/test_reporters_1.pkb b/old_tests/helpers/test_reporters_1.pkb deleted file mode 100644 index 6ac9e6035..000000000 --- a/old_tests/helpers/test_reporters_1.pkb +++ /dev/null @@ -1,11 +0,0 @@ -create or replace package body test_reporters_1 -as - procedure diffrentowner_test - is - l_result number; - begin - ut3$user#.html_coverage_test.run_if_statment(l_result); - ut.expect(l_result).to_equal(1); - end; -end; -/ diff --git a/old_tests/helpers/test_reporters_1.pks b/old_tests/helpers/test_reporters_1.pks deleted file mode 100644 index c64820744..000000000 --- a/old_tests/helpers/test_reporters_1.pks +++ /dev/null @@ -1,10 +0,0 @@ -create or replace package test_reporters_1 -as - --%suite(A suite for testing html coverage options) - --%suitepath(org.utplsql.utplsql.test.test_reporters) - - --%test(a test calling package outside schema) - procedure diffrentowner_test; - -end; -/ diff --git a/old_tests/helpers/ut_example_tests.pkb b/old_tests/helpers/ut_example_tests.pkb deleted file mode 100644 index b04953303..000000000 --- a/old_tests/helpers/ut_example_tests.pkb +++ /dev/null @@ -1,43 +0,0 @@ -create or replace package body ut_example_tests -as - - procedure setup as - begin - g_number := 0; - end; - - procedure teardown - as - begin - g_char := null; - end; - - procedure beforeeach as - begin - g_number2 := 0; - end; - - procedure aftereach - as - begin - g_char2 := 'F'; - end; - - procedure ut_passing_test - as - begin - g_number := g_number + 1; - g_number2 := g_number2 + 1; - g_char := 'a'; - g_char2 := 'a'; - ut.expect(1,'Test 1 Should Pass').to_equal(1); - end; - - procedure ut_commit_test - is - begin - commit; - end; - -end; -/ diff --git a/old_tests/helpers/ut_example_tests.pks b/old_tests/helpers/ut_example_tests.pks deleted file mode 100644 index 56d9e32fe..000000000 --- a/old_tests/helpers/ut_example_tests.pks +++ /dev/null @@ -1,14 +0,0 @@ -create or replace package ut_example_tests -as - g_number number; - g_number2 number; - g_char varchar2(1); - g_char2 varchar2(1); - procedure setup; - procedure teardown; - procedure beforeeach; - procedure aftereach; - procedure ut_passing_test; - procedure ut_commit_test; -end; -/ diff --git a/old_tests/helpers/utplsql_test_reporter.typ b/old_tests/helpers/utplsql_test_reporter.typ deleted file mode 100644 index 874777341..000000000 --- a/old_tests/helpers/utplsql_test_reporter.typ +++ /dev/null @@ -1,20 +0,0 @@ -create or replace type utplsql_test_reporter under ut_output_reporter_base( - constructor function utplsql_test_reporter(self in out nocopy utplsql_test_reporter) return self as result, - overriding member procedure after_calling_run(self in out nocopy utplsql_test_reporter, a_run in ut_run) -) -/ - -create or replace type body utplsql_test_reporter is - constructor function utplsql_test_reporter(self in out nocopy utplsql_test_reporter) return self as result is - begin - self.init($$plsql_unit); - return; - end; - - overriding member procedure after_calling_run(self in out nocopy utplsql_test_reporter, a_run in ut_run) is - begin - self.print_text(a_run.result); - end; -end; -/ - diff --git a/old_tests/lib/RunSummary.sql b/old_tests/lib/RunSummary.sql deleted file mode 100644 index 60c7c8e71..000000000 --- a/old_tests/lib/RunSummary.sql +++ /dev/null @@ -1,16 +0,0 @@ -prompt -prompt ************************************************************************************ -begin - dbms_output.put_line( - 'tests: '||to_char(:failures_count + :successes_count) - ||' , success: '||:successes_count - ||' , failure: '||:failures_count - ||' , executed in '||((dbms_utility.get_time - :run_start_time)/100)||' second(s)' - ); - if :failures_count > 0 then - dbms_output.put_line( ' Some tests have failed, please review results!'); - else - dbms_output.put_line( ' All tests have passed.'); - end if; -end; -/ diff --git a/old_tests/lib/RunTest.sql b/old_tests/lib/RunTest.sql deleted file mode 100644 index 59075f045..000000000 --- a/old_tests/lib/RunTest.sql +++ /dev/null @@ -1,30 +0,0 @@ -var test_result number -exec :test_result := null; - -prompt Executing test: &1 -exec :test_start_time := dbms_utility.get_time; -@@&1 -set serveroutput on size unlimited format truncated -set termout on -declare - l_duration_str varchar2(300) := ', executed in: '||((dbms_utility.get_time - :test_start_time)/100)||' second(s)'; -begin - case - when :test_result = ut_utils.gc_success then - :successes_count := :successes_count + 1; - else - dbms_output.put_line('---------------------------------------'); - dbms_output.put_line(' Failure'||l_duration_str); - dbms_output.put_line('---------------------------------------'); - :failures_count := :failures_count + 1; - end case; -end; -/ - -rollback; -begin - ut_expectation_processor.clear_expectations; - ut_utils.cleanup_temp_tables; -end; -/ - diff --git a/old_tests/lib/RunVars.sql b/old_tests/lib/RunVars.sql deleted file mode 100644 index bbc0f3124..000000000 --- a/old_tests/lib/RunVars.sql +++ /dev/null @@ -1,9 +0,0 @@ -var successes_count number -var failures_count number -var test_result number -var run_start_time number -var test_start_time number -exec :successes_count := 0; -exec :failures_count := 0; -exec :test_result := 0; -exec :run_start_time := dbms_utility.get_time; diff --git a/old_tests/readme.md b/old_tests/readme.md deleted file mode 100644 index 51e6cc05a..000000000 --- a/old_tests/readme.md +++ /dev/null @@ -1 +0,0 @@ -Contains tests used to test utPLSQL. \ No newline at end of file diff --git a/old_tests/runAll.sh b/old_tests/runAll.sh deleted file mode 100755 index a8b52979a..000000000 --- a/old_tests/runAll.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -set -ev -#goto git root directory -git rev-parse && cd "$(git rev-parse --show-cdup)" - -cd old_tests - -"$SQLCLI" ${UT3_OWNER}/${UT3_OWNER_PASSWORD}@//${CONNECTION_STR} @RunAll.sql diff --git a/old_tests/ut_expectations/ut_expectation_processor.nulls_are_equal.raisesExceptionWhenTryingToSetNullValue.sql b/old_tests/ut_expectations/ut_expectation_processor.nulls_are_equal.raisesExceptionWhenTryingToSetNullValue.sql deleted file mode 100644 index 49eb501ba..000000000 --- a/old_tests/ut_expectations/ut_expectation_processor.nulls_are_equal.raisesExceptionWhenTryingToSetNullValue.sql +++ /dev/null @@ -1,12 +0,0 @@ -declare - e_numeric_or_value_error exception; - pragma exception_init(e_numeric_or_value_error, -6502); - l_value boolean := null; -begin - ut_expectation_processor.nulls_Are_equal(l_value); - :test_result := ut_utils.gc_failure; - exception - when e_numeric_or_value_error then - :test_result := ut_utils.gc_success; -end; -/ diff --git a/old_tests/ut_expectations/ut_expectation_processor.stackOnFailedTest.sql b/old_tests/ut_expectations/ut_expectation_processor.stackOnFailedTest.sql deleted file mode 100644 index 4a94cbf0d..000000000 --- a/old_tests/ut_expectations/ut_expectation_processor.stackOnFailedTest.sql +++ /dev/null @@ -1,41 +0,0 @@ -set termout off -create or replace package tst_stack_on_failed_test as - --%suite - - --%test - procedure test; -end; -/ - -create or replace package body tst_stack_on_failed_test as - procedure test is begin ut.expect(1).to_equal(2); end; -end; -/ - -set termout on - -declare - l_test_report ut_varchar2_list; - l_output_data ut_varchar2_list; - l_output varchar2(32767); - l_expected varchar2(32767); -begin - l_expected := q'[%Failures:%at "UT3.TST_STACK_ON_FAIL%", line 2%]'; - - --act - select * - bulk collect into l_output_data - from table(ut.run('tst_stack_on_failed_test',ut_documentation_reporter())); - - l_output := ut_utils.table_to_clob(l_output_data); - - --assert - if l_output like l_expected then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('Actual:"'||l_output||'"'); - end if; -end; -/ - -drop package tst_stack_on_failed_test; diff --git a/old_tests/ut_expectations/ut_expectation_processor.stackOnUtFail.sql b/old_tests/ut_expectations/ut_expectation_processor.stackOnUtFail.sql deleted file mode 100644 index 13e64b1ac..000000000 --- a/old_tests/ut_expectations/ut_expectation_processor.stackOnUtFail.sql +++ /dev/null @@ -1,41 +0,0 @@ -set termout off -create or replace package tst_stack_on_fail as - --%suite - - --%test - procedure test; -end; -/ - -create or replace package body tst_stack_on_fail as - procedure test is begin ut.fail('test failure'); end; -end; -/ - -set termout on - -declare - l_test_report ut_varchar2_list; - l_output_data ut_varchar2_list; - l_output varchar2(32767); - l_expected varchar2(32767); -begin - l_expected := q'[%Failures:%at "UT3.TST_STACK_ON_FAIL%", line 2%]'; - - --act - select * - bulk collect into l_output_data - from table(ut.run('tst_stack_on_fail',ut_documentation_reporter())); - - l_output := ut_utils.table_to_clob(l_output_data); - - --assert - if l_output like l_expected then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('Actual:"'||l_output||'"'); - end if; -end; -/ - -drop package tst_stack_on_fail; diff --git a/old_tests/ut_metadata/ut_metadata.form_name.TrimStandaloneProgramName.sql b/old_tests/ut_metadata/ut_metadata.form_name.TrimStandaloneProgramName.sql deleted file mode 100644 index d2679dc51..000000000 --- a/old_tests/ut_metadata/ut_metadata.form_name.TrimStandaloneProgramName.sql +++ /dev/null @@ -1,17 +0,0 @@ -PROMPT Trims a name for standalone program - ---Arrange -declare - l_expected varchar2(20) := 'some_procedure'; - l_result varchar2(20); -begin ---Act - l_result := ut_metadata.form_name(NULL, ' '||l_expected||' '); ---Assert - if l_result = l_expected then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('expected: '''||l_expected||''', got: '''||l_result||'''' ); - end if; -end; -/ diff --git a/old_tests/ut_reporters/ut_documentation_reporter.providesCorrectLineFromStacktrace.sql b/old_tests/ut_reporters/ut_documentation_reporter.providesCorrectLineFromStacktrace.sql deleted file mode 100644 index 66cf41b32..000000000 --- a/old_tests/ut_reporters/ut_documentation_reporter.providesCorrectLineFromStacktrace.sql +++ /dev/null @@ -1,32 +0,0 @@ -declare - l_output_data ut_varchar2_list; - l_output varchar2(32767); - l_expected varchar2(32767); -begin - l_expected := q'[% -%Failures:% -%1)%failing_test% -%"Fails as values are different"% -%Actual: 1 (number) was expected to equal: 2 (number)% -%at "%.TEST_REPORTERS%", line% -%2)%erroring_test% -%ORA-06502% -%ORA-06512% -Finished % -5 tests, 1 failed, 1 errored%]'; - - --act - select * - bulk collect into l_output_data - from table(ut.run('test_reporters',ut_documentation_reporter())); - - l_output := ut_utils.table_to_clob(l_output_data); - - --assert - if l_output like l_expected then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('Actual:"'||l_output||'"'); - end if; -end; -/ diff --git a/old_tests/ut_reporters/ut_documentation_reporter.reportMultipleWarnings.sql b/old_tests/ut_reporters/ut_documentation_reporter.reportMultipleWarnings.sql deleted file mode 100644 index 3ebfa5790..000000000 --- a/old_tests/ut_reporters/ut_documentation_reporter.reportMultipleWarnings.sql +++ /dev/null @@ -1,75 +0,0 @@ -set termout off -create or replace package ut_output_test_rollback as - --%suite - - --%beforeall - procedure ba; - --%beforeeach - procedure be; - --%test - procedure test; - --%test - --%rollback(manual) - procedure t_manual; - --%afterall - procedure aa; - --%aftereach - procedure ae; -end; -/ - -create or replace package body ut_output_test_rollback as - procedure ba is begin commit; end; - procedure be is begin commit; end; - procedure test is begin null; end; - procedure t_manual is begin commit; end; - procedure aa is begin commit; end; - procedure ae is begin commit; end; -end; -/ - -set termout on - -declare - l_test_report ut_varchar2_list; - l_output_data ut_varchar2_list; - l_output varchar2(32767); - l_expected varchar2(32767); -begin - l_expected := q'[% - 1) ut_output_test_rollback.test - Unable to perform automatic rollback after test. An implicit or explicit commit/rollback occurred in procedures: - ut3.ut_output_test_rollback.be - ut3.ut_output_test_rollback.ae - 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.ba - ut3.ut_output_test_rollback.aa - ut3.ut_output_test_rollback.be - ut3.ut_output_test_rollback.ae - ut3.ut_output_test_rollback.t_manual - Use the "--%rollback(manual)" annotation or remove commit/rollback/ddl statements that are causing the issue. -% -Finished in % seconds -2 tests, 0 failed, 0 errored, 0 disabled, 2 warning(s)%]'; - - --act - select * - bulk collect into l_output_data - from table(ut.run(ut_varchar2_list('ut_output_test_rollback'),ut_documentation_reporter())); - - l_output := ut_utils.table_to_clob(l_output_data); - - --assert - if l_output like l_expected then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('Actual:"'||l_output||'"'); - dbms_output.put_line('Expected:"'||l_expected||'"'); - end if; -end; -/ - -drop package ut_output_test_rollback; diff --git a/old_tests/ut_reporters/ut_documentation_reporter.reportTestTiming.sql b/old_tests/ut_reporters/ut_documentation_reporter.reportTestTiming.sql deleted file mode 100644 index f7b0dd265..000000000 --- a/old_tests/ut_reporters/ut_documentation_reporter.reportTestTiming.sql +++ /dev/null @@ -1,50 +0,0 @@ -set termout off -create or replace package tst_doc_reporter_timing as - --%suite - - --%test - procedure test1; - - --%test - procedure test2; -end; -/ - -create or replace package body tst_doc_reporter_timing as - procedure test1 is begin ut.expect(1).to_equal(1); end; - procedure test2 is begin ut.expect(1).to_equal(2); end; -end; -/ - -set termout on - -declare - l_test_report ut_varchar2_list; - l_output_data ut_varchar2_list; - l_output varchar2(32767); - l_expected varchar2(32767); -begin - l_expected := q'[tst_doc_reporter_timing -%test1 [%sec] -%test2 [%sec] (FAILED - 1) -%Failures:% -Finished in % seconds -2 tests, 1 failed, 0 errored, 0 disabled, 0 warning(s)%]'; - - --act - select * - bulk collect into l_output_data - from table(ut.run('tst_doc_reporter_timing',ut_documentation_reporter())); - - l_output := ut_utils.table_to_clob(l_output_data); - - --assert - if l_output like l_expected then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('Actual:"'||l_output||'"'); - end if; -end; -/ - -drop package tst_doc_reporter_timing; diff --git a/old_tests/ut_reporters/ut_html_reporter.DefaultSchemaCoverage.sql b/old_tests/ut_reporters/ut_html_reporter.DefaultSchemaCoverage.sql deleted file mode 100644 index 5cc14f02b..000000000 --- a/old_tests/ut_reporters/ut_html_reporter.DefaultSchemaCoverage.sql +++ /dev/null @@ -1,19 +0,0 @@ -DECLARE - l_results ut_varchar2_list; - l_clob CLOB; - l_expected VARCHAR2(32767); -BEGIN - l_expected := '%

UT3.TEST_REPORTERS_1

%'; - SELECT * BULK COLLECT - INTO l_results - FROM TABLE(ut.run('test_reporters_1', ut_coverage_html_reporter())); - l_clob := ut3.ut_utils.table_to_clob(l_results); - - IF l_clob LIKE l_expected THEN - :test_result := ut3.ut_utils.gc_success; - ELSE - dbms_output.put_line('Failed to match to default schema'); - END IF; - -END; -/ \ No newline at end of file diff --git a/old_tests/ut_reporters/ut_html_reporter.UserOverrideSchemaCoverage.sql b/old_tests/ut_reporters/ut_html_reporter.UserOverrideSchemaCoverage.sql deleted file mode 100644 index ba2dd3ab6..000000000 --- a/old_tests/ut_reporters/ut_html_reporter.UserOverrideSchemaCoverage.sql +++ /dev/null @@ -1,20 +0,0 @@ -DECLARE - l_results ut_varchar2_list; - l_clob CLOB; - l_expected VARCHAR2(32767); -BEGIN - l_expected := '%

UT3$USER#.HTML_COVERAGE_TEST

%'; - SELECT * BULK COLLECT - INTO l_results - FROM TABLE(ut.run('test_reporters_1', ut_coverage_html_reporter(), - a_coverage_schemes => ut_varchar2_list('ut3$user#'))); - l_clob := ut3.ut_utils.table_to_clob(l_results); - - IF l_clob LIKE l_expected THEN - :test_result := ut3.ut_utils.gc_success; - ELSE - dbms_output.put_line('Failed to run coverage outside schema'); - END IF; - -END; -/ diff --git a/old_tests/ut_suite_manager/ut_suite_manager.AllowsDescriptionsWithComma.sql b/old_tests/ut_suite_manager/ut_suite_manager.AllowsDescriptionsWithComma.sql deleted file mode 100644 index 3ef89840a..000000000 --- a/old_tests/ut_suite_manager/ut_suite_manager.AllowsDescriptionsWithComma.sql +++ /dev/null @@ -1,67 +0,0 @@ -set termout off -create or replace package tst_package_to_be_dropped as - --%suite(A suite description, though with comma, is assigned by suite_manager) - - --%test(A test description, though with comma, is assigned by suite_manager) - procedure test1; - - --%test - --%displayname(A test description, though with comma, is assigned by suite_manager) - procedure test2; -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 - -set termout on - -declare - l_objects_to_run ut_suite_items; - l_suite ut_suite; - l_test ut_test; - l_results ut_expectation_results; -begin - l_objects_to_run := ut_suite_manager.configure_execution_by_path(ut_varchar2_list('tst_package_to_be_dropped')); - - --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_package_to_be_dropped'); - ut.expect(l_suite.description).to_equal('A suite description, though with comma, is assigned by suite_manager'); - ut.expect(l_suite.items.count).to_equal(2); - - l_test := treat(l_suite.items(1) as ut_test); - - 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 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_results := ut_expectation_processor.get_failed_expectations(); - - :test_result := ut_utils.gc_success; - for i in 1 .. l_results.count loop - :test_result := greatest(:test_result, l_results(i).status); - if l_results(i).status != ut_utils.gc_success then - dbms_output.put_line(l_results(i).get_result_clob); - end if; - end loop; -end; -/ - -set termout off -drop package tst_package_to_be_dropped -/ -set termout on 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.IncludesInvalidPackageBodiesInTheRun.sql b/old_tests/ut_suite_manager/ut_suite_manager.IncludesInvalidPackageBodiesInTheRun.sql deleted file mode 100644 index f601dc070..000000000 --- a/old_tests/ut_suite_manager/ut_suite_manager.IncludesInvalidPackageBodiesInTheRun.sql +++ /dev/null @@ -1,31 +0,0 @@ -set termout off -create table test_dependency_table (id integer); -create or replace package test_dependencies as - -- %suite - - -- %test - procedure dependant; -end; -/ -create or replace package body test_dependencies as - gc_dependant_variable test_dependency_table.id%type; - procedure dependant is begin null; end; -end; -/ -alter table test_dependency_table modify id number; -set termout on - -declare - l_result integer; -begin - select * - into l_result - from table(ut.run('test_dependencies',utplsql_test_reporter())); - :test_result := l_result; -end; -/ - -set termout off -drop table test_dependency_table; -drop package test_dependencies; -set termout on diff --git a/old_tests/ut_suite_manager/ut_suite_manager.PackageWithDollarSign.sql b/old_tests/ut_suite_manager/ut_suite_manager.PackageWithDollarSign.sql deleted file mode 100644 index d69aabe1f..000000000 --- a/old_tests/ut_suite_manager/ut_suite_manager.PackageWithDollarSign.sql +++ /dev/null @@ -1,38 +0,0 @@ -set termout off -create or replace package tst_package_with$dollar as - --%suite - - --%test - procedure test1; -end; -/ - -create or replace package body tst_package_with$dollar 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_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_package_with$dollar')); - - --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_package_with$dollar'); - - if ut_expectation_processor.get_status = ut_utils.gc_success then - :test_result := ut_utils.gc_success; - end if; -end; -/ - -drop package tst_package_with$dollar -/ diff --git a/old_tests/ut_suite_manager/ut_suite_manager.PackageWithHash.sql b/old_tests/ut_suite_manager/ut_suite_manager.PackageWithHash.sql deleted file mode 100644 index 0cb113226..000000000 --- a/old_tests/ut_suite_manager/ut_suite_manager.PackageWithHash.sql +++ /dev/null @@ -1,40 +0,0 @@ -set termout off -create or replace package tst_package_with#hash as - --%suite - - --%test - procedure test1; -end; -/ - -create or replace package body tst_package_with#hash 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_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_package_with#hash')); - - --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_package_with#hash'); - - if ut_expectation_processor.get_status = ut_utils.gc_success then - :test_result := ut_utils.gc_success; - end if; - -end; -/ - -drop package tst_package_with#hash -/ diff --git a/old_tests/ut_suite_manager/ut_suite_manager.TestWithDollarSign.sql b/old_tests/ut_suite_manager/ut_suite_manager.TestWithDollarSign.sql deleted file mode 100644 index 4d58b704f..000000000 --- a/old_tests/ut_suite_manager/ut_suite_manager.TestWithDollarSign.sql +++ /dev/null @@ -1,45 +0,0 @@ -set termout off -create or replace package tst_package_with_dollar_test as - --%suite - - --%test - procedure test$1; -end; -/ - -create or replace package body tst_package_with_dollar_test as - procedure test$1 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; - l_test ut_test; -begin - --act - l_objects_to_run := ut_suite_manager.configure_execution_by_path(ut_varchar2_list('tst_package_with_dollar_test.test$1')); - - --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_package_with_dollar_test'); - ut.expect(l_suite.items.count).to_equal(1); - - l_test := treat(l_suite.items(1) as ut_test); - - ut.expect(l_test.name).to_equal('test$1'); - - if ut_expectation_processor.get_status = ut_utils.gc_success then - :test_result := ut_utils.gc_success; - end if; - -end; -/ - -drop package tst_package_with_dollar_test -/ diff --git a/old_tests/ut_suite_manager/ut_suite_manager.TestWithHashSign.sql b/old_tests/ut_suite_manager/ut_suite_manager.TestWithHashSign.sql deleted file mode 100644 index ef965509c..000000000 --- a/old_tests/ut_suite_manager/ut_suite_manager.TestWithHashSign.sql +++ /dev/null @@ -1,46 +0,0 @@ -set termout off -create or replace package tst_package_with_hash_test as - --%suite - - --%test - procedure test#1; -end; -/ - -create or replace package body tst_package_with_hash_test as - procedure test#1 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; - l_test ut_test; -begin - - --act - l_objects_to_run := ut_suite_manager.configure_execution_by_path(ut_varchar2_list('tst_package_with_hash_test.test#1')); - - --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_package_with_hash_test'); - ut.expect(l_suite.items.count).to_equal(1); - - l_test := treat(l_suite.items(1) as ut_test); - - ut.expect(l_test.name).to_equal('test#1'); - - if ut_expectation_processor.get_status = ut_utils.gc_success then - :test_result := ut_utils.gc_success; - end if; - -end; -/ - -drop package tst_package_with_hash_test -/ 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 deleted file mode 100644 index 3023c28f0..000000000 --- a/old_tests/ut_suite_manager/ut_suite_manager.get_schema_ut_packages.IncludesPackagesWithSutePath.sql +++ /dev/null @@ -1,33 +0,0 @@ -set termout off -create or replace package tests as - procedure dummy; -end; -/ -set termout on - -declare - l_expected ut_object_names; - l_actual ut_object_names; -begin - l_expected := ut_object_names( - ut_object_name(user,'TEST_PACKAGE_1'), - ut_object_name(user,'TEST_PACKAGE_2'), - ut_object_name(user,'TEST_PACKAGE_3'), - ut_object_name(user,'TEST_REPORTERS_1'), - 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 - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('actual:'||xmltype(anydata.convertcollection(l_actual)).getclobval()); - dbms_output.put_line('expected:'||xmltype(anydata.convertcollection(l_expected)).getclobval()); - end if; -end; -/ - -set termout off -drop package tests -/ -set termout on - 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/old_tests/ut_utils/common/ut_utils.clob_to_table.sql b/old_tests/ut_utils/common/ut_utils.clob_to_table.sql deleted file mode 100644 index 9fc831576..000000000 --- a/old_tests/ut_utils/common/ut_utils.clob_to_table.sql +++ /dev/null @@ -1,43 +0,0 @@ ---Arrange -declare - l_clob clob := '&1'; - l_delimiter varchar2(1) := '&2'; - l_expected ut_varchar2_list := &3; - l_result ut_varchar2_list; - l_limit integer := &4; - l_result_str varchar2(32767); - l_errors integer := 0; - function compare_element(a_element_id integer, a_expected ut_varchar2_list, a_actual ut_varchar2_list) return integer is - begin - if a_expected.exists(a_element_id) and a_actual.exists(a_element_id) then - if a_expected(a_element_id) = a_actual(a_element_id) or a_expected(a_element_id) is null and a_actual(a_element_id) is null then - return 0; - else - dbms_output.put('a_expected('||a_element_id||')='||a_expected(a_element_id)||' | a_actual('||a_element_id||')='||a_actual(a_element_id)); - end if; - end if; - if not a_expected.exists(a_element_id) then - dbms_output.put('a_expected('||a_element_id||') does not exist '); - end if; - if not a_actual.exists(a_element_id) then - dbms_output.put('a_actual('||a_element_id||') does not exist '); - end if; - dbms_output.put_line(null); - return 1; - end; -begin ---Act - select column_value bulk collect into l_result from table( ut_utils.clob_to_table(l_clob, l_limit, l_delimiter) ); - for i in 1 .. l_result.count loop - l_result_str := l_result_str||''''||l_result(i)||''''||l_delimiter; - end loop; - l_result_str := rtrim(l_result_str,l_delimiter); ---Assert - for i in 1 .. greatest(l_expected.count, l_result.count) loop - l_errors := l_errors + compare_element(i, l_expected, l_result); - end loop; - if l_errors = 0 then - :test_result := ut_utils.gc_success; - end if; -end; -/ diff --git a/old_tests/ut_utils/common/ut_utils.table_to_clob.sql b/old_tests/ut_utils/common/ut_utils.table_to_clob.sql deleted file mode 100644 index fa319d731..000000000 --- a/old_tests/ut_utils/common/ut_utils.table_to_clob.sql +++ /dev/null @@ -1,17 +0,0 @@ ---Arrange -declare - l_delimiter varchar2(1) := &2; - l_expected clob := &3; - l_result clob; -begin ---Act - l_result := ut_utils.table_to_clob(&1, l_delimiter); ---Assert - if l_expected is null and l_result is null or l_expected = l_result then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('Expected: "'||l_expected||'"'); - dbms_output.put_line('Actual: "'||l_result||'"'); - end if; -end; -/ diff --git a/old_tests/ut_utils/ut_utils.append_to_clob.worksWithMultiByteChars.sql b/old_tests/ut_utils/ut_utils.append_to_clob.worksWithMultiByteChars.sql deleted file mode 100644 index 80dfddcdf..000000000 --- a/old_tests/ut_utils/ut_utils.append_to_clob.worksWithMultiByteChars.sql +++ /dev/null @@ -1,43 +0,0 @@ -column nls_lang noprint new_value v_nls_lang - -select value as nls_lang from nls_session_parameters where parameter = 'NLS_DATE_LANGUAGE'; - ---Arrange -alter session set nls_date_language=ENGLISH; -create or replace package tst_chars as --- 2) Status of the process = ‘PE’ with no linked data -end; -/ - -alter session set nls_date_language=RUSSIAN; - ---Act -declare - l_lines sys.dbms_preprocessor.source_lines_t; - l_result clob; -begin - l_lines := sys.dbms_preprocessor.get_post_processed_source( - object_type => 'PACKAGE', - schema_name => user, - object_name => 'TST_CHARS' - ); - :test_result := ut_utils.gc_success; - for i in 1..l_lines.count loop - l_result := null; - ut_utils.append_to_clob(l_result, l_lines(i)); - - --Assert - :test_result := coalesce(:test_result, ut_utils.gc_success); - if dbms_lob.getlength(l_result) != dbms_lob.getlength(l_lines(i)) then - :test_result := ut_utils.gc_failure; - dbms_output.put_line('Expected: "'||l_lines(i)||'"'); - dbms_output.put_line('Actual: "'||l_result||'"'); - end if; - end loop; -end; -/ - -alter session set nls_date_language=&&v_nls_lang; - -undef v_nls_lang; -drop package tst_chars; diff --git a/old_tests/ut_utils/ut_utils.clob_to_table.sql b/old_tests/ut_utils/ut_utils.clob_to_table.sql deleted file mode 100644 index 5c45c729a..000000000 --- a/old_tests/ut_utils/ut_utils.clob_to_table.sql +++ /dev/null @@ -1,7 +0,0 @@ -@@lib/RunTest.sql "ut_utils/common/ut_utils.clob_to_table.sql 'a,b,c,d' ',' ut_varchar2_list('a','b','c','d') 1000" -@@lib/RunTest.sql "ut_utils/common/ut_utils.clob_to_table.sql '' ',' ut_varchar2_list() 1000" -@@lib/RunTest.sql "ut_utils/common/ut_utils.clob_to_table.sql '1,b,c,d' '' ut_varchar2_list('1,b,','c,d') 4" -@@lib/RunTest.sql "ut_utils/common/ut_utils.clob_to_table.sql 'abcdefg,hijk,axa,a' ',' ut_varchar2_list('abc','def','g','hij','k','axa','a') 3" -@@lib/RunTest.sql "ut_utils/common/ut_utils.clob_to_table.sql ',a,,c,d,' ',' ut_varchar2_list('','a','','c','d','') 1000" - - diff --git a/old_tests/ut_utils/ut_utils.clob_to_table_multibyte.sql b/old_tests/ut_utils/ut_utils.clob_to_table_multibyte.sql deleted file mode 100644 index 9926a5dff..000000000 --- a/old_tests/ut_utils/ut_utils.clob_to_table_multibyte.sql +++ /dev/null @@ -1,22 +0,0 @@ ---Arrange -declare - l_varchar2_byte_limit integer := 32767; - l_workaround_byte_limit integer := 8191; - l_singlebyte_string_max_size varchar2(32767 char) := rpad('x',l_varchar2_byte_limit,'x'); - l_twobyte_character char(1 char) := 'ж'; - l_clob_multibyte clob := l_twobyte_character||l_singlebyte_string_max_size; --here we have 32769(2+32767) bytes and 32768 chars - l_expected ut_varchar2_list := ut_varchar2_list(); - l_result ut_varchar2_list; -begin - l_expected.extend(1); - l_expected(1) := l_twobyte_character||substr(l_singlebyte_string_max_size,1,l_workaround_byte_limit-1); ---Act - l_result := ut_utils.clob_to_table(l_clob_multibyte); ---Assert - if l_result(1) = l_expected(1) then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('expected: 1st string length '||length(l_expected(1))||', got 1st string length: '||length(l_result(1))); - end if; -end; -/ \ No newline at end of file diff --git a/old_tests/ut_utils/ut_utils.table_to_clob.sql b/old_tests/ut_utils/ut_utils.table_to_clob.sql deleted file mode 100644 index 8fe37ff92..000000000 --- a/old_tests/ut_utils/ut_utils.table_to_clob.sql +++ /dev/null @@ -1,7 +0,0 @@ -@@lib/RunTest.sql "ut_utils/common/ut_utils.table_to_clob.sql "cast(null as ut_varchar2_list)" ''',''' ''''''" -@@lib/RunTest.sql "ut_utils/common/ut_utils.table_to_clob.sql ut_varchar2_list() ''',''' ''''''" -@@lib/RunTest.sql "ut_utils/common/ut_utils.table_to_clob.sql ut_varchar2_list('a','b','c','d') ''',''' '''a,b,c,d''' " -@@lib/RunTest.sql "ut_utils/common/ut_utils.table_to_clob.sql ut_varchar2_list('1,b,','c,d') ''',''' '''1,b,,c,d'''" -@@lib/RunTest.sql "ut_utils/common/ut_utils.table_to_clob.sql ut_varchar2_list('','a','','c','d','') ''',''' ''',a,,c,d,'''" - - diff --git a/old_tests/ut_utils/ut_utils.test_result_to_char.RunsWithInvalidValues.sql b/old_tests/ut_utils/ut_utils.test_result_to_char.RunsWithInvalidValues.sql deleted file mode 100644 index 012e03c5c..000000000 --- a/old_tests/ut_utils/ut_utils.test_result_to_char.RunsWithInvalidValues.sql +++ /dev/null @@ -1,15 +0,0 @@ ---Arrange -declare - l_expected varchar2(20) := 'Unknown(-1)'; - l_result varchar2(20); -begin ---Act - l_result := ut_utils.test_result_to_char(-1); ---Assert - if l_result = l_expected then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('expected: '||l_expected||', got: '||l_result ); - end if; -end; -/ diff --git a/old_tests/ut_utils/ut_utils.test_result_to_char.RunsWithNullValue.sql b/old_tests/ut_utils/ut_utils.test_result_to_char.RunsWithNullValue.sql deleted file mode 100644 index c4f7a6962..000000000 --- a/old_tests/ut_utils/ut_utils.test_result_to_char.RunsWithNullValue.sql +++ /dev/null @@ -1,15 +0,0 @@ ---Arrange -declare - l_expected varchar2(20) := 'Unknown(NULL)'; - l_result varchar2(20); -begin ---Act - l_result := ut_utils.test_result_to_char(NULL); ---Assert - if l_result = l_expected then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('expected: '||l_expected||', got: '||l_result ); - end if; -end; -/ diff --git a/old_tests/ut_utils/ut_utils.test_result_to_char.Success.sql b/old_tests/ut_utils/ut_utils.test_result_to_char.Success.sql deleted file mode 100644 index a0ce237f5..000000000 --- a/old_tests/ut_utils/ut_utils.test_result_to_char.Success.sql +++ /dev/null @@ -1,15 +0,0 @@ ---Arrange -declare - l_expected varchar2(20) := ut_utils.gc_success_char; - l_result varchar2(20); -begin ---Act - l_result := ut_utils.test_result_to_char(ut_utils.gc_success); ---Assert - if l_result = l_expected then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('expected: '||l_expected||', got: '||l_result ); - end if; -end; -/ diff --git a/readme.md b/readme.md index 5dbec9166..141c68ffe 100644 --- a/readme.md +++ b/readme.md @@ -1,14 +1,16 @@ -# utPLSQL v3 | Powerful PL/SQL Unit Testing Framework +![utPLSQL v3 | Testing Framework for PL/SQL](docs/images/utPLSQL-testing-framework-transparent_120.png) + +---------- -[![latest-release](https://img.shields.io/github/release/utPLSQL/utPLSQL.svg)](https://github.com/utPLSQL/utPLSQL/releases) [![license](https://img.shields.io/github/license/utPLSQL/utPLSQL.svg)](https://www.apache.org/licenses/LICENSE-2.0) -[![chat](http://img.shields.io/badge/slack-team--chat-blue.svg)](http://utplsql-slack-invite.herokuapp.com/) +[![latest-release](https://img.shields.io/github/release/utPLSQL/utPLSQL.svg)](https://github.com/utPLSQL/utPLSQL/releases) +[![Download statistics](https://img.shields.io/github/downloads/utPLSQL/utPLSQL/total.svg)](http://gra.caldis.me/?url=https://github.com/utPLSQL/utPLSQL) +[![chat](http://img.shields.io/badge/slack-team--chat-blue.svg)](https://join.slack.com/t/utplsql/shared_invite/zt-xwm68udy-4cF_3PNEyczYEbWr38W5ww) [![twitter](https://img.shields.io/twitter/follow/utPLSQL.svg?style=social&label=Follow)](https://twitter.com/utPLSQL) -[![build](https://img.shields.io/travis/utPLSQL/utPLSQL/master.svg?label=master%20branch)](https://travis-ci.org/utPLSQL/utPLSQL) -[![build](https://img.shields.io/travis/utPLSQL/utPLSQL/develop.svg?label=develop%20branch)](https://travis-ci.org/utPLSQL/utPLSQL) -[![sonar](https://sonarcloud.io/api/project_badges/measure?project=utPLSQL&metric=sqale_rating)](https://sonarcloud.io/dashboard/index?id=utPLSQL) -[![Coveralls coverage](https://coveralls.io/repos/github/utPLSQL/utPLSQL/badge.svg?branch=develop)](https://coveralls.io/github/utPLSQL/utPLSQL?branch=develop) +[![build](https://github.com/utPLSQL/utPLSQL/actions/workflows/build.yml/badge.svg)](https://github.com/utPLSQL/utPLSQL/actions/workflows/build.yml) +[![QualityGate](https://sonarcloud.io/api/project_badges/measure?project=utPLSQL&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=utPLSQL) +[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=utPLSQL&metric=coverage)](https://sonarcloud.io/summary/new_code?id=utPLSQL) ---------- utPLSQL version 3 is a complete rewrite of utPLSQL v2 from scratch. @@ -82,7 +84,7 @@ Amongst many benefits it provides ability to: * use many reporting formats simultaneously and save reports to files (publish) * map your project source files and test files into database objects -Just download the [latest client](https://github.com/utPLSQL/utPLSQL-cli/releases/latest), download Oracle jdbc driver you are good to go. +Download the [latest client](https://github.com/utPLSQL/utPLSQL-cli/releases/latest) and are good to go. See [project readme](https://github.com/utPLSQL/utPLSQL-cli/blob/develop/README.md) for details. @@ -160,72 +162,17 @@ We welcome new developers to join our community and contribute to the utPLSQL pr If you are interested in helping please read our [guide to contributing](CONTRIBUTING.md) The best place to start is to read the documentation and get familiar with the existing code base. A [slack chat](https://utplsql.slack.com/) is the place to go if you want to talk with team members. -To sign up to the chat use [this link](http://utplsql-slack-invite.herokuapp.com/) +To sign up to the chat use [this link](https://join.slack.com/t/utplsql/shared_invite/zt-xwm68udy-4cF_3PNEyczYEbWr38W5ww). ---------- [__Authors__](docs/about/authors.md) ----------- -__Version 2 to Version 3 Comparison__ - -If you have a great feature in mind, that you would like to see in utPLSQL v3 please create an [issue on GitHub](https://github.com/utPLSQL/utPLSQL/issues) or discuss it with us in the [Slack chat rooms](http://utplsql-slack-invite.herokuapp.com/). - - -| Feature | Version 2 | Version 3 | -| -------------------------------------- | ---------------------- | ---------------------- | -| Easy to install | Yes | Yes | -| Documentation | Yes | Yes | -| License | GPL v2 | Apache 2.0 | -| **Tests Creation** | | | -| Declarative test configuration | No | Yes - Annotations1| -| Tests as Packages | Yes | Yes | -| Multiple Tests in a single Package | Yes | Yes | -| Optional Setup/Teardown | No | Yes | -| Different Setup/Teardown
For Each Test in a Single Package| No | Yes - Annotations1 | -| Suite Definition Storage | Tables | Package - Annotations1 | -| Multiple Suites | Yes | Yes | -| Suites can contain Suites | No | Yes | -| Automatic Test detection | No | Yes - Annotations1| -| Unconstrained naming of Test packages | No - prefixes | Yes - name not relevant| -| Require Prefix on Test procedures | No - prefixes | Yes - name not relevant| -| Auto Compilation of Tests | Yes | No (Let us know if you use this) | -| Assertion Library | 30 assertions2 | 26 matchers (13 + 13 negated) | -| Extendable assertions | No | Yes - custom matchers | -| PLSQL Record Assertions | generated code through **utRecEq** Package | [possible on Oracle 12c+](https://oracle-base.com/articles/12c/using-the-table-operator-with-locally-defined-types-in-plsql-12cr1) using [cursor matchers](docs/userguide/expectations.md#comparing-cursors)| -| Test Skeleton Generation | Yes | No (Let us know if you use this) | -| **Test Execution3** | | | -| Single Test Package Execution | Yes | Yes | -| Single Test Procedure Execution | No | Yes | -| Test Suite Execution | Yes | Yes | -| Subset of Suite Execution | No | Yes | -| Multiple Suite Execution | No | Yes | -| Organizing Suites into hierarchies | No | Yes | -| **Code Coverage Reporting** | No | Yes | -| Html Coverage Report | No | Yes | -| Sonar XML Coverage Report | No | Yes | -| Coveralls Json Coverage Report | No | Yes | -| Framework Transaction Control | No | Yes - Annotations1 | -| **Test Output** | | | -| Real-time test execution progress reporting | No | Yes | -| Multiple Output Reporters can be used during test execution | No| Yes | -| DBMS_OUTPUT | Yes | Yes (clean formatting) | -| File | Yes (to db server only)| Yes (on client side) | -| Stored in Table | Yes | No (can be added as custom reporter) | -| XUnit format support | No | Yes | -| HTML Format | Yes | No | -| Custom Output reporter | Yes-needs configuration| Yes - no config needed | - -1 Annotations are specially formatted comments in your package specification. This enables *declarative* test configuration that is coupled with the source code. See Documentation for more details. - -2 **utAssert2** package - Contains 59 Assertions - 2 Not implemented = 57, 28 are duplicated only change on outcome_in parameter 57-28 = 29, **utPipe** package - Contains 1 Assertion 29 + 1 = 30 - -3 Test execution comparison is in a single call so the results are combined. We know it was always possible to group in any way with multiple calls. But that may not be desired under a CI system where you want a single JUnit XML Output. - ---------- __Project Directories__ +* .github - contains files needed for github Actions integration * .travis - contains files needed for travis-ci integration * client_source - Sources to be used on the client-side. Developer workstation or CI platform to run the tests. * development - Set of useful scripts and utilities for development and debugging of utPLSQL @@ -233,3 +180,26 @@ __Project Directories__ * examples - Example source code and unit tests * source - The installation code for utPLSQL * tests - Tests for utPLSQL framework + +---------- + +If you have a great feature in mind, that you would like to see in utPLSQL v3 please create an [issue on GitHub](https://github.com/utPLSQL/utPLSQL/issues) or discuss it with us in the [slack chat rooms](https://utplsql.slack.com/). Use [invite link](https://join.slack.com/t/utplsql/shared_invite/zt-xwm68udy-4cF_3PNEyczYEbWr38W5ww) to join the chat. + + +# Version 2 to Version 3 Comparison + +[Version 2 to Version 3 Comparison](docs/compare_version2_to_3.md) + +# Supporters + +The utPLSQL project is community-driven and is not commercially motivated. Nonetheless, donations and other contributions are always welcome, and are detailed below. + + + + + + + + +
supported_by_redgateutPLSQL has been supported by Redgate in the form of sponsored stickers and t-shirts. Thank you for helping us spreading the word!
+ diff --git a/sonar-project.properties b/sonar-project.properties index a1fabbede..d088e9ccb 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,15 +1,17 @@ # must be unique in a given SonarQube instance +sonar.organization=utplsql sonar.projectKey=utPLSQL # this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1. sonar.projectName=utPLSQL -sonar.projectVersion=v3.1.3-develop +sonar.projectVersion=v3.1.14-develop # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. # Since SonarQube 4.2, this property is optional if sonar.modules is set. # 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.coverage.exclusions=**/*.sql,**/*.pks sonar.tests=./test sonar.testExecutionReportPaths=./test_results.xml sonar.links.issue=https://github.com/utPLSQL/utPLSQL/issues @@ -19,9 +21,18 @@ sonar.projectDescription=PL/SQL Unit Testing Framework sonar.plsql.file.suffixes=sql,tab,pkb,tpb sonar.language=plsql + +sonar.exclusions=**/*.sql + sonar.pullrequest.provider=github sonar.pullrequest.github.endpoint=https://api.github.com/ sonar.pullrequest.github.repository=utPLSQL/utPLSQL +sonar.plsql.jdbc.driver.class=oracle.jdbc.OracleDriver +sonar.plsql.jdbc.user=UT3_DEVELOP +sonar.plsql.jdbc.password=ut3 +sonar.plsql.defaultSchema=UT3_DEVELOP + + # Encoding of the source code. Default is default system encoding #sonar.sourceEncoding=UTF-8 diff --git a/source/api/be_within.syn b/source/api/be_within.syn new file mode 100644 index 000000000..e00005bb7 --- /dev/null +++ b/source/api/be_within.syn @@ -0,0 +1 @@ +create synonym be_within for ut_be_within; diff --git a/source/api/be_within_pct.syn b/source/api/be_within_pct.syn new file mode 100644 index 000000000..40e3fb8b9 --- /dev/null +++ b/source/api/be_within_pct.syn @@ -0,0 +1 @@ +create synonym be_within_pct for ut_be_within_pct; diff --git a/source/api/contain.syn b/source/api/contain.syn new file mode 100644 index 000000000..5bce7d1d2 --- /dev/null +++ b/source/api/contain.syn @@ -0,0 +1 @@ +create synonym contain for ut_contain; diff --git a/source/api/ut.pkb b/source/api/ut.pkb index bd241ce13..cff35b771 100644 --- a/source/api/ut.pkb +++ b/source/api/ut.pkb @@ -2,7 +2,7 @@ create or replace package body ut is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -18,6 +18,10 @@ create or replace package body ut is */ g_nls_date_format varchar2(4000); + gc_fail_on_errors constant boolean := false; + + g_result_line_no binary_integer; + g_result_lines ut_varchar2_list := ut_varchar2_list(); function version return varchar2 is begin @@ -26,7 +30,7 @@ create or replace package body ut is function expect(a_actual in anydata, a_message varchar2 := null) return ut_expectation_compound is begin - return ut_expectation_compound(ut_data_value_anydata.get_instance(a_actual), a_message); + return ut_expectation_compound(ut_data_value_anydata(a_actual), a_message); end; function expect(a_actual in blob, a_message varchar2 := null) return ut_expectation is @@ -89,6 +93,16 @@ create or replace package body ut is return ut_expectation(ut_data_value_dsinterval(a_actual), a_message); end; + function expect(a_actual in json_element_t , a_message varchar2 := null) return ut_expectation_json is + begin + return ut_expectation_json(ut_data_value_json(a_actual), a_message); + end; + + function expect(a_actual in json , a_message varchar2 := null) return ut_expectation_json is + begin + return ut_expectation_json(ut_data_value_json(a_actual), a_message); + end; + procedure fail(a_message in varchar2) is begin ut_expectation_processor.report_failure(a_message); @@ -109,15 +123,21 @@ create or replace package body ut is a_paths ut_varchar2_list, a_reporter in out nocopy ut_reporter_base, a_color_console integer, - a_coverage_schemes ut_varchar2_list := null, + a_coverage_schemes ut_varchar2_list, a_source_file_mappings ut_file_mappings, a_test_file_mappings ut_file_mappings, a_include_objects ut_varchar2_list, a_exclude_objects ut_varchar2_list, - a_client_character_set varchar2 := null + a_client_character_set varchar2, + a_random_test_order integer, + a_random_test_order_seed positive, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ) is pragma autonomous_transaction; - c_fail_on_errors constant boolean := false; begin a_reporter := coalesce(a_reporter,ut_documentation_reporter()); ut_runner.run( @@ -129,8 +149,16 @@ create or replace package body ut is a_test_file_mappings, a_include_objects, a_exclude_objects, - c_fail_on_errors, - a_client_character_set + gc_fail_on_errors, + a_client_character_set, + false, + ut_utils.int_to_boolean(a_random_test_order), + a_random_test_order_seed, + a_tags, + a_include_schema_expr, + a_include_object_expr, + a_exclude_schema_expr, + a_exclude_object_expr ); rollback; end; @@ -139,16 +167,23 @@ create or replace package body ut is a_paths ut_varchar2_list, a_reporter in out nocopy ut_reporter_base, a_color_console integer, - a_coverage_schemes ut_varchar2_list := null, + a_coverage_schemes ut_varchar2_list, a_source_files ut_varchar2_list, a_test_files ut_varchar2_list, a_include_objects ut_varchar2_list, a_exclude_objects ut_varchar2_list, - a_client_character_set varchar2 := null + a_client_character_set varchar2, + a_random_test_order integer, + a_random_test_order_seed positive, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ) is pragma autonomous_transaction; - c_fail_on_errors constant boolean := false; begin + a_reporter := coalesce(a_reporter,ut_documentation_reporter()); ut_runner.run( a_paths, @@ -159,12 +194,50 @@ create or replace package body ut is ut_file_mapper.build_file_mappings(a_test_files), a_include_objects, a_exclude_objects, - c_fail_on_errors, - a_client_character_set + gc_fail_on_errors, + a_client_character_set, + false, + ut_utils.int_to_boolean(a_random_test_order), + a_random_test_order_seed, + a_tags, + a_include_schema_expr, + a_include_object_expr, + a_exclude_schema_expr, + a_exclude_object_expr ); rollback; end; + function get_report_outputs( a_cursor sys_refcursor ) return varchar2 is + l_clob clob; + l_item_type varchar2(32767); + l_result varchar2(4000); + begin + if g_result_line_no is null then + fetch a_cursor into l_clob, l_item_type; + if a_cursor%notfound then + close a_cursor; + g_result_line_no := null; + g_result_lines := ut_varchar2_list(); + raise_if_packages_invalidated(); + raise no_data_found; + end if; + if l_clob is not null and l_clob != empty_clob() then + if length(l_clob) > ut_utils.gc_max_storage_varchar2_len then + g_result_lines := ut_utils.clob_to_table(l_clob, ut_utils.gc_max_storage_varchar2_len); + else + g_result_lines := ut_varchar2_list(l_clob); + end if; + g_result_line_no := g_result_lines.first; + end if; + end if; + if g_result_line_no is not null then + l_result := g_result_lines(g_result_line_no); + g_result_line_no := g_result_lines.next(g_result_line_no); + end if; + return l_result; + end; + function run( a_reporter ut_reporter_base := null, a_color_console integer := 0, @@ -173,11 +246,17 @@ create or replace package body ut is a_test_file_mappings ut_file_mappings := null, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_random_test_order integer := 0, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ) return ut_varchar2_rows pipelined is l_reporter ut_reporter_base := a_reporter; - l_lines sys_refcursor; - l_line varchar2(4000); + l_results sys_refcursor; begin run_autonomous( ut_varchar2_list(), @@ -188,18 +267,22 @@ create or replace package body ut is a_test_file_mappings, a_include_objects, a_exclude_objects, - a_client_character_set + a_client_character_set, + a_random_test_order, + a_random_test_order_seed, + a_tags, + a_include_schema_expr, + a_include_object_expr, + a_exclude_schema_expr, + a_exclude_object_expr ); if l_reporter is of (ut_output_reporter_base) then - l_lines := treat(l_reporter as ut_output_reporter_base).get_lines_cursor(); + l_results := treat(l_reporter as ut_output_reporter_base).get_lines_cursor(); + g_result_lines := ut_varchar2_list(); loop - fetch l_lines into l_line; - exit when l_lines%notfound; - pipe row(l_line); + pipe row( get_report_outputs( l_results ) ); end loop; - close l_lines; end if; - raise_if_packages_invalidated(); return; end; @@ -211,11 +294,17 @@ create or replace package body ut is a_test_files ut_varchar2_list, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_random_test_order integer := 0, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ) return ut_varchar2_rows pipelined is l_reporter ut_reporter_base := a_reporter; - l_lines sys_refcursor; - l_line varchar2(4000); + l_results sys_refcursor; begin run_autonomous( ut_varchar2_list(), @@ -226,18 +315,22 @@ create or replace package body ut is a_test_files, a_include_objects, a_exclude_objects, - a_client_character_set + a_client_character_set, + a_random_test_order, + a_random_test_order_seed, + a_tags, + a_include_schema_expr, + a_include_object_expr, + a_exclude_schema_expr, + a_exclude_object_expr ); if l_reporter is of (ut_output_reporter_base) then - l_lines := treat(l_reporter as ut_output_reporter_base).get_lines_cursor(); + l_results := treat(l_reporter as ut_output_reporter_base).get_lines_cursor(); + g_result_lines := ut_varchar2_list(); loop - fetch l_lines into l_line; - exit when l_lines%notfound; - pipe row(l_line); + pipe row( get_report_outputs( l_results ) ); end loop; - close l_lines; end if; - raise_if_packages_invalidated(); return; end; @@ -250,11 +343,17 @@ create or replace package body ut is a_test_file_mappings ut_file_mappings := null, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_random_test_order integer := 0, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ) return ut_varchar2_rows pipelined is l_reporter ut_reporter_base := a_reporter; - l_lines sys_refcursor; - l_line varchar2(4000); + l_results sys_refcursor; begin run_autonomous( a_paths, @@ -265,18 +364,22 @@ create or replace package body ut is a_test_file_mappings, a_include_objects, a_exclude_objects, - a_client_character_set + a_client_character_set, + a_random_test_order, + a_random_test_order_seed, + a_tags, + a_include_schema_expr, + a_include_object_expr, + a_exclude_schema_expr, + a_exclude_object_expr ); if l_reporter is of (ut_output_reporter_base) then - l_lines := treat(l_reporter as ut_output_reporter_base).get_lines_cursor(); + l_results := treat(l_reporter as ut_output_reporter_base).get_lines_cursor(); + g_result_lines := ut_varchar2_list(); loop - fetch l_lines into l_line; - exit when l_lines%notfound; - pipe row(l_line); + pipe row( get_report_outputs( l_results ) ); end loop; - close l_lines; end if; - raise_if_packages_invalidated(); return; end; @@ -289,11 +392,17 @@ create or replace package body ut is a_test_files ut_varchar2_list, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_random_test_order integer := 0, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ) return ut_varchar2_rows pipelined is l_reporter ut_reporter_base := a_reporter; - l_lines sys_refcursor; - l_line varchar2(4000); + l_results sys_refcursor; begin run_autonomous( a_paths, @@ -304,18 +413,22 @@ create or replace package body ut is a_test_files, a_include_objects, a_exclude_objects, - a_client_character_set + a_client_character_set, + a_random_test_order, + a_random_test_order_seed, + a_tags, + a_include_schema_expr, + a_include_object_expr, + a_exclude_schema_expr, + a_exclude_object_expr ); if l_reporter is of (ut_output_reporter_base) then - l_lines := treat(l_reporter as ut_output_reporter_base).get_lines_cursor(); + l_results := treat(l_reporter as ut_output_reporter_base).get_lines_cursor(); + g_result_lines := ut_varchar2_list(); loop - fetch l_lines into l_line; - exit when l_lines%notfound; - pipe row(l_line); + pipe row( get_report_outputs( l_results ) ); end loop; - close l_lines; end if; - raise_if_packages_invalidated(); return; end; @@ -328,11 +441,17 @@ create or replace package body ut is a_test_file_mappings ut_file_mappings := null, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_random_test_order integer := 0, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ) return ut_varchar2_rows pipelined is - l_reporter ut_reporter_base := a_reporter; - l_lines sys_refcursor; - l_line varchar2(4000); + l_reporter ut_reporter_base := a_reporter; + l_results sys_refcursor; begin run_autonomous( ut_varchar2_list(a_path), @@ -343,18 +462,22 @@ create or replace package body ut is a_test_file_mappings, a_include_objects, a_exclude_objects, - a_client_character_set + a_client_character_set, + a_random_test_order, + a_random_test_order_seed, + a_tags, + a_include_schema_expr, + a_include_object_expr, + a_exclude_schema_expr, + a_exclude_object_expr ); if l_reporter is of (ut_output_reporter_base) then - l_lines := treat(l_reporter as ut_output_reporter_base).get_lines_cursor(); + l_results := treat(l_reporter as ut_output_reporter_base).get_lines_cursor(); + g_result_lines := ut_varchar2_list(); loop - fetch l_lines into l_line; - exit when l_lines%notfound; - pipe row(l_line); + pipe row( get_report_outputs( l_results ) ); end loop; - close l_lines; end if; - raise_if_packages_invalidated(); return; end; @@ -367,11 +490,17 @@ create or replace package body ut is a_test_files ut_varchar2_list, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_random_test_order integer := 0, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ) return ut_varchar2_rows pipelined is l_reporter ut_reporter_base := a_reporter; - l_lines sys_refcursor; - l_line varchar2(4000); + l_results sys_refcursor; begin run_autonomous( ut_varchar2_list(a_path), @@ -382,18 +511,22 @@ create or replace package body ut is a_test_files, a_include_objects, a_exclude_objects, - a_client_character_set + a_client_character_set, + a_random_test_order, + a_random_test_order_seed, + a_tags, + a_include_schema_expr, + a_include_object_expr, + a_exclude_schema_expr, + a_exclude_object_expr ); if l_reporter is of (ut_output_reporter_base) then - l_lines := treat(l_reporter as ut_output_reporter_base).get_lines_cursor(); + l_results := treat(l_reporter as ut_output_reporter_base).get_lines_cursor(); + g_result_lines := ut_varchar2_list(); loop - fetch l_lines into l_line; - exit when l_lines%notfound; - pipe row(l_line); + pipe row( get_report_outputs( l_results ) ); end loop; - close l_lines; end if; - raise_if_packages_invalidated(); return; end; @@ -406,21 +539,60 @@ create or replace package body ut is a_test_file_mappings ut_file_mappings := null, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_force_manual_rollback boolean := false, + a_random_test_order boolean := false, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ) is l_reporter ut_reporter_base := a_reporter; begin - run_autonomous( - a_paths, - l_reporter, - ut_utils.boolean_to_int(a_color_console), - a_coverage_schemes, - a_source_file_mappings, - a_test_file_mappings, - a_include_objects, - a_exclude_objects, - a_client_character_set - ); + if a_force_manual_rollback then + l_reporter := coalesce(l_reporter,ut_documentation_reporter()); + ut_runner.run( + a_paths, + ut_reporters(l_reporter), + a_color_console, + a_coverage_schemes, + a_source_file_mappings, + a_test_file_mappings, + a_include_objects, + a_exclude_objects, + gc_fail_on_errors, + a_client_character_set, + a_force_manual_rollback, + a_random_test_order, + a_random_test_order_seed, + a_tags, + a_include_schema_expr, + a_include_object_expr, + a_exclude_schema_expr, + a_exclude_object_expr + ); + else + run_autonomous( + a_paths, + l_reporter, + ut_utils.boolean_to_int(a_color_console), + a_coverage_schemes, + a_source_file_mappings, + a_test_file_mappings, + a_include_objects, + a_exclude_objects, + a_client_character_set, + ut_utils.boolean_to_int(a_random_test_order), + a_random_test_order_seed, + a_tags, + a_include_schema_expr, + a_include_object_expr, + a_exclude_schema_expr, + a_exclude_object_expr + ); + end if; if l_reporter is of (ut_output_reporter_base) then treat(l_reporter as ut_output_reporter_base).lines_to_dbms_output(); end if; @@ -436,25 +608,37 @@ create or replace package body ut is a_test_files ut_varchar2_list, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_force_manual_rollback boolean := false, + a_random_test_order boolean := false, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ) is l_reporter ut_reporter_base := a_reporter; begin - run_autonomous( + ut.run( a_paths, l_reporter, - ut_utils.boolean_to_int(a_color_console), + a_color_console, a_coverage_schemes, - a_source_files, - a_test_files, + ut_file_mapper.build_file_mappings(a_source_files), + ut_file_mapper.build_file_mappings(a_test_files), a_include_objects, a_exclude_objects, - a_client_character_set + a_client_character_set, + a_force_manual_rollback, + a_random_test_order, + a_random_test_order_seed, + a_tags, + a_include_schema_expr, + a_include_object_expr, + a_exclude_schema_expr, + a_exclude_object_expr ); - if l_reporter is of (ut_output_reporter_base) then - treat(l_reporter as ut_output_reporter_base).lines_to_dbms_output(); - end if; - raise_if_packages_invalidated(); end; procedure run( @@ -465,7 +649,15 @@ create or replace package body ut is a_test_file_mappings ut_file_mappings := null, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_force_manual_rollback boolean := false, + a_random_test_order boolean := false, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ) is begin ut.run( @@ -477,7 +669,15 @@ create or replace package body ut is a_test_file_mappings, a_include_objects, a_exclude_objects, - a_client_character_set + a_client_character_set, + a_force_manual_rollback, + a_random_test_order, + a_random_test_order_seed, + a_tags, + a_include_schema_expr, + a_include_object_expr, + a_exclude_schema_expr, + a_exclude_object_expr ); end; @@ -489,7 +689,15 @@ create or replace package body ut is a_test_files ut_varchar2_list, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_force_manual_rollback boolean := false, + a_random_test_order boolean := false, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ) is begin ut.run( @@ -501,7 +709,15 @@ create or replace package body ut is a_test_files, a_include_objects, a_exclude_objects, - a_client_character_set + a_client_character_set, + a_force_manual_rollback, + a_random_test_order, + a_random_test_order_seed, + a_tags, + a_include_schema_expr, + a_include_object_expr, + a_exclude_schema_expr, + a_exclude_object_expr ); end; @@ -514,7 +730,15 @@ create or replace package body ut is a_test_file_mappings ut_file_mappings := null, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_force_manual_rollback boolean := false, + a_random_test_order boolean := false, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ) is begin ut.run( @@ -526,7 +750,15 @@ create or replace package body ut is a_test_file_mappings, a_include_objects, a_exclude_objects, - a_client_character_set + a_client_character_set, + a_force_manual_rollback, + a_random_test_order, + a_random_test_order_seed, + a_tags, + a_include_schema_expr, + a_include_object_expr, + a_exclude_schema_expr, + a_exclude_object_expr ); end; @@ -539,7 +771,15 @@ create or replace package body ut is a_test_files ut_varchar2_list, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_force_manual_rollback boolean := false, + a_random_test_order boolean := false, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ) is begin ut.run( @@ -551,14 +791,23 @@ create or replace package body ut is a_test_files, a_include_objects, a_exclude_objects, - a_client_character_set + a_client_character_set, + a_force_manual_rollback, + a_random_test_order, + a_random_test_order_seed, + a_tags, + a_include_schema_expr, + a_include_object_expr, + a_exclude_schema_expr, + a_exclude_object_expr ); end; + procedure set_nls is begin if g_nls_date_format is null then - select nsp.value + select /*+ no_parallel */ nsp.value into g_nls_date_format from nls_session_parameters nsp where parameter = 'NLS_DATE_FORMAT'; diff --git a/source/api/ut.pks b/source/api/ut.pks index 59c709a33..f72c82a0c 100644 --- a/source/api/ut.pks +++ b/source/api/ut.pks @@ -2,7 +2,7 @@ create or replace package ut authid current_user as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -45,6 +45,10 @@ create or replace package ut authid current_user as function expect(a_actual in dsinterval_unconstrained, a_message varchar2 := null) return ut_expectation; + function expect(a_actual in json_element_t , a_message varchar2 := null) return ut_expectation_json; + + function expect(a_actual in json , a_message varchar2 := null) return ut_expectation_json; + procedure fail(a_message in varchar2); function run( @@ -55,7 +59,14 @@ create or replace package ut authid current_user as a_test_file_mappings ut_file_mappings := null, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_random_test_order integer := 0, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ) return ut_varchar2_rows pipelined; function run( @@ -66,7 +77,14 @@ create or replace package ut authid current_user as a_test_files ut_varchar2_list, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_random_test_order integer := 0, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ) return ut_varchar2_rows pipelined; function run( @@ -78,7 +96,14 @@ create or replace package ut authid current_user as a_test_file_mappings ut_file_mappings := null, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_random_test_order integer := 0, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ) return ut_varchar2_rows pipelined; function run( @@ -90,7 +115,14 @@ create or replace package ut authid current_user as a_test_files ut_varchar2_list, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_random_test_order integer := 0, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ) return ut_varchar2_rows pipelined; function run( @@ -102,7 +134,14 @@ create or replace package ut authid current_user as a_test_file_mappings ut_file_mappings := null, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_random_test_order integer := 0, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ) return ut_varchar2_rows pipelined; function run( @@ -114,7 +153,14 @@ create or replace package ut authid current_user as a_test_files ut_varchar2_list, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_random_test_order integer := 0, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ) return ut_varchar2_rows pipelined; procedure run( @@ -125,7 +171,15 @@ create or replace package ut authid current_user as a_test_file_mappings ut_file_mappings := null, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_force_manual_rollback boolean := false, + a_random_test_order boolean := false, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ); procedure run( @@ -136,7 +190,15 @@ create or replace package ut authid current_user as a_test_files ut_varchar2_list, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_force_manual_rollback boolean := false, + a_random_test_order boolean := false, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ); procedure run( @@ -148,7 +210,15 @@ create or replace package ut authid current_user as a_test_file_mappings ut_file_mappings := null, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_force_manual_rollback boolean := false, + a_random_test_order boolean := false, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ); procedure run( @@ -160,7 +230,15 @@ create or replace package ut authid current_user as a_test_files ut_varchar2_list, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_force_manual_rollback boolean := false, + a_random_test_order boolean := false, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ); procedure run( @@ -172,7 +250,15 @@ create or replace package ut authid current_user as a_test_file_mappings ut_file_mappings := null, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_force_manual_rollback boolean := false, + a_random_test_order boolean := false, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ); procedure run( @@ -184,7 +270,15 @@ create or replace package ut authid current_user as a_test_files ut_varchar2_list, a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_force_manual_rollback boolean := false, + a_random_test_order boolean := false, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ); /** diff --git a/source/api/ut_runner.pkb b/source/api/ut_runner.pkb index c04fa5112..3ec2a5393 100644 --- a/source/api/ut_runner.pkb +++ b/source/api/ut_runner.pkb @@ -2,7 +2,7 @@ create or replace package body ut_runner is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -20,35 +20,17 @@ create or replace package body ut_runner is /** * Private functions */ - function to_ut_object_list(a_names ut_varchar2_list, a_schema_names ut_varchar2_rows) return ut_object_names is - l_result ut_object_names; - l_object_name ut_object_name; - begin - if a_names is not empty then - l_result := ut_object_names(); - for i in 1 .. a_names.count loop - l_object_name := ut_object_name(a_names(i)); - if l_object_name.owner is null then - for i in 1 .. cardinality(a_schema_names) loop - l_result.extend; - l_result(l_result.last) := ut_object_name(a_schema_names(i)||'.'||l_object_name.name); - end loop; - else - l_result.extend; - l_result(l_result.last) := l_object_name; - end if; - end loop; - end if; - return l_result; - end; - procedure finish_run(a_run ut_run) is + procedure finish_run(a_run ut_run, a_force_manual_rollback boolean) is begin - ut_utils.cleanup_temp_tables; - ut_event_manager.trigger_event(ut_utils.gc_finalize, a_run); + ut_event_manager.trigger_event(ut_event_manager.gc_finalize, a_run); ut_metadata.reset_source_definition_cache; ut_utils.read_cache_to_dbms_output(); ut_coverage_helper.cleanup_tmp_table(); + ut_compound_data_helper.cleanup_diff(); + if not a_force_manual_rollback then + rollback; + end if; end; @@ -83,21 +65,44 @@ create or replace package body ut_runner is a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, a_fail_on_errors boolean := false, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_force_manual_rollback boolean := false, + a_random_test_order boolean := false, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ) is - l_run ut_run; - l_coverage_schema_names ut_varchar2_rows; - l_exclude_object_names ut_object_names := ut_object_names(); - l_include_object_names ut_object_names; - l_paths ut_varchar2_list := ut_varchar2_list(); + l_run ut_run; + l_coverage_schema_names ut_varchar2_rows; + l_paths ut_varchar2_list; + l_random_test_order_seed positive; begin ut_event_manager.initialize(); - if a_paths is null or a_paths is empty or a_paths.count = 1 and a_paths(1) is null then - l_paths := ut_varchar2_list(sys_context('userenv', 'current_schema')); - else - for i in 1..a_paths.COUNT loop - l_paths := l_paths multiset union ut_utils.string_to_table(a_string => a_paths(i),a_delimiter => ','); + if a_reporters is not empty then + for i in 1 .. a_reporters.count loop + ut_event_manager.add_listener( a_reporters(i) ); end loop; + else + ut_event_manager.add_listener( ut_documentation_reporter() ); + end if; + ut_event_manager.add_listener( ut_session_info() ); + + ut_event_manager.trigger_event(ut_event_manager.gc_initialize); + ut_event_manager.trigger_event(ut_event_manager.gc_debug, ut_run_info()); + + if a_random_test_order_seed is not null then + l_random_test_order_seed := a_random_test_order_seed; + elsif a_random_test_order then + dbms_random.seed( to_char(systimestamp,'yyyyddmmhh24missffff') ); + l_random_test_order_seed := trunc(dbms_random.value(1, 1000000000)); + end if; + + l_paths := ut_utils.filter_list(ut_utils.string_table_to_table(a_paths,','), '.+'); + if l_paths is null or l_paths is empty then + l_paths := ut_varchar2_list(sys_context('userenv', 'current_schema')); end if; begin @@ -105,13 +110,6 @@ create or replace package body ut_runner is ut_utils.save_dbms_output_to_cache(); ut_console_reporter_base.set_color_enabled(a_color_console); - if a_reporters is null or a_reporters.count = 0 then - ut_event_manager.add_listener(ut_documentation_reporter()); - else - for i in 1 .. a_reporters.count loop - ut_event_manager.add_listener(a_reporters(i)); - end loop; - end if; if a_coverage_schemes is not empty then l_coverage_schema_names := ut_utils.convert_collection(a_coverage_schemes); @@ -119,34 +117,37 @@ create or replace package body ut_runner is l_coverage_schema_names := ut_suite_manager.get_schema_names(l_paths); end if; - if a_exclude_objects is not empty then - l_exclude_object_names := to_ut_object_list(a_exclude_objects, l_coverage_schema_names); - end if; - - l_exclude_object_names := l_exclude_object_names multiset union all ut_suite_manager.get_schema_ut_packages(l_coverage_schema_names); - - 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), - l_paths, - l_coverage_schema_names, - l_exclude_object_names, - l_include_object_names, - set(a_source_file_mappings), - set(a_test_file_mappings), - a_client_character_set + a_run_paths => l_paths, + a_coverage_options => ut_coverage_options( + coverage_run_id => ut_coverage.get_coverage_run_id(), + schema_names => l_coverage_schema_names, + exclude_objects => ut_utils.convert_collection(a_exclude_objects), + include_objects => ut_utils.convert_collection(a_include_objects), + file_mappings => set(a_source_file_mappings), + include_schema_expr => a_include_schema_expr, + include_object_expr => a_include_object_expr, + exclude_schema_expr => a_exclude_schema_expr, + exclude_object_expr => a_exclude_object_expr + ), + a_test_file_mappings => set(a_test_file_mappings), + a_client_character_set => a_client_character_set, + a_random_test_order_seed => l_random_test_order_seed, + a_run_tags => a_tags ); - l_run.do_execute(); - finish_run(l_run); - rollback; + ut_suite_manager.configure_execution_by_path(l_paths, l_run.items, l_random_test_order_seed, a_tags); + if a_force_manual_rollback then + l_run.set_rollback_type( a_rollback_type => ut_utils.gc_rollback_manual, a_force => true ); + end if; + + l_run.do_execute(); + finish_run(l_run, a_force_manual_rollback); exception when others then - finish_run(l_run); + finish_run(l_run, a_force_manual_rollback); dbms_output.put_line(dbms_utility.format_error_backtrace); dbms_output.put_line(dbms_utility.format_error_stack); - rollback; raise; end; if a_fail_on_errors and l_run.result in (ut_utils.gc_failure, ut_utils.gc_error) then @@ -164,21 +165,14 @@ 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, a_package_name varchar2) 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; - c_bulk_limit constant integer := 10; + l_results ut_suite_items_info; + c_bulk_limit constant integer := 100; + l_path varchar2(4000) := nvl(a_owner,sys_context('userenv', 'current_schema'))||'.'||nvl(a_package_name,'*'); 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(ut_varchar2_list(l_path)); loop fetch l_cursor bulk collect into l_results limit c_bulk_limit; for i in 1 .. l_results.count loop @@ -190,33 +184,88 @@ create or replace package body ut_runner is return; end; - function get_reporters_list return tt_reporters_info pipelined is - l_cursor sys_refcursor; - l_owner varchar2(128) := upper(ut_utils.ut_owner()); - l_results tt_reporters_info; - c_bulk_limit constant integer := 10; - l_view_name varchar2(200) := ut_metadata.get_dba_view('dba_types'); + function get_suites_info(a_path varchar2 := null) return ut_suite_items_info pipelined is + l_cursor sys_refcursor; + l_results ut_suite_items_info; + c_bulk_limit constant integer := 100; + i pls_integer; begin - open l_cursor for q'[ - SELECT - owner || '.' || type_name, - CASE - WHEN sys_connect_by_path(owner||'.'||type_name,',') LIKE '%]' || l_owner || q'[.UT_OUTPUT_REPORTER_BASE%' - THEN 'Y' - ELSE 'N' - END is_output_reporter - FROM ]'||l_view_name||q'[ t - WHERE instantiable = 'YES' - CONNECT BY supertype_name = PRIOR type_name AND supertype_owner = PRIOR owner - START WITH type_name = 'UT_REPORTER_BASE' AND owner = ']'|| l_owner || ''''; + l_cursor := ut_suite_manager.get_suites_info(ut_varchar2_list(nvl(a_path,sys_context('userenv', 'current_schema')))); loop fetch l_cursor bulk collect into l_results limit c_bulk_limit; - for i in 1 .. l_results.count loop + i := l_results.first; + while (i is not null) loop pipe row (l_results(i)); + i := l_results.next(i); end loop; exit when l_cursor%notfound; end loop; close l_cursor; + 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_owner varchar2(128) := upper(ut_utils.ut_owner()); + l_reporters ut_reporters_info; + l_result t_reporter_rec; + begin + loop + l_reporters := ut_utils.get_child_reporters( l_reporters ); + exit when l_reporters is null or l_reporters.count = 0; + for i in 1 .. l_reporters.count loop + if l_reporters(i).is_instantiable = 'Y' then + l_result.reporter_object_name := l_owner||'.'||l_reporters(i).object_name; + l_result.is_output_reporter := l_reporters(i).is_output_reporter; + pipe row( l_result ); + end if; + end loop; + end loop; + end; + + procedure coverage_start(a_coverage_run_id raw) is + begin + ut_coverage.coverage_start(a_coverage_run_id); + end; + + procedure coverage_stop is + begin + ut_coverage.coverage_stop; end; end ut_runner; diff --git a/source/api/ut_runner.pks b/source/api/ut_runner.pks index 45b8cb642..85eff1c93 100644 --- a/source/api/ut_runner.pks +++ b/source/api/ut_runner.pks @@ -2,7 +2,7 @@ create or replace package ut_runner authid current_user is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -43,6 +43,8 @@ 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 + * @param a_force_manual_rollback true/false - should the transaction control be forced to --%rollback(manual) and no rollback issued at the end of the run * * @example * Parameter `a_paths` accepts values of the following formats: @@ -65,7 +67,15 @@ create or replace package ut_runner authid current_user is a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, a_fail_on_errors boolean := false, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_force_manual_rollback boolean := false, + a_random_test_order boolean := false, + a_random_test_order_seed positive := null, + a_tags varchar2 := null, + a_include_schema_expr varchar2 := null, + a_include_object_expr varchar2 := null, + a_exclude_schema_expr varchar2 := null, + a_exclude_object_expr varchar2 := null ); /** @@ -87,28 +97,51 @@ 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, a_package_name varchar2) return ut_suite_items_info pipelined; + + /** + * Returns a pipelined collection containing information about unit test suites and the tests contained in them + * + * @param a_path a path from which we lookg for object or suite + */ + function get_suites_info(a_path varchar2 := null) return ut_suite_items_info pipelined; + + + /** + * 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 a pipelined collection containing information about unit tests package/packages for a given owner + * 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), - is_output_reporter varchar2(1) --Y/N flag + reporter_object_name varchar2(250), -- full reporter name in format: owner.name + is_output_reporter varchar2(1) -- Y/N indication of reporter providing output for API ); type tt_reporters_info is table of t_reporter_rec ; @@ -118,5 +151,9 @@ create or replace package ut_runner authid current_user is */ function get_reporters_list return tt_reporters_info pipelined; + procedure coverage_start(a_coverage_run_id raw); + + procedure coverage_stop; + end ut_runner; / diff --git a/source/api/ut_suite_item_info.tpb b/source/api/ut_suite_item_info.tpb new file mode 100644 index 000000000..3315f7a16 --- /dev/null +++ b/source/api/ut_suite_item_info.tpb @@ -0,0 +1,42 @@ +create or replace type body ut_suite_item_info is + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + constructor function ut_suite_item_info(a_object_owner varchar2, a_object_name varchar2, a_item_name varchar2, + a_item_description varchar2, a_item_type varchar2, a_item_line_no integer, a_path varchar2, a_disabled_flag integer, + a_disabled_reason varchar2, a_tags ut_varchar2_rows) return self as result is + begin + self.object_owner := a_object_owner; + self.object_name := a_object_name; + self.item_name := a_item_name; + self.item_description := a_item_description; + self.item_type := a_item_type; + self.item_line_no := a_item_line_no; + self.path := a_path; + self.disabled_flag := a_disabled_flag; + self.disabled_reason := case when + a_disabled_flag = 1 then a_disabled_reason + else null + end; + self.tags := case + when a_tags is null then null + when a_tags.count = 0 then null + else ut_utils.to_string(ut_utils.table_to_clob(a_tags,',') ,a_quote_char => null) + end; + return; + end; +end; +/ diff --git a/source/api/ut_suite_item_info.tps b/source/api/ut_suite_item_info.tps new file mode 100644 index 000000000..2c92f261d --- /dev/null +++ b/source/api/ut_suite_item_info.tps @@ -0,0 +1,32 @@ +create or replace type ut_suite_item_info as object ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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( 4000 ), -- 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 + disabled_reason varchar2(4000), -- if disable flag is set then you can pass reason + tags varchar2(4000), + constructor function ut_suite_item_info(a_object_owner varchar2, a_object_name varchar2, a_item_name varchar2, + a_item_description varchar2, a_item_type varchar2, a_item_line_no integer, a_path varchar2, a_disabled_flag integer, + a_disabled_reason varchar2, a_tags ut_varchar2_rows) return self as result +) +/ diff --git a/source/api/ut_suite_items_info.tps b/source/api/ut_suite_items_info.tps new file mode 100644 index 000000000..208098f9d --- /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 - 2021 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/check_object_grants.sql b/source/check_object_grants.sql index 705882bd2..5f560e6b1 100644 --- a/source/check_object_grants.sql +++ b/source/check_object_grants.sql @@ -1,12 +1,15 @@ declare - c_expected_grants constant dbmsoutput_linesarray := dbmsoutput_linesarray('DBMS_LOCK','DBMS_CRYPTO'); - + $if dbms_db_version.version >= 18 $then + c_expected_grants constant dbmsoutput_linesarray := dbmsoutput_linesarray('DBMS_CRYPTO'); + $else + c_expected_grants constant dbmsoutput_linesarray := dbmsoutput_linesarray('DBMS_LOCK','DBMS_CRYPTO'); + $end l_missing_grants varchar2(4000); l_target_table varchar2(128); l_owner_column varchar2(128); function get_view(a_dba_view_name varchar2) return varchar2 is - l_invalid_object_name exception; + l_invalid_object_name exception; l_result varchar2(128) := lower(a_dba_view_name); pragma exception_init(l_invalid_object_name,-44002); begin @@ -21,7 +24,7 @@ begin l_target_table := get_view('dba_tab_privs'); l_owner_column := case when l_target_table like 'dba%' then 'owner' else 'table_schema' end; execute immediate q'[ - select listagg(' - '||object_name,CHR(10)) within group(order by object_name) + select /*+ no_parallel */ listagg(' - '||object_name,CHR(10)) within group(order by object_name) from ( select column_value as object_name from table(:l_expected_grants) diff --git a/source/check_sys_grants.sql b/source/check_sys_grants.sql index e16869e54..79b657328 100644 --- a/source/check_sys_grants.sql +++ b/source/check_sys_grants.sql @@ -1,29 +1,40 @@ +define expected_grants = "&1" declare - c_expected_grants constant dbmsoutput_linesarray - := dbmsoutput_linesarray( - 'CREATE TYPE','CREATE VIEW','CREATE SYNONYM','CREATE SEQUENCE','CREATE PROCEDURE','CREATE TABLE' - ); + c_expected_grants constant dbmsoutput_linesarray := dbmsoutput_linesarray( &expected_grants ); l_expected_grants dbmsoutput_linesarray := c_expected_grants; l_missing_grants varchar2(4000); begin if user != SYS_CONTEXT('userenv','current_schema') then for i in 1 .. l_expected_grants.count loop - l_expected_grants(i) := replace(l_expected_grants(i),' ',' ANY '); + if l_expected_grants(i) != 'ADMINISTER DATABASE TRIGGER' then + l_expected_grants(i) := replace(l_expected_grants(i),' ',' ANY '); + end if; end loop; end if; + + with + x as ( + select '' as remove from dual + union all + select ' ANY' as remove from dual + ) select listagg(' - '||privilege,CHR(10)) within group(order by privilege) - into l_missing_grants - from ( - select column_value as privilege - from table(l_expected_grants) - minus - (select privilege - from user_sys_privs - union all - select replace(privilege,' ANY ') privilege - from user_sys_privs) - ); + into l_missing_grants + from ( + select column_value as privilege + from table(l_expected_grants) + minus ( + select replace(p.privilege, x.remove) as privilege + from role_sys_privs p + join session_roles r using (role) + cross join x + union all + select replace(p.privilege, x.remove) as privilege + from user_sys_privs p + cross join x + ) + ); if l_missing_grants is not null then raise_application_error( -20000 diff --git a/source/core/annotations/ut_annotated_object.tps b/source/core/annotations/ut_annotated_object.tps index 4bf141a3f..3fda363fe 100644 --- a/source/core/annotations/ut_annotated_object.tps +++ b/source/core/annotations/ut_annotated_object.tps @@ -1,7 +1,7 @@ create type ut_annotated_object as object( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -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_annotated_objects.tps b/source/core/annotations/ut_annotated_objects.tps index b7c01fe7a..c67c1bd53 100644 --- a/source/core/annotations/ut_annotated_objects.tps +++ b/source/core/annotations/ut_annotated_objects.tps @@ -1,7 +1,7 @@ create type ut_annotated_objects as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/annotations/ut_annotation.tps b/source/core/annotations/ut_annotation.tps index 35af758c7..3d0311571 100644 --- a/source/core/annotations/ut_annotation.tps +++ b/source/core/annotations/ut_annotation.tps @@ -1,7 +1,7 @@ create type ut_annotation as object( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/annotations/ut_annotation_cache.sql b/source/core/annotations/ut_annotation_cache.sql index f9c9295cb..67149ce60 100644 --- a/source/core/annotations/ut_annotation_cache.sql +++ b/source/core/annotations/ut_annotation_cache.sql @@ -1,7 +1,7 @@ create table ut_annotation_cache ( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 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 diff --git a/source/core/annotations/ut_annotation_cache_info.sql b/source/core/annotations/ut_annotation_cache_info.sql index 48f8a606c..167973a04 100644 --- a/source/core/annotations/ut_annotation_cache_info.sql +++ b/source/core/annotations/ut_annotation_cache_info.sql @@ -1,7 +1,7 @@ create table ut_annotation_cache_info ( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 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 @@ -16,8 +16,9 @@ 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, - constraint ut_annotation_cache_info_pk primary key(cache_id), - constraint ut_annotation_cache_info_uk unique (object_owner, object_name, object_type) + parse_time timestamp not null, + constraint ut_annotation_cache_info_pk primary key(cache_id) using index, + constraint ut_annotation_cache_info_uk unique (object_owner, object_type, object_name) using index, + constraint ut_annotation_cache_info_fk foreign key(object_owner, object_type) references ut_annotation_cache_schema(object_owner, object_type) on delete cascade ) organization index; diff --git a/source/core/annotations/ut_annotation_cache_manager.pkb b/source/core/annotations/ut_annotation_cache_manager.pkb index a05914e37..e1131b3bd 100644 --- a/source/core/annotations/ut_annotation_cache_manager.pkb +++ b/source/core/annotations/ut_annotation_cache_manager.pkb @@ -1,7 +1,7 @@ create or replace package body ut_annotation_cache_manager as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -17,76 +17,170 @@ 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; + l_cache_id integer; + l_timestamp timestamp := systimestamp; pragma autonomous_transaction; begin - update ut_annotation_cache_info i - set i.parse_time = sysdate - 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; + update /*+ no_parallel */ ut_annotation_cache_schema s + set s.max_parse_time = l_timestamp + where s.object_type = a_object.object_type and s.object_owner = a_object.object_owner; + 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) - returning cache_id into l_cache_id; + insert /*+ no_parallel */ into ut_annotation_cache_schema s + (object_owner, object_type, max_parse_time) + values (a_object.object_owner, a_object.object_type, l_timestamp); end if; - delete from ut_annotation_cache c - where cache_id = l_cache_id; - + -- if not in trigger, or object has annotations if a_object.annotations is not null and a_object.annotations.count > 0 then --- begin - insert into ut_annotation_cache + + update /*+ no_parallel */ ut_annotation_cache_info i + set i.parse_time = l_timestamp + 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 /*+ no_parallel */ 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, l_timestamp) + returning cache_id into l_cache_id; + end if; + + delete /*+ no_parallel */ from ut_annotation_cache c where cache_id = l_cache_id; + + insert /*+ no_parallel */ 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 + select /*+ no_parallel */ 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; + elsif a_object.annotations is null or a_object.annotations.count = 0 then + ut_annotation_cache_manager.remove_from_cache( + ut_annotation_objs_cache_info( + ut_annotation_obj_cache_info(a_object.object_owner, a_object.object_name, a_object.object_type, 'Y', null) + ) + ); end if; commit; end; - procedure cleanup_cache(a_objects ut_annotation_objs_cache_info) is + procedure reset_objects_cache(a_objects ut_annotation_objs_cache_info) is + l_timestamp timestamp := systimestamp; pragma autonomous_transaction; begin - delete from ut_annotation_cache c + delete /*+ no_parallel */ from ut_annotation_cache c where c.cache_id - in (select i.cache_id + in (select /*+ no_parallel */ i.cache_id from ut_annotation_cache_info i join table (a_objects) o on o.object_name = i.object_name and o.object_type = i.object_type and o.object_owner = i.object_owner + and o.needs_refresh = 'Y' ); - merge into ut_annotation_cache_info i - using (select o.object_name, o.object_type, o.object_owner - from table(a_objects) o ) o + update /*+ no_parallel */ ut_annotation_cache_schema s + set s.max_parse_time = l_timestamp + where (s.object_owner, s.object_type) + in ( + select /*+ no_parallel */ o.object_owner, o.object_type + from table(a_objects) o + where o.needs_refresh = 'Y' + ); + + if sql%rowcount = 0 then + insert /*+ no_parallel */ into ut_annotation_cache_schema s + (object_owner, object_type, max_parse_time) + select /*+ no_parallel */ distinct o.object_owner, o.object_type, l_timestamp + from table(a_objects) o + where o.needs_refresh = 'Y'; + end if; + + merge /*+ no_parallel */ + into ut_annotation_cache_info i + using (select /*+ no_parallel */ o.object_name, o.object_type, o.object_owner + from table(a_objects) o + where o.needs_refresh = 'Y' + ) o 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 = l_timestamp 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); + (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, l_timestamp); commit; end; - function get_annotations_for_objects(a_cached_objects ut_annotation_objs_cache_info) return sys_refcursor is - l_results sys_refcursor; + function get_cached_objects_list(a_object_owner varchar2, a_object_type varchar2, a_parsed_after timestamp := null) return ut_annotation_objs_cache_info is + l_result ut_annotation_objs_cache_info; + begin + select /*+ no_parallel */ ut_annotation_obj_cache_info( + object_owner => i.object_owner, + object_name => i.object_name, + object_type => i.object_type, + needs_refresh => 'N', + parse_time => i.parse_time + ) + bulk collect into l_result + from ut_annotation_cache_info i + where i.object_owner = a_object_owner + and i.object_type = a_object_type + and (i.parse_time > a_parsed_after or a_parsed_after is null); + return l_result; + end; + + function get_cache_schema_info(a_object_owner varchar2, a_object_type varchar2) return t_cache_schema_info is + l_result t_cache_schema_info; + begin + begin + select /*+ no_parallel */ * + into l_result + from ut_annotation_cache_schema s + where s.object_type = a_object_type and s.object_owner = a_object_owner; + exception + when no_data_found then + null; + end; + return l_result; + end; + + procedure set_fully_refreshed(a_object_owner varchar2, a_object_type varchar2) is + pragma autonomous_transaction; + begin + update /*+ no_parallel */ ut_annotation_cache_schema s + set s.full_refresh_time = s.max_parse_time + where s.object_owner = a_object_owner + and s.object_type = a_object_type; + commit; + end; + + procedure remove_from_cache(a_objects ut_annotation_objs_cache_info) is + pragma autonomous_transaction; + begin + + delete /*+ no_parallel */ from ut_annotation_cache_info i + where exists ( + select /*+ no_parallel */ 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_parsed_since(a_object_owner varchar2, a_object_type varchar2, a_parsed_after timestamp) return sys_refcursor is + l_results sys_refcursor; begin open l_results for - select ut_annotated_object( - o.object_owner, o.object_name, o.object_type, + select /*+ no_parallel */ ut_annotated_object( + i.object_owner, i.object_name, i.object_type, i.parse_time, cast( collect( ut_annotation( @@ -94,12 +188,12 @@ create or replace package body ut_annotation_cache_manager as ) order by c.annotation_position ) as ut_annotations ) - ) - 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 + ) as annotated_object + from ut_annotation_cache_info i join ut_annotation_cache c on i.cache_id = c.cache_id - group by o.object_owner, o.object_name, o.object_type; + where i.object_owner = a_object_owner and i.object_type = a_object_type + and (i.parse_time > a_parsed_after or a_parsed_after is null) + group by i.object_owner, i.object_type, i.object_name, i.parse_time; return l_results; end; @@ -109,29 +203,24 @@ create or replace package body ut_annotation_cache_manager as pragma autonomous_transaction; begin if a_object_owner is null and a_object_type is null then - l_cache_filter := ':a_object_owner is null and :a_object_type is null'; - l_filter := l_cache_filter; + l_filter := ':a_object_owner is null and :a_object_type is null'; + l_cache_filter := l_filter; else - l_filter := - case when a_object_owner is null then ':a_object_owner is null' else 'object_owner = :a_object_owner' end || ' - and '||case when a_object_type is null then ':a_object_type is null' else 'object_type = :a_object_type' end; - l_cache_filter := ' c.cache_id - in (select i.cache_id - from ut_annotation_cache_info i - where '|| l_filter || ' - )'; + l_filter := case when a_object_owner is null then ':a_object_owner is null' else 'object_owner = :a_object_owner' end; + l_filter := l_filter || ' and ' || case when a_object_type is null then ':a_object_type is null' else 'object_type = :a_object_type' end; + l_cache_filter := ' c.cache_id in (select /*+ no_parallel */ i.cache_id from ut_annotation_cache_info i where ' || l_filter || ' )'; end if; - execute immediate ' - delete from ut_annotation_cache c - where '||l_cache_filter + execute immediate 'delete /*+ no_parallel */ from ut_annotation_cache c where ' || l_cache_filter + using a_object_owner, a_object_type; + + execute immediate ' delete /*+ no_parallel */ from ut_annotation_cache_info i where ' || l_filter using a_object_owner, a_object_type; - execute immediate ' - delete from ut_annotation_cache_info i - where ' || l_filter + execute immediate ' delete /*+ no_parallel */ from ut_annotation_cache_schema s where ' || l_filter using a_object_owner, a_object_type; + commit; end; -end ut_annotation_cache_manager; +end; / diff --git a/source/core/annotations/ut_annotation_cache_manager.pks b/source/core/annotations/ut_annotation_cache_manager.pks index d37212d69..1e9734934 100644 --- a/source/core/annotations/ut_annotation_cache_manager.pks +++ b/source/core/annotations/ut_annotation_cache_manager.pks @@ -1,7 +1,7 @@ create or replace package ut_annotation_cache_manager authid definer as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ create or replace package ut_annotation_cache_manager authid definer as See the License for the specific language governing permissions and limitations under the License. */ + subtype t_cache_schema_info is ut_annotation_cache_schema%rowtype; /** * Populates cache with information about object and it's annotations @@ -30,16 +31,34 @@ create or replace package ut_annotation_cache_manager authid definer as * Returns a ref_cursor containing `ut_annotated_object` as result * Range of data returned is limited by the input collection o cache object info * - * @param a_cached_objects a `ut_annotation_objs_cache_info` list with information about objects to get from cache + * @param a_cached_objects - list of `ut_annotation_objs_cache_info` containing objects to get from cache + * @param a_min_parse_time - limit results to annotations parsed after specified time only, + * if null - all cached annotations for given objects are returned */ - function get_annotations_for_objects(a_cached_objects ut_annotation_objs_cache_info) return sys_refcursor; + function get_annotations_parsed_since(a_object_owner varchar2, a_object_type varchar2, a_parsed_after timestamp) return sys_refcursor; + + procedure set_fully_refreshed(a_object_owner varchar2, a_object_type varchar2); + + function get_cache_schema_info(a_object_owner varchar2, a_object_type varchar2) return t_cache_schema_info; + + /** + * Returns information about all objects stored in annotation cache + */ + function get_cached_objects_list(a_object_owner varchar2, a_object_type varchar2, a_parsed_after timestamp := null) return ut_annotation_objs_cache_info; + + /** + * Resets 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 annotations for + */ + procedure reset_objects_cache(a_objects ut_annotation_objs_cache_info); /** - * Removes cached information about annotations for objects on the list and updates parse_time in cache info table. + * 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 cleanup_cache(a_objects ut_annotation_objs_cache_info); + 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_schema.sql b/source/core/annotations/ut_annotation_cache_schema.sql new file mode 100644 index 000000000..8889b9abf --- /dev/null +++ b/source/core/annotations/ut_annotation_cache_schema.sql @@ -0,0 +1,21 @@ +create table ut_annotation_cache_schema ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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_type varchar2(250) not null, + max_parse_time date not null, + full_refresh_time timestamp, + constraint ut_annotation_cache_schema_pk primary key(object_owner, object_type) +) organization index; + diff --git a/source/core/annotations/ut_annotation_cache_seq.sql b/source/core/annotations/ut_annotation_cache_seq.sql index 028225ddb..b371b382b 100644 --- a/source/core/annotations/ut_annotation_cache_seq.sql +++ b/source/core/annotations/ut_annotation_cache_seq.sql @@ -1,7 +1,7 @@ create sequence ut_annotation_cache_seq /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 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 @@ -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..65f7b3e40 100644 --- a/source/core/annotations/ut_annotation_manager.pkb +++ b/source/core/annotations/ut_annotation_manager.pkb @@ -1,7 +1,7 @@ create or replace package body ut_annotation_manager as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -19,100 +19,137 @@ 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; - 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; + function user_can_see_whole_schema( a_schema_name varchar2 ) return boolean is 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 - ) - 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; - return l_result; + return sys_context('userenv','current_user') = a_schema_name + or ut_metadata.user_has_execute_any_proc() + or ut_metadata.is_object_visible('dba_objects'); 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'); + function get_non_existing_objects( a_object_owner varchar2, a_object_type varchar2 ) return ut_annotation_objs_cache_info is + l_objects_view varchar2(200) := ut_metadata.get_objects_view_name(); + l_object_to_delete ut_annotation_objs_cache_info := ut_annotation_objs_cache_info(); + l_cached_objects ut_annotation_objs_cache_info; 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]' - using a_object_type, a_object_owner, a_object_type, a_object_owner; + l_cached_objects := ut_annotation_cache_manager.get_cached_objects_list( a_object_owner, a_object_type ); + if l_cached_objects is not empty then + execute immediate 'select /*+ no_parallel cardinality(i '||ut_utils.scale_cardinality(cardinality(l_cached_objects))||') */ + value(i) + from table( :l_data ) 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 = ']'||ut_utils.qualified_sql_name(a_object_owner)||q'[' + and o.object_type = ']'||ut_utils.qualified_sql_name(a_object_type)||q'[' + )]' + bulk collect into l_object_to_delete + using l_cached_objects; + end if; + return l_object_to_delete; + end; + + function get_objects_to_refresh( + a_object_owner varchar2, + a_object_type varchar2, + a_modified_after timestamp + ) return ut_annotation_objs_cache_info is + l_ut_owner varchar2(250) := ut_utils.ut_owner; + l_refresh_needed boolean; + l_objects_view varchar2(200) := ut_metadata.get_objects_view_name(); + l_cached_objects ut_annotation_objs_cache_info; + l_result ut_annotation_objs_cache_info := ut_annotation_objs_cache_info(); + begin + ut_event_manager.trigger_event( 'get_objects_to_refresh - start', ut_key_anyvalues().put('ut_trigger_check.is_alive()',ut_trigger_check.is_alive()) ); + + l_refresh_needed := ( ut_trigger_check.is_alive() = false ) or a_modified_after is null; + if l_refresh_needed then + --limit the list to objects that exist and are visible to the invoking user + --enrich the list by info about cache validity + l_cached_objects := ut_annotation_cache_manager.get_cached_objects_list( a_object_owner, a_object_type, a_modified_after ); + execute immediate + 'select /*+ no_parallel cardinality(i '||ut_utils.scale_cardinality(cardinality(l_cached_objects))||') */ + '||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 => 'Y', + parse_time => c.parse_time + ) + from ]'||l_objects_view||' o + left join table( cast(:l_cached_objects as '||l_ut_owner||q'[.ut_annotation_objs_cache_info ) ) c + on o.owner = c.object_owner + and o.object_name = c.object_name + and o.object_type = c.object_type + where o.owner = ']'||ut_utils.qualified_sql_name(a_object_owner)||q'[' + and o.object_type = ']'||ut_utils.qualified_sql_name(a_object_type)||q'[' + and case when o.last_ddl_time < cast(c.parse_time as date) then 'N' else 'Y' end = 'Y' + and ]' + || case + when a_modified_after is null + then ':a_modified_after is null' + else 'o.last_ddl_time >= cast(:a_modified_after as date)' + end + bulk collect into l_result using l_cached_objects, a_modified_after; + end if; + ut_event_manager.trigger_event('get_objects_to_refresh - end (count='||l_result.count||')'); return l_result; end; 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 /*+ no_parallel */ x.name, x.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*--\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.owner = ']'||ut_utils.qualified_sql_name(a_object_owner)||q'[' + and s.type = ']'||ut_utils.qualified_sql_name(a_object_type)||q'[' + ) x + where x.is_annotated = 'Y' + order by x.name, x.line]' + using a_objects_to_refresh; 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; + c_lines_fetch_limit constant integer := 10000; l_lines dbms_preprocessor.source_lines_t; 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); + l_annotations := ut_annotation_parser.parse_object_annotations(l_object_lines, a_object_type); 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; @@ -124,88 +161,160 @@ create or replace package body ut_annotation_manager as end loop; if a_sources_cursor%rowcount > 0 then - l_annotations := ut_annotation_parser.parse_object_annotations(l_object_lines); + l_annotations := ut_annotation_parser.parse_object_annotations(l_object_lines, a_object_type); 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; close a_sources_cursor; - commit; 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 validate_annotation_cache( + a_object_owner varchar2, + a_object_type varchar2, + a_modified_after timestamp := null + ) is + l_objects_to_refresh ut_annotation_objs_cache_info; + l_modified_after timestamp := a_modified_after; 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'; + if ut_annotation_cache_manager.get_cache_schema_info(a_object_owner, a_object_type).full_refresh_time is null then + l_modified_after := null; + end if; + + l_objects_to_refresh := get_objects_to_refresh(a_object_owner, a_object_type, l_modified_after); + + ut_event_manager.trigger_event('validate_annotation_cache - start (l_objects_to_refresh.count = '||l_objects_to_refresh.count||')'); - --if cache is empty and there are objects to parse - if l_objects_in_cache_count = 0 and a_info_rows.count > 0 then + if user_can_see_whole_schema( a_object_owner ) then + --Remove non existing objects from cache only when user can see whole schema + ut_annotation_cache_manager.remove_from_cache( get_non_existing_objects( a_object_owner, a_object_type ) ); + end if; + + --if some source needs parsing and putting into cache + if l_objects_to_refresh.count > 0 then + --Delete annotations for objects that are to be refreshed + ut_annotation_cache_manager.reset_objects_cache(l_objects_to_refresh); + --Rebuild cache from objects source 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_refresh) ); + end if; - --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 - ); + if l_modified_after is null then + if user_can_see_whole_schema( a_object_owner ) then + ut_annotation_cache_manager.set_fully_refreshed( a_object_owner, a_object_type ); + else + -- if user cannot see full schema - we dont mark it as fully refreshed + -- it will get refreshed each time until someone with proper privs will refresh it + null; end if; - end if; + ut_event_manager.trigger_event('validate_annotation_cache - end'); end; ------------------------------------------------------------ --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); + validate_annotation_cache( a_object_owner, a_object_type ); end; - function get_annotated_objects(a_object_owner varchar2, a_object_type varchar2) return ut_annotated_objects pipelined is - l_info_cursor sys_refcursor; - l_info_rows ut_annotation_objs_cache_info; + procedure trigger_obj_annotation_rebuild is + l_sql_text ora_name_list_t; + l_parts binary_integer; + l_restricted_users ora_name_list_t; + + function get_source_from_sql_text(a_object_name varchar2, a_sql_text ora_name_list_t, a_parts binary_integer) return sys_refcursor is + l_sql_clob clob; + l_sql_lines ut_varchar2_rows := ut_varchar2_rows(); + l_result sys_refcursor; + begin + if a_parts > 0 then + for i in 1..a_parts loop + ut_utils.append_to_clob(l_sql_clob, a_sql_text(i)); + end loop; + l_sql_clob := ut_utils.replace_multiline_comments(l_sql_clob); + -- replace comment lines that contain "-- create or replace" + l_sql_clob := regexp_replace(l_sql_clob, '^.*[-]{2,}\s*create(\s+or\s+replace).*$', modifier => 'mi'); + -- remove the "create [or replace] [[non]editionable] " so that we have only "type|package" for parsing + -- needed for dbms_preprocessor + l_sql_clob := regexp_replace(l_sql_clob, '^(.*?\s*create(\s+or\s+replace)?(\s+(editionable|noneditionable))?\s+?)((package|type).*)', '\5', 1, 1, 'ni'); + -- remove "OWNER." from create or replace statement. + -- Owner is not supported along with AUTHID - see issue https://github.com/utPLSQL/utPLSQL/issues/1088 + l_sql_clob := regexp_replace(l_sql_clob, '^(package|type)\s+("?[[:alpha:]][[:alnum:]$#_]*"?\.)(.*)', '\1 \3', 1, 1, 'ni'); + l_sql_lines := ut_utils.convert_collection( ut_utils.clob_to_table(l_sql_clob) ); + end if; + open l_result for + select /*+ no_parallel */ a_object_name as name, column_value||chr(10) as text from table(l_sql_lines); + return l_result; + end; + + function get_source_for_object(a_object_owner varchar2, a_object_name varchar2, a_object_type varchar2) return sys_refcursor is + l_result sys_refcursor; + l_sources_view varchar2(200) := ut_metadata.get_source_view_name(); + begin + open l_result for + q'[select /*+ no_parallel */ :a_object_name, s.text + from ]'||l_sources_view||q'[ s + where s.type = :a_object_type + and s.owner = :a_object_owner + and s.name = :a_object_name + order by s.line]' + using a_object_name, a_object_type, a_object_owner, a_object_name; + return l_result; + end; + + begin + if ora_dict_obj_type in ('PACKAGE','PROCEDURE','FUNCTION','TYPE') then + $if dbms_db_version.version < 12 $then + l_restricted_users := ora_name_list_t( + 'ANONYMOUS','APPQOSSYS','AUDSYS','DBSFWUSER','DBSNMP','DIP','GGSYS','GSMADMIN_INTERNAL', + 'GSMCATUSER','GSMUSER','ORACLE_OCM','OUTLN','REMOTE_SCHEDULER_AGENT','SYS','SYS$UMF', + 'SYSBACKUP','SYSDG','SYSKM','SYSRAC','SYSTEM','WMSYS','XDB','XS$NULL'); + $else + select /*+ no_parallel */ username bulk collect into l_restricted_users + from all_users where oracle_maintained = 'Y'; + $end + if ora_dict_obj_owner member of l_restricted_users then + return; + end if; + + if ora_sysevent = 'CREATE' then + l_parts := ORA_SQL_TXT(l_sql_text); + build_annot_cache_for_sources( + ora_dict_obj_owner, ora_dict_obj_type, + get_source_from_sql_text(ora_dict_obj_name, l_sql_text, l_parts) + ); + elsif ora_sysevent = 'ALTER' then + build_annot_cache_for_sources( + ora_dict_obj_owner, ora_dict_obj_type, + get_source_for_object(ora_dict_obj_owner, ora_dict_obj_name, ora_dict_obj_type) + ); + elsif ora_sysevent = 'DROP' then + ut_annotation_cache_manager.remove_from_cache( + ut_annotation_objs_cache_info( + ut_annotation_obj_cache_info(ora_dict_obj_owner, ora_dict_obj_name, ora_dict_obj_type, 'Y', null) + ) + ); + end if; + end if; + end; + + function get_annotated_objects(a_object_owner varchar2, a_object_type varchar2, a_modified_after timestamp) return sys_refcursor is 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; - rebuild_annotation_cache(a_object_owner, a_object_type, l_info_rows); + ut_event_manager.trigger_event('get_annotated_objects - start: a_modified_after='||ut_utils.to_string(a_modified_after)); + validate_annotation_cache(a_object_owner, a_object_type, a_modified_after); --pipe annotations from cache - l_cursor := ut_annotation_cache_manager.get_annotations_for_objects(l_info_rows); - loop - fetch l_cursor bulk collect into l_results limit c_object_fetch_limit; - for i in 1 .. l_results.count loop - pipe row (l_results(i)); - end loop; - exit when l_cursor%notfound; - end loop; - close l_cursor; - + l_cursor := ut_annotation_cache_manager.get_annotations_parsed_since(a_object_owner, a_object_type, a_modified_after); + ut_event_manager.trigger_event('get_annotated_objects - end'); + return l_cursor; end; procedure purge_cache(a_object_owner varchar2, a_object_type varchar2) is @@ -213,5 +322,5 @@ create or replace package body ut_annotation_manager as ut_annotation_cache_manager.purge_cache(a_object_owner, a_object_type); end; -end ut_annotation_manager; +end; / diff --git a/source/core/annotations/ut_annotation_manager.pks b/source/core/annotations/ut_annotation_manager.pks index a2925c388..20fcd810f 100644 --- a/source/core/annotations/ut_annotation_manager.pks +++ b/source/core/annotations/ut_annotation_manager.pks @@ -1,7 +1,7 @@ create or replace package ut_annotation_manager authid current_user as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -23,17 +23,17 @@ create or replace package ut_annotation_manager authid current_user as /** * Gets annotations for all objects of a specified type for database schema. * Annotations that are stale or missing are parsed and placed in persistent cache. - * After placing in cache, annotation data is returned as pipelined table data. + * After placing in cache, annotation data is returned as ref_cursor. * - * @param a_object_owner owner of objects to get annotations for - * @param a_object_type type of objects to get annotations for - * @return array containing annotated objects along with annotations for each object (nested) + * @param a_object_owner owner of objects to get annotations for + * @param a_object_type type of objects to get annotations for + * @param a_modified_after return only objects modified after thr timestamp + * @return cursor 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_modified_after timestamp) return sys_refcursor; /** * Rebuilds annotation cache for a specified schema and object type. - * The procedure is called internally by `get_annotated_objects` function. * It can be used to speedup initial execution of utPLSQL on a given schema * if it is executed before any call is made to `ut.run` or `ut_runner.run` procedure. * @@ -42,6 +42,11 @@ create or replace package ut_annotation_manager authid current_user as */ procedure rebuild_annotation_cache(a_object_owner varchar2, a_object_type varchar2); + /** + * Rebuilds annotation cache for a specified object. + */ + procedure trigger_obj_annotation_rebuild; + /** * Removes cached information about annotations for objects of specified type and specified owner * @@ -50,5 +55,6 @@ create or replace package ut_annotation_manager authid current_user as */ procedure purge_cache(a_object_owner varchar2, a_object_type varchar2); -end ut_annotation_manager; + +end; / diff --git a/source/core/annotations/ut_annotation_obj_cache_info.tps b/source/core/annotations/ut_annotation_obj_cache_info.tps index 2be2ac184..1db3fd190 100644 --- a/source/core/annotations/ut_annotation_obj_cache_info.tps +++ b/source/core/annotations/ut_annotation_obj_cache_info.tps @@ -1,7 +1,7 @@ create type ut_annotation_obj_cache_info as object( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ create type ut_annotation_obj_cache_info as object( object_owner varchar2(250), object_name varchar2(250), object_type varchar2(250), - needs_refresh varchar2(1) + needs_refresh varchar2(1), + parse_time timestamp ) / diff --git a/source/core/annotations/ut_annotation_objs_cache_info.tps b/source/core/annotations/ut_annotation_objs_cache_info.tps index 9773a045e..fc96e7d25 100644 --- a/source/core/annotations/ut_annotation_objs_cache_info.tps +++ b/source/core/annotations/ut_annotation_objs_cache_info.tps @@ -1,7 +1,7 @@ create type ut_annotation_objs_cache_info as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/annotations/ut_annotation_parser.pkb b/source/core/annotations/ut_annotation_parser.pkb index 2467c6262..10bb76b3c 100644 --- a/source/core/annotations/ut_annotation_parser.pkb +++ b/source/core/annotations/ut_annotation_parser.pkb @@ -1,7 +1,7 @@ create or replace package body ut_annotation_parser as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -19,13 +19,13 @@ create or replace package body ut_annotation_parser as ------------------------------ --private definitions - type tt_comment_list is table of varchar2(32767) index by pls_integer; + type tt_comment_list is table of varchar2(32767) index by binary_integer; gc_annotation_qualifier constant varchar2(1) := '%'; gc_annot_comment_pattern constant varchar2(30) := '^( |'||chr(09)||')*-- *('||gc_annotation_qualifier||'.*?)$'; -- chr(09) is a tab character gc_comment_replacer_patter constant varchar2(50) := '{COMMENT#%N%}'; gc_comment_replacer_regex_ptrn constant varchar2(25) := '{COMMENT#(\d+)}'; - gc_regexp_identifier constant varchar2(50) := '[a-z][a-z0-9#_$]*'; + gc_regexp_identifier constant varchar2(50) := '[[:alpha:]][[:alnum:]$#_]*'; gc_annotation_block_pattern constant varchar2(200) := '(({COMMENT#.+}'||chr(10)||')+)( |'||chr(09)||')*(procedure|function)\s+(' || gc_regexp_identifier || ')'; gc_annotation_pattern constant varchar2(50) := gc_annotation_qualifier || gc_regexp_identifier || '[ '||chr(9)||']*(\(.*?\)\s*?$)?'; @@ -46,10 +46,7 @@ create or replace package body ut_annotation_parser as if l_annotation_str is not null then -- get the annotation name and it's parameters if present - l_annotation_name := lower(regexp_substr(l_annotation_str - ,'%(' || gc_regexp_identifier || ')' - ,modifier => 'i' - ,subexpression => 1)); + l_annotation_name := lower(regexp_substr(l_annotation_str ,'%(' || gc_regexp_identifier || ')', subexpression => 1)); l_annotation_text := trim(regexp_substr(l_annotation_str, '\((.*?)\)\s*$', subexpression => 1)); a_annotations.extend; @@ -59,7 +56,7 @@ create or replace package body ut_annotation_parser as end; procedure delete_processed_comments( a_comments in out nocopy tt_comment_list, a_annotations ut_annotations ) is - l_loop_index pls_integer := 1; + l_loop_index binary_integer := 1; begin l_loop_index := a_annotations.first; while l_loop_index is not null loop @@ -74,8 +71,8 @@ create or replace package body ut_annotation_parser as a_comments tt_comment_list, a_subobject_name varchar2 := null ) is - l_loop_index pls_integer := 1; - l_annotation_index pls_integer; + l_loop_index binary_integer := 1; + l_annotation_index binary_integer; begin -- loop while there are unprocessed comment blocks while 0 != nvl(regexp_instr(srcstr => a_source @@ -155,7 +152,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 @@ -213,32 +210,29 @@ create or replace package body ut_annotation_parser as dbms_lob.freetemporary(l_source); - select value(x) bulk collect into l_result from table(l_annotations) x order by x.position; + select /*+ no_parallel */ value(x) bulk collect into l_result from table(l_annotations) x order by x.position; - -- printing out parsed structure for debugging - $if $$ut_trace $then - print_parse_results(l_result); - dbms_output.put_line('Annotations count: ' || l_result.count); - for i in 1 .. l_result.count loop - dbms_output.put_line(xmltype(l_result(i)).getclobval()); - end loop; - $end return l_result; end parse_object_annotations; - function parse_object_annotations(a_source_lines dbms_preprocessor.source_lines_t) return ut_annotations is + function parse_object_annotations(a_source_lines dbms_preprocessor.source_lines_t, a_object_type varchar2) return ut_annotations is l_processed_lines dbms_preprocessor.source_lines_t; l_source clob; l_annotations ut_annotations := ut_annotations(); ex_package_is_wrapped exception; pragma exception_init(ex_package_is_wrapped, -24241); - + source_text_is_empty exception; + pragma exception_init(source_text_is_empty, -24236); begin if a_source_lines.count > 0 then --convert to post-processed source clob begin --get post-processed source - l_processed_lines := sys.dbms_preprocessor.get_post_processed_source(a_source_lines); + if a_object_type = 'TYPE' then + l_processed_lines := a_source_lines; + else + l_processed_lines := sys.dbms_preprocessor.get_post_processed_source(a_source_lines); + end if; --convert to clob for i in 1..l_processed_lines.count loop ut_utils.append_to_clob(l_source, replace(l_processed_lines(i), chr(13)||chr(10), chr(10))); @@ -247,12 +241,12 @@ create or replace package body ut_annotation_parser as l_annotations := parse_object_annotations(l_source); dbms_lob.freetemporary(l_source); exception - when ex_package_is_wrapped then + when ex_package_is_wrapped or source_text_is_empty then null; end; end if; return l_annotations; end; -end ut_annotation_parser; +end; / diff --git a/source/core/annotations/ut_annotation_parser.pks b/source/core/annotations/ut_annotation_parser.pks index a396e877e..2f474c883 100644 --- a/source/core/annotations/ut_annotation_parser.pks +++ b/source/core/annotations/ut_annotation_parser.pks @@ -1,7 +1,7 @@ create or replace package ut_annotation_parser authid current_user as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -27,7 +27,7 @@ create or replace package ut_annotation_parser authid current_user as * @param a_source_lines ordered lines of source code to be parsed * @return array containing annotations */ - function parse_object_annotations(a_source_lines dbms_preprocessor.source_lines_t) return ut_annotations; + function parse_object_annotations(a_source_lines dbms_preprocessor.source_lines_t, a_object_type varchar2) return ut_annotations; /** @@ -40,5 +40,5 @@ create or replace package ut_annotation_parser authid current_user as */ function parse_object_annotations(a_source clob) return ut_annotations; -end ut_annotation_parser; +end; / diff --git a/source/core/annotations/ut_annotations.tps b/source/core/annotations/ut_annotations.tps index 4238f9512..a6579d236 100644 --- a/source/core/annotations/ut_annotations.tps +++ b/source/core/annotations/ut_annotations.tps @@ -1,7 +1,7 @@ create type ut_annotations /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/annotations/ut_trigger_annotation_parsing.trg b/source/core/annotations/ut_trigger_annotation_parsing.trg new file mode 100644 index 000000000..437b7742d --- /dev/null +++ b/source/core/annotations/ut_trigger_annotation_parsing.trg @@ -0,0 +1,18 @@ +create or replace trigger ut_trigger_annotation_parsing + after create or alter or drop +on database +begin + if (ora_dict_obj_owner = UPPER('&&UT3_OWNER') + and ora_dict_obj_name = 'UT3_TRIGGER_ALIVE' + and ora_dict_obj_type = 'SYNONYM') + then + execute immediate 'begin ut_trigger_check.is_alive(); end;'; + elsif ora_dict_obj_type in ('PACKAGE','PROCEDURE','FUNCTION','TYPE') + and not (ora_dict_obj_type = 'TYPE' and ora_dict_obj_name like 'SYS\_PLSQL\_%' escape '\') + then + execute immediate 'begin ut_annotation_manager.trigger_obj_annotation_rebuild; end;'; + end if; +exception + when others then null; +end; +/ diff --git a/source/core/annotations/ut_trigger_check.pkb b/source/core/annotations/ut_trigger_check.pkb new file mode 100644 index 000000000..34e43ba46 --- /dev/null +++ b/source/core/annotations/ut_trigger_check.pkb @@ -0,0 +1,39 @@ +create or replace package body ut_trigger_check is + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + gc_check_object_name constant varchar2(128) := 'UT3_TRIGGER_ALIVE'; + g_is_trigger_live boolean := false; + + function is_alive return boolean is + pragma autonomous_transaction; + begin + execute immediate 'create or replace synonym '||ut_utils.ut_owner||'.'||gc_check_object_name||' for no_object'; + return g_is_trigger_live; + end; + + procedure is_alive is + begin + if ora_dict_obj_owner is not null and ora_dict_obj_name is not null and ora_dict_obj_type is not null then + g_is_trigger_live := true; + else + g_is_trigger_live := false; + end if; + end; + +end; +/ diff --git a/source/expectations/data_values/ut_data_value_object.tpb b/source/core/annotations/ut_trigger_check.pks similarity index 57% rename from source/expectations/data_values/ut_data_value_object.tpb rename to source/core/annotations/ut_trigger_check.pks index 89e49abc1..cee0b06fd 100644 --- a/source/expectations/data_values/ut_data_value_object.tpb +++ b/source/core/annotations/ut_trigger_check.pks @@ -1,7 +1,7 @@ -create or replace type body ut_data_value_object as +create or replace package ut_trigger_check authid definer is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -16,17 +16,16 @@ create or replace type body ut_data_value_object as limitations under the License. */ - constructor function ut_data_value_object(self in out nocopy ut_data_value_object, a_value anydata) return self as result is - begin - self.self_type := $$plsql_unit; - self.init(a_value, 'object', '/*/*'); - return; - end; + /** + * checks if the trigger &&UT3_OWNER._PARSE is enabled and operational. + */ + function is_alive return boolean; - overriding member function get_object_info return varchar2 is - begin - return self.data_type; - end; + /** + * If called from a DDL trigger sets alive flag to true. + * If called outside of DDL trigger, sets alive flag to false. + */ + procedure is_alive; end; / diff --git a/source/core/coverage/dbms_plssqlcode.sql b/source/core/coverage/dbms_plssqlcode.sql index e3aa2ec9a..1ae287207 100644 --- a/source/core/coverage/dbms_plssqlcode.sql +++ b/source/core/coverage/dbms_plssqlcode.sql @@ -1,8 +1,67 @@ +declare + l_tab_exist number; begin - $if dbms_db_version.version = 12 and dbms_db_version.release >= 2 or dbms_db_version.version > 12 $then - dbms_plsql_code_coverage.create_coverage_tables(force_it => true); - $else - null; - $end + select count(*) into l_tab_exist from + (select table_name from all_tables where table_name = 'DBMSPCC_BLOCKS' and owner = sys_context('USERENV','CURRENT_SCHEMA') + union all + select synonym_name from all_synonyms where synonym_name = 'DBMSPCC_BLOCKS' and owner = sys_context('USERENV','CURRENT_SCHEMA')); + if l_tab_exist = 0 then + execute immediate q'[ + create table dbmspcc_blocks ( + run_id number(38, 0), + object_id number(38, 0), + block number(38, 0), + line number(38, 0) constraint dbmspcc_blocks_line_nn not null enable, + col number(38, 0) constraint dbmspcc_blocks_col_nn not null enable, + covered number(1, 0) constraint dbmspcc_blocks_covered_nn not null enable, + not_feasible number(1, 0) constraint dbmspcc_blocks_not_feasible_nn not null enable, + constraint dbmspcc_blocks_block_ck check ( block >= 0 ) enable, + constraint dbmspcc_blocks_line_ck check ( line >= 0 ) enable, + constraint dbmspcc_blocks_col_ck check ( col >= 0 ) enable, + constraint dbmspcc_blocks_covered_ck check ( covered in ( 0, 1 ) ) enable, + constraint dbmspcc_blocks_not_feasible_ck check ( not_feasible in ( 0, 1 ) ) enable, + constraint dbmspcc_blocks_pk primary key ( run_id, object_id, block ) using index + )]'; + end if; +end; +/ +declare + l_tab_exist number; +begin + select count(*) into l_tab_exist from + (select table_name from all_tables where table_name = 'DBMSPCC_RUNS' and owner = sys_context('USERENV','CURRENT_SCHEMA') + union all + select synonym_name from all_synonyms where synonym_name = 'DBMSPCC_RUNS' and owner = sys_context('USERENV','CURRENT_SCHEMA')); + if l_tab_exist = 0 then + execute immediate q'[ + create table dbmspcc_runs ( + run_id number(38, 0), + run_comment varchar2(4000 byte), + run_owner varchar2(128 byte) constraint dbmspcc_runs_run_owner_nn not null enable, + run_timestamp date constraint dbmspcc_runs_run_timestamp_nn not null enable, + constraint dbmspcc_runs_pk primary key ( run_id ) using index enable + )]'; + end if; +end; +/ +declare + l_tab_exist number; +begin + select count(*) into l_tab_exist from + (select table_name from all_tables where table_name = 'DBMSPCC_UNITS' and owner = sys_context('USERENV','CURRENT_SCHEMA') + union all + select synonym_name from all_synonyms where synonym_name = 'DBMSPCC_UNITS' and owner = sys_context('USERENV','CURRENT_SCHEMA')); + if l_tab_exist = 0 then + execute immediate q'[ + create table dbmspcc_units ( + run_id number(38, 0), + object_id number(38, 0), + owner varchar2(128 byte) constraint dbmspcc_units_owner_nn not null enable, + name varchar2(128 byte) constraint dbmspcc_units_name_nn not null enable, + type varchar2(12 byte) constraint dbmspcc_units_type_nn not null enable, + last_ddl_time date constraint dbmspcc_units_last_ddl_time_nn not null enable, + constraint dbmspcc_units_pk primary key ( run_id, object_id ) using index enable + )]'; + end if; end; / diff --git a/source/core/coverage/ut_coverage.pkb b/source/core/coverage/ut_coverage.pkb index 64d625d84..7eb5a34c2 100644 --- a/source/core/coverage/ut_coverage.pkb +++ b/source/core/coverage/ut_coverage.pkb @@ -1,7 +1,7 @@ create or replace package body ut_coverage is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -16,114 +16,187 @@ create or replace package body ut_coverage is limitations under the License. */ - g_coverage_id tt_coverage_id_arr; - g_develop_mode boolean not null := false; - g_is_started boolean not null := false; + g_develop_mode boolean not null := false; + g_is_started boolean not null := false; + g_coverage_run_id raw(32); procedure set_develop_mode(a_develop_mode in boolean) is - begin - g_develop_mode := a_develop_mode; - end; - - function get_coverage_id(a_coverage_type in varchar2) return integer is - begin - return g_coverage_id(a_coverage_type); - end; + begin + g_develop_mode := a_develop_mode; + end; function is_develop_mode return boolean is - begin - return g_develop_mode; - end; - - 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'); 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'; - else - l_full_name := 'lower(s.owner||''.''||s.name)'; - end if; - l_result := ' - select full_name, owner, name, line, to_be_skipped, text - from ( - select '||l_full_name||q'[ as full_name, - s.owner, - s.name, - s.line - - coalesce( - case when type!='TRIGGER' then 0 end, - (select min(t.line) - 1 - from ]'||l_view_name||q'[ t - where t.owner = s.owner and t.type = s.type and t.name = s.name - and regexp_like( t.text, '[A-Za-z0-9$#_]*(begin|declare|compound).*','i')) - ) as line, - s.text, ]'; - l_result := l_result || - q'[case - when - -- to avoid execution of regexp_like on every line - -- first do a rough check for existence of search pattern keyword - (lower(s.text) like '%procedure%' - or lower(s.text) like '%function%' - or lower(s.text) like '%begin%' - or lower(s.text) like '%end%' - or lower(s.text) like '%package%' - ) and - regexp_like( - s.text, - '^([\t ]*(((not)?\s*(overriding|final|instantiable)[\t ]*)*(static|constructor|member)?[\t ]*(procedure|function)|package([\t ]+body)|begin|end([\t ]+\S+)*[ \t]*;))', 'i' - ) - then 'Y' - end as to_be_skipped ]'; - - l_result := l_result ||' from '||l_view_name||q'[ s]'; - + return g_develop_mode; + end; + + function get_cov_sources_sql(a_coverage_options ut_coverage_options, a_skip_objects ut_object_names) return varchar2 is + l_result varchar2(32767); + l_full_name varchar2(32767); + l_join_mappings varchar2(32767); + l_filters varchar2(32767); + l_mappings_cardinality integer := 0; + l_regex_exc_filters varchar2(32767); + begin + l_result := q'[ + with + sources as ( + select /*+ cardinality(f {mappings_cardinality}) */ + {l_full_name} as full_name, s.owner, s.name, s.type, + s.line + - case + when s.type = 'TRIGGER' + then + /* calculate offset of line number for trigger source in coverage reporting */ + min(case when lower(s.text) like '%begin%' or lower(s.text) like '%declare%' or lower(s.text) like '%compound%' then s.line-1 end) + over (partition by s.owner, s.type, s.name) + else 0 + end as line, + s.text + from {sources_view} s {join_file_mappings} + where s.type in ('PACKAGE BODY', 'TYPE BODY', 'PROCEDURE', 'FUNCTION', 'TRIGGER') + {filters} + {regex_exc_filters} + and not exists ( + select /*+ cardinality(el {excuded_objects_cardinality})*/ 1 + from table(:l_excluded_objects) el + where s.owner = el.owner and s.name = el.name + ) + ), + coverage_sources as ( + select full_name, owner, name, type, line, text, + case + when + -- to avoid execution of regexp_like on every line + -- first do a rough check for existence of search pattern keyword + (lower(s.text) like '%procedure%' + or lower(s.text) like '%function%' + or lower(s.text) like '%begin%' + or lower(s.text) like '%end%' + or lower(s.text) like '%package%' + ) and + regexp_like( + s.text, + '^([\t ]*(((not)?\s*(overriding|final|instantiable)[\t ]*)*(static|constructor|member)?[\t ]*(procedure|function)|package([\t ]+body)|begin|end([\t ]+\S+)*[ \t]*;))', 'i' + ) + then 'Y' + end as to_be_skipped + from sources s + ) + select /*+ no_parallel */ full_name, owner, name, type, line, to_be_skipped, text + from coverage_sources s + -- Exclude calls to utPLSQL framework, Unit Test packages and objects from a_exclude_list parameter of coverage reporter + where not exists ( + select /*+ cardinality(el {skipped_objects_cardinality})*/ 1 + from table(:l_skipped_objects) el + where s.owner = el.owner and s.name = el.name + ) + and line > 0 + ]'; + if a_coverage_options.file_mappings is not empty then - l_result := l_result || ' + l_mappings_cardinality := ut_utils.scale_cardinality(cardinality(a_coverage_options.file_mappings)); + l_full_name := 'f.file_name'; + l_join_mappings := ' join table(:file_mappings) f on s.name = f.object_name and s.type = f.object_type - and s.owner = f.object_owner - where 1 = 1'; - elsif a_coverage_options.include_objects is not empty then - l_result := l_result || ' - where (s.owner, s.name) in (select il.owner, il.name from table(:include_objects) il)'; + and s.owner = f.object_owner'; + elsif coalesce(a_coverage_options.include_schema_expr,a_coverage_options.include_object_expr) is not null then + l_full_name := q'[lower(s.type||' '||s.owner||'.'||s.name)]'; + if a_coverage_options.include_schema_expr is not null then + l_filters := q'[and regexp_like(s.owner,:a_include_schema_expr,'i')]'; + else + l_filters := 'and :a_include_schema_expr is null'; + end if; + if a_coverage_options.include_object_expr is not null then + l_filters := l_filters|| q'[ and regexp_like(s.name,:a_include_object_expr,'i')]'; + else + l_filters := l_filters|| 'and :a_include_object_expr is null'; + end if; else - l_result := l_result || ' - where s.owner in (select upper(t.column_value) from table(:l_schema_names) t)'; + l_full_name := q'[lower(s.type||' '||s.owner||'.'||s.name)]'; + l_filters := case + when a_coverage_options.include_objects is not empty then ' + and (s.owner, s.name) in ( + select /*+ cardinality(il '||ut_utils.scale_cardinality(cardinality(a_coverage_options.include_objects))||') */ + il.owner, il.name + from table(:include_objects) il + )' + else ' + and s.owner in ( + select /*+ cardinality(t '||ut_utils.scale_cardinality(cardinality(a_coverage_options.schema_names))||') */ + upper(t.column_value) + from table(:l_schema_names) t)' + end; end if; - l_result := l_result || q'[ - and s.type not in ('PACKAGE', 'TYPE', 'JAVA SOURCE') - --Exclude calls to utPLSQL framework, Unit Test packages and objects from a_exclude_list parameter of coverage reporter - and (s.owner, s.name) not in (select el.owner, el.name from table(:l_skipped_objects) el) - ) - where line > 0]'; + + + if a_coverage_options.exclude_schema_expr is not null then + l_regex_exc_filters := q'[ and not regexp_like(s.owner,:a_exclude_schema_expr,'i')]'; + else + l_regex_exc_filters := ' and :a_exclude_schema_expr is null '; + end if; + + if a_coverage_options.exclude_object_expr is not null then + l_regex_exc_filters := l_regex_exc_filters||q'[ and not regexp_like(s.name,:a_exclude_obj_expr,'i')]'; + else + l_regex_exc_filters := l_regex_exc_filters||'and :a_exclude_obj_expr is null '; + end if; + + + + l_result := replace(l_result, '{sources_view}', ut_metadata.get_source_view_name()); + l_result := replace(l_result, '{l_full_name}', l_full_name); + l_result := replace(l_result, '{join_file_mappings}', l_join_mappings); + l_result := replace(l_result, '{filters}', l_filters); + l_result := replace(l_result, '{mappings_cardinality}', l_mappings_cardinality); + l_result := replace(l_result, '{skipped_objects_cardinality}', ut_utils.scale_cardinality(cardinality(a_skip_objects))); + l_result := replace(l_result, '{excuded_objects_cardinality}', ut_utils.scale_cardinality(cardinality(coalesce(a_coverage_options.exclude_objects, ut_object_names())))); + l_result := replace(l_result, '{regex_exc_filters}', l_regex_exc_filters); + return l_result; + end; - function get_cov_sources_cursor(a_coverage_options in ut_coverage_options,a_sql in varchar2) return sys_refcursor is - l_cursor sys_refcursor; - l_skip_objects ut_object_names; - l_sql varchar2(32767); + function get_cov_sources_cursor(a_coverage_options in ut_coverage_options) return sys_refcursor is + l_cursor sys_refcursor; + l_skip_objects ut_object_names; + l_excluded_objects ut_object_names; + l_sql varchar2(32767); begin if not is_develop_mode() then --skip all the utplsql framework objects and all the unit test packages that could potentially be reported by coverage. - l_skip_objects := ut_utils.get_utplsql_objects_list() multiset union all coalesce(a_coverage_options.exclude_objects, ut_object_names()); + l_skip_objects := coalesce( ut_utils.get_utplsql_objects_list() multiset union all ut_suite_manager.get_schema_ut_packages(a_coverage_options.schema_names, a_coverage_options.include_schema_expr) , ut_object_names() ); end if; - l_sql := a_sql; + + --Regex exclusion override the standard exclusion objects. + if a_coverage_options.exclude_schema_expr is null and a_coverage_options.exclude_object_expr is null then + l_excluded_objects := coalesce(a_coverage_options.exclude_objects, ut_object_names()); + end if; + + l_sql := get_cov_sources_sql(a_coverage_options, l_skip_objects); + + ut_event_manager.trigger_event(ut_event_manager.gc_debug, ut_key_anyvalues().put('l_sql',l_sql) ); + if a_coverage_options.file_mappings is not empty then - open l_cursor for l_sql using a_coverage_options.file_mappings, l_skip_objects; + open l_cursor for l_sql using a_coverage_options.file_mappings, a_coverage_options.exclude_schema_expr, + a_coverage_options.exclude_object_expr, l_excluded_objects, l_skip_objects; + elsif coalesce(a_coverage_options.include_schema_expr,a_coverage_options.include_object_expr) is not null then + open l_cursor for l_sql using a_coverage_options.include_schema_expr, a_coverage_options.include_object_expr, + a_coverage_options.exclude_schema_expr, a_coverage_options.exclude_object_expr, + l_excluded_objects, l_skip_objects; elsif a_coverage_options.include_objects is not empty then - open l_cursor for l_sql using a_coverage_options.include_objects, l_skip_objects; + open l_cursor for l_sql using a_coverage_options.include_objects, a_coverage_options.exclude_schema_expr, + a_coverage_options.exclude_object_expr, l_excluded_objects, l_skip_objects; else - open l_cursor for l_sql using a_coverage_options.schema_names, l_skip_objects; + open l_cursor for l_sql using a_coverage_options.schema_names, a_coverage_options.exclude_schema_expr, + a_coverage_options.exclude_object_expr, l_excluded_objects, l_skip_objects; end if; return l_cursor; end; - procedure populate_tmp_table(a_coverage_options ut_coverage_options, a_sql in varchar2) is + procedure populate_tmp_table(a_coverage_options ut_coverage_options) is pragma autonomous_transaction; l_cov_sources_crsr sys_refcursor; l_cov_sources_data ut_coverage_helper.t_coverage_sources_tmp_rows; @@ -131,11 +204,10 @@ create or replace package body ut_coverage is if not ut_coverage_helper.is_tmp_table_populated() or is_develop_mode() then ut_coverage_helper.cleanup_tmp_table(); - - l_cov_sources_crsr := get_cov_sources_cursor(a_coverage_options,a_sql); + l_cov_sources_crsr := get_cov_sources_cursor(a_coverage_options); 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); @@ -151,16 +223,17 @@ create or replace package body ut_coverage is /** * Public functions */ - procedure coverage_start(a_coverage_options ut_coverage_options default null) is + procedure coverage_start(a_coverage_run_id t_coverage_run_id) is l_run_comment varchar2(200) := 'utPLSQL Code coverage run '||ut_utils.to_string(systimestamp); + l_line_coverage_id integer; + l_block_coverage_id integer; begin if not is_develop_mode() and not g_is_started then - $if dbms_db_version.version = 12 and dbms_db_version.release >= 2 or dbms_db_version.version > 12 $then - ut_coverage_helper_block.coverage_start( l_run_comment, g_coverage_id(gc_block_coverage) ); - $end - ut_coverage_helper_profiler.coverage_start( l_run_comment, g_coverage_id(gc_proftab_coverage) ); - coverage_pause(); + g_coverage_run_id := a_coverage_run_id; + l_line_coverage_id := ut_coverage_helper_profiler.coverage_start( l_run_comment ); + l_block_coverage_id := ut_coverage_helper_block.coverage_start( l_run_comment ); g_is_started := true; + ut_coverage_helper.set_coverage_run_ids(a_coverage_run_id, l_line_coverage_id, l_block_coverage_id); end if; end; @@ -176,84 +249,79 @@ create or replace package body ut_coverage is ut_coverage_helper_profiler.coverage_resume(); end; - procedure mock_coverage_id(a_coverage_id integer,a_coverage_type in varchar2) is - begin - g_develop_mode := true; - g_is_started := true; - g_coverage_id(a_coverage_type) := a_coverage_id; - end; - - procedure mock_coverage_id(a_coverage_id tt_coverage_id_arr) is - begin - g_develop_mode := true; - g_is_started := true; - g_coverage_id := a_coverage_id; - end; - procedure coverage_stop is begin if not is_develop_mode() then g_is_started := false; - $if dbms_db_version.version = 12 and dbms_db_version.release >= 2 or dbms_db_version.version > 12 $then + g_coverage_run_id := null; ut_coverage_helper_block.coverage_stop(); - $end ut_coverage_helper_profiler.coverage_stop(); - g_is_started := false; end if; end; function get_coverage_data(a_coverage_options ut_coverage_options) return t_coverage is l_result_block ut_coverage.t_coverage; l_result_profiler_enrich ut_coverage.t_coverage; - l_object ut_coverage.t_full_name; + l_object ut_coverage.t_object_name; l_line_no binary_integer; + l_coverage_options ut_coverage_options := a_coverage_options; begin --prepare global temp table with sources - populate_tmp_table(a_coverage_options, get_cov_sources_sql(a_coverage_options)); + ut_event_manager.trigger_event('about to populate coverage temp table'); + populate_tmp_table(l_coverage_options); + ut_event_manager.trigger_event('coverage temp table populated'); -- Get raw data for both reporters, order is important as tmp table will skip headers and dont populate -- tmp table for block again. - l_result_profiler_enrich:= ut_coverage_profiler.get_coverage_data( a_coverage_options, get_coverage_id(gc_proftab_coverage) ); - - -- If block coverage available we will use it. - $if dbms_db_version.version = 12 and dbms_db_version.release >= 2 or dbms_db_version.version > 12 $then - l_result_block := ut_coverage_block.get_coverage_data( a_coverage_options, get_coverage_id(gc_block_coverage) ); - - -- Enrich profiler results with some of the block results - l_object := l_result_profiler_enrich.objects.first; - while (l_object is not null) - loop - - l_line_no := l_result_profiler_enrich.objects(l_object).lines.first; - - -- to avoid no data found check if we got object in profiler - if l_result_block.objects.exists(l_object) then - while (l_line_no is not null) - loop - -- To avoid no data check for object line - if l_result_block.objects(l_object).lines.exists(l_line_no) then - -- enrich line level stats - l_result_profiler_enrich.objects(l_object).lines(l_line_no).partcove := l_result_block.objects(l_object).lines(l_line_no).partcove; - l_result_profiler_enrich.objects(l_object).lines(l_line_no).covered_blocks := l_result_block.objects(l_object).lines(l_line_no).covered_blocks; - l_result_profiler_enrich.objects(l_object).lines(l_line_no).no_blocks := l_result_block.objects(l_object).lines(l_line_no).no_blocks; - -- enrich object level stats - l_result_profiler_enrich.objects(l_object).partcovered_lines := nvl(l_result_profiler_enrich.objects(l_object).partcovered_lines,0) + l_result_block.objects(l_object).lines(l_line_no).partcove; + l_result_profiler_enrich := ut_coverage_profiler.get_coverage_data( l_coverage_options ); + ut_event_manager.trigger_event('profiler coverage data retrieved'); + + -- If block coverage available we will use it. + $if dbms_db_version.version = 12 and dbms_db_version.release >= 2 or dbms_db_version.version > 12 $then + l_result_block := ut_coverage_block.get_coverage_data( l_coverage_options ); + ut_event_manager.trigger_event('block coverage data retrieved'); + + -- Enrich profiler results with some of the block results + l_object := l_result_profiler_enrich.objects.first; + while (l_object is not null) loop + + l_line_no := l_result_profiler_enrich.objects(l_object).lines.first; + + -- to avoid no data found check if we got object in profiler + if l_result_block.objects.exists(l_object) then + while (l_line_no is not null) loop + -- To avoid no data check for object line + if l_result_block.objects(l_object).lines.exists(l_line_no) then + -- enrich line level stats + l_result_profiler_enrich.objects(l_object).lines(l_line_no).partcove := l_result_block.objects(l_object).lines(l_line_no).partcove; + l_result_profiler_enrich.objects(l_object).lines(l_line_no).covered_blocks := l_result_block.objects(l_object).lines(l_line_no).covered_blocks; + l_result_profiler_enrich.objects(l_object).lines(l_line_no).no_blocks := l_result_block.objects(l_object).lines(l_line_no).no_blocks; + -- enrich object level stats + l_result_profiler_enrich.objects(l_object).partcovered_lines := nvl(l_result_profiler_enrich.objects(l_object).partcovered_lines,0) + l_result_block.objects(l_object).lines(l_line_no).partcove; + end if; + --At the end go to next line + l_line_no := l_result_profiler_enrich.objects(l_object).lines.next(l_line_no); + end loop; + --total level stats enrich + l_result_profiler_enrich.partcovered_lines := nvl(l_result_profiler_enrich.partcovered_lines,0) + l_result_profiler_enrich.objects(l_object).partcovered_lines; + -- At the end go to next object end if; - --At the end go to next line - l_line_no := l_result_profiler_enrich.objects(l_object).lines.next(l_line_no); - end loop; - --total level stats enrich - l_result_profiler_enrich.partcovered_lines := nvl(l_result_profiler_enrich.partcovered_lines,0) + l_result_profiler_enrich.objects(l_object).partcovered_lines; - -- At the end go to next object - end if; - - l_object := l_result_profiler_enrich.objects.next(l_object); - - end loop; - $end + + l_object := l_result_profiler_enrich.objects.next(l_object); + end loop; + ut_event_manager.trigger_event('coverage data combined'); + $end return l_result_profiler_enrich; - end get_coverage_data; + end get_coverage_data; + + function get_coverage_run_id return raw is + begin + if g_coverage_run_id is null then + g_coverage_run_id := sys_guid(); + end if; + return g_coverage_run_id; + end; end; / diff --git a/source/core/coverage/ut_coverage.pks b/source/core/coverage/ut_coverage.pks index b291f4b26..21f3b1f9e 100644 --- a/source/core/coverage/ut_coverage.pks +++ b/source/core/coverage/ut_coverage.pks @@ -1,7 +1,7 @@ create or replace package ut_coverage authid current_user is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -16,26 +16,21 @@ create or replace package ut_coverage authid current_user is limitations under the License. */ - gc_proftab_coverage constant varchar2(32) := 'proftab'; - gc_block_coverage constant varchar2(32) := 'block'; - gc_extended_coverage constant varchar2(32) := 'extended'; - - type tt_coverage_id_arr is table of integer index by varchar2(30); + subtype t_coverage_run_id is raw(32) not null; -- total run coverage information - subtype t_full_name is varchar2(4000); - subtype t_object_name is varchar2(250); - - --subtype t_line_executions is binary_integer; + subtype t_object_name is varchar2(257); + subtype t_line_no is binary_integer; type t_line_executions is record( - executions binary_integer - ,partcove binary_integer - ,no_blocks binary_integer + executions binary_integer + ,partcove binary_integer + ,no_blocks binary_integer ,covered_blocks binary_integer); + -- line coverage information indexed by line no. - --type tt_lines is table of t_line_executions index by binary_integer; - type tt_lines is table of t_line_executions index by binary_integer; + type tt_lines is table of t_line_executions index by t_line_no; + --unit coverage information record type t_unit_coverage is record( owner varchar2(128) @@ -51,7 +46,7 @@ create or replace package ut_coverage authid current_user is ,lines tt_lines); -- coverage information indexed by full object name (schema.object) - type tt_program_units is table of t_unit_coverage index by t_full_name; + type tt_program_units is table of t_unit_coverage index by t_object_name; -- total run coverage information type t_coverage is record( @@ -65,21 +60,11 @@ create or replace package ut_coverage authid current_user is ,executions number(38, 0) := 0 ,objects tt_program_units); - function get_coverage_id(a_coverage_type in varchar2) return integer; - procedure set_develop_mode(a_develop_mode in boolean); function is_develop_mode return boolean; - /*** - * Allows overwriting of private global variable g_coverage_id - * Used internally, only for unit testing of the framework only - */ - procedure mock_coverage_id(a_coverage_id integer,a_coverage_type in varchar2); - - procedure mock_coverage_id(a_coverage_id tt_coverage_id_arr); - - procedure coverage_start(a_coverage_options ut_coverage_options default null); + procedure coverage_start(a_coverage_run_id t_coverage_run_id); procedure coverage_stop; @@ -89,5 +74,7 @@ create or replace package ut_coverage authid current_user is function get_coverage_data(a_coverage_options ut_coverage_options) return t_coverage; + function get_coverage_run_id return raw; + end; / diff --git a/source/core/coverage/ut_coverage_block.pkb b/source/core/coverage/ut_coverage_block.pkb index 7da62ff80..a906b81a3 100644 --- a/source/core/coverage/ut_coverage_block.pkb +++ b/source/core/coverage/ut_coverage_block.pkb @@ -1,7 +1,7 @@ create or replace package body ut_coverage_block is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ create or replace package body ut_coverage_block is * Public functions */ - function get_coverage_data(a_coverage_options ut_coverage_options, a_coverage_id integer) return ut_coverage.t_coverage is + function get_coverage_data(a_coverage_options ut_coverage_options) return ut_coverage.t_coverage is l_line_calls ut_coverage_helper.t_unit_line_calls; l_result ut_coverage.t_coverage; l_new_unit ut_coverage.t_unit_coverage; @@ -32,6 +32,7 @@ create or replace package body ut_coverage_block is l_source_object ut_coverage_helper.t_tmp_table_object; begin + $if dbms_db_version.version = 12 and dbms_db_version.release >= 2 or dbms_db_version.version > 12 $then l_source_objects_crsr := ut_coverage_helper.get_tmp_table_objects_cursor(); loop fetch l_source_objects_crsr @@ -39,7 +40,7 @@ create or replace package body ut_coverage_block is exit when l_source_objects_crsr%notfound; --get coverage data - l_line_calls := ut_coverage_helper_block.get_raw_coverage_data(l_source_object.owner, l_source_object.name, a_coverage_id); + l_line_calls := ut_coverage_helper_block.get_raw_coverage_data(l_source_object, a_coverage_options.coverage_run_id); --if there is coverage, we need to filter out the garbage (badly indicated data) if l_line_calls.count > 0 then --remove lines that should not be indicted as meaningful @@ -150,7 +151,8 @@ create or replace package body ut_coverage_block is end loop; close l_source_objects_crsr; - + $end + return l_result; end get_coverage_data; diff --git a/source/core/coverage/ut_coverage_block.pks b/source/core/coverage/ut_coverage_block.pks index fdce622a5..01caca035 100644 --- a/source/core/coverage/ut_coverage_block.pks +++ b/source/core/coverage/ut_coverage_block.pks @@ -1,7 +1,7 @@ create or replace package ut_coverage_block authid current_user is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ create or replace package ut_coverage_block authid current_user is limitations under the License. */ - function get_coverage_data(a_coverage_options ut_coverage_options, a_coverage_id integer) return ut_coverage.t_coverage; + function get_coverage_data(a_coverage_options ut_coverage_options) return ut_coverage.t_coverage; end; / diff --git a/source/core/coverage/ut_coverage_helper.pkb b/source/core/coverage/ut_coverage_helper.pkb index cfa3e413c..e249b3381 100644 --- a/source/core/coverage/ut_coverage_helper.pkb +++ b/source/core/coverage/ut_coverage_helper.pkb @@ -1,7 +1,7 @@ create or replace package body ut_coverage_helper is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -35,23 +35,21 @@ create or replace package body ut_coverage_helper is procedure insert_into_tmp_table(a_data t_coverage_sources_tmp_rows) is begin forall i in 1 .. a_data.count - insert into ut_coverage_sources_tmp - (full_name,owner,name,line,text, to_be_skipped) - values(a_data(i).full_name,a_data(i).owner,a_data(i).name,a_data(i).line,a_data(i).text,a_data(i).to_be_skipped); + insert /*+ no_parallel */ into ut_coverage_sources_tmp + (full_name,owner,name,type,line,text,to_be_skipped) + values(a_data(i).full_name,a_data(i).owner,a_data(i).name,a_data(i).type,a_data(i).line,a_data(i).text,a_data(i).to_be_skipped); end; procedure cleanup_tmp_table is pragma autonomous_transaction; begin - null; - execute immediate 'truncate table ut_coverage_sources_tmp$'; - commit; + execute immediate 'truncate table ut_coverage_sources_tmp'; end; function is_tmp_table_populated return boolean is l_result integer; begin - select 1 into l_result from ut_coverage_sources_tmp where rownum = 1; + select /*+ no_parallel */ 1 into l_result from ut_coverage_sources_tmp where rownum = 1; return (l_result = 1); exception when no_data_found then @@ -62,12 +60,12 @@ create or replace package body ut_coverage_helper is l_result t_tmp_table_objects_crsr; begin open l_result for - select o.owner, o.name, o.full_name, max(o.line) lines_count, + select /*+ no_parallel */ o.owner, o.name, o.type, o.full_name, max(o.line) as lines_count, cast( collect(decode(to_be_skipped, 'Y', to_char(line))) as ut_varchar2_list - ) to_be_skipped_list + ) as to_be_skipped_list from ut_coverage_sources_tmp o - group by o.owner, o.name, o.full_name; + group by o.owner, o.name, o.type, o.full_name; return l_result; end; @@ -75,7 +73,7 @@ create or replace package body ut_coverage_helper is function get_tmp_table_object_lines(a_owner varchar2, a_object_name varchar2) return ut_varchar2_list is l_result ut_varchar2_list; begin - select rtrim(s.text,chr(10)) text + select /*+ no_parallel */ rtrim(s.text,chr(10)) as text bulk collect into l_result from ut_coverage_sources_tmp s where s.owner = a_owner @@ -85,5 +83,15 @@ create or replace package body ut_coverage_helper is return l_result; end; + procedure set_coverage_run_ids( a_coverage_run_id raw, a_line_coverage_id integer, a_block_coverage_id integer ) is + pragma autonomous_transaction; + begin + insert /*+ no_parallel */ into ut_coverage_runs + ( coverage_run_id, line_coverage_id, block_coverage_id ) + values + ( a_coverage_run_id, a_line_coverage_id, a_block_coverage_id ); + commit; + end; + end; / diff --git a/source/core/coverage/ut_coverage_helper.pks b/source/core/coverage/ut_coverage_helper.pks index 014e7b471..cd6ed9ec7 100644 --- a/source/core/coverage/ut_coverage_helper.pks +++ b/source/core/coverage/ut_coverage_helper.pks @@ -1,7 +1,7 @@ create or replace package ut_coverage_helper authid definer is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -32,6 +32,7 @@ create or replace package ut_coverage_helper authid definer is full_name ut_coverage_sources_tmp.full_name%type, owner ut_coverage_sources_tmp.owner%type, name ut_coverage_sources_tmp.name%type, + type ut_coverage_sources_tmp.type%type, line ut_coverage_sources_tmp.line%type, to_be_skipped ut_coverage_sources_tmp.to_be_skipped%type, text ut_coverage_sources_tmp.text%type @@ -42,6 +43,7 @@ create or replace package ut_coverage_helper authid definer is type t_tmp_table_object is record( owner ut_coverage_sources_tmp.owner%type, name ut_coverage_sources_tmp.name%type, + type ut_coverage_sources_tmp.type%type, full_name ut_coverage_sources_tmp.full_name%type, lines_count integer, to_be_skipped_list ut_varchar2_list @@ -59,5 +61,7 @@ create or replace package ut_coverage_helper authid definer is function get_tmp_table_object_lines(a_owner varchar2, a_object_name varchar2) return ut_varchar2_list; + procedure set_coverage_run_ids( a_coverage_run_id raw, a_line_coverage_id integer, a_block_coverage_id integer ); + end; / diff --git a/source/core/coverage/ut_coverage_helper_block.pkb b/source/core/coverage/ut_coverage_helper_block.pkb index 865576b3e..fb4d4812e 100644 --- a/source/core/coverage/ut_coverage_helper_block.pkb +++ b/source/core/coverage/ut_coverage_helper_block.pkb @@ -1,7 +1,7 @@ create or replace package body ut_coverage_helper_block is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -16,13 +16,6 @@ create or replace package body ut_coverage_helper_block is limitations under the License. */ - type t_proftab_row is record ( - line binary_integer, - calls number(38,0) - ); - - type t_proftab_rows is table of t_proftab_row; - type t_block_row is record( line binary_integer ,blocks binary_integer @@ -30,62 +23,88 @@ create or replace package body ut_coverage_helper_block is type t_block_rows is table of t_block_row; - procedure coverage_start(a_run_comment varchar2, a_coverage_id out integer) is + function coverage_start(a_run_comment varchar2) return integer is begin - a_coverage_id := dbms_plsql_code_coverage.start_coverage(run_comment => a_run_comment); + $if dbms_db_version.version = 12 and dbms_db_version.release >= 2 or dbms_db_version.version > 12 $then + return dbms_plsql_code_coverage.start_coverage(run_comment => a_run_comment); + $else + return null; + $end end; procedure coverage_stop is begin - dbms_plsql_code_coverage.stop_coverage(); + $if dbms_db_version.version = 12 and dbms_db_version.release >= 2 or dbms_db_version.version > 12 $then + dbms_plsql_code_coverage.stop_coverage(); + $else + null; + $end + exception + when others then + if sqlcode = -08402 then + dbms_output.put_line('Unable to finish gathering coverage with DBMS_PLSQL_CODE_COVERAGE. '); + dbms_output.put_line('Encountered exception `ORA-08402` when calling procedure `DBMS_PLSQL_CODE_COVERAGE.STOP_COVERAGE()`.'); + dbms_output.put_line('Coverage report will only include line-level code-coverage (without branches).'); + dbms_output.put_line('Please reference following issue for details on possible causes: https://github.com/utPLSQL/utPLSQL/issues/1097 '); + end if; end; - function block_results(a_object_owner varchar2, a_object_name varchar2, a_coverage_id integer) return t_block_rows is - l_raw_coverage sys_refcursor; + function block_results(a_object ut_coverage_helper.t_tmp_table_object, a_coverage_run_id raw) return t_block_rows is l_coverage_rows t_block_rows; - l_ut3_owner varchar2(128) := ut_utils.ut_owner(); + l_ut_owner varchar2(250) := ut_utils.ut_owner; begin - - open l_raw_coverage for 'select ccb.line - ,count(ccb.block) totalblocks - ,sum(ccb.covered) - from dbmspcc_units ccu - left outer join dbmspcc_blocks ccb - on ccu.run_id = ccb.run_id - and ccu.object_id = ccb.object_id - where ccu.run_id = :a_coverage_id - and ccu.owner = :a_object_owner - and ccu.name = :a_object_name - group by ccb.line - order by 1' using a_coverage_id,a_object_owner,a_object_name; - - fetch l_raw_coverage bulk collect into l_coverage_rows; - close l_raw_coverage; + execute immediate q'[ + select /*+ no_parallel */ + line as line, + count(block) as blocks, + sum(covered) as covered_blocks + from (select line, + block, + max(covered) as covered + from dbmspcc_units ccu + join ]'||l_ut_owner||q'[.ut_coverage_runs r + on r.block_coverage_id = ccu.run_id + left join dbmspcc_blocks ccb + on ccu.run_id = ccb.run_id + and ccu.object_id = ccb.object_id + where r.coverage_run_id = :a_coverage_run_id + and ccu.owner = :a_object_owner + and ccu.name = :a_object_name + and ccu.type = :a_object_type + group by ccb.line, ccb.block + ) + group by line + having count(block) > 1 + order by line]' + bulk collect into l_coverage_rows + using + a_coverage_run_id, a_object.owner, + a_object.name, a_object.type; - return l_coverage_rows; + return l_coverage_rows; end; - function get_raw_coverage_data(a_object_owner varchar2, a_object_name varchar2, a_coverage_id integer) return ut_coverage_helper.t_unit_line_calls is + function get_raw_coverage_data(a_object ut_coverage_helper.t_tmp_table_object, a_coverage_run_id raw) return ut_coverage_helper.t_unit_line_calls is l_tmp_data t_block_rows; l_results ut_coverage_helper.t_unit_line_calls; begin - l_tmp_data := block_results(a_object_owner, a_object_name, a_coverage_id); - - for i in 1 .. l_tmp_data.count loop - l_results(l_tmp_data(i).line).blocks := l_tmp_data(i).blocks; - l_results(l_tmp_data(i).line).covered_blocks := l_tmp_data(i).covered_blocks; - l_results(l_tmp_data(i).line).partcovered := case - when (l_tmp_data(i).covered_blocks > 0) and - (l_tmp_data(i).blocks > l_tmp_data(i).covered_blocks) then - 1 - else - 0 - end; - end loop; + $if dbms_db_version.version = 12 and dbms_db_version.release >= 2 or dbms_db_version.version > 12 $then + l_tmp_data := block_results(a_object, a_coverage_run_id); + + for i in 1 .. l_tmp_data.count loop + l_results(l_tmp_data(i).line).blocks := l_tmp_data(i).blocks; + l_results(l_tmp_data(i).line).covered_blocks := l_tmp_data(i).covered_blocks; + l_results(l_tmp_data(i).line).partcovered := + case + when (l_tmp_data(i).covered_blocks > 0) + and (l_tmp_data(i).blocks > l_tmp_data(i).covered_blocks) + then 1 + else 0 + end; + end loop; + $end return l_results; end; - - end; / diff --git a/source/core/coverage/ut_coverage_helper_block.pks b/source/core/coverage/ut_coverage_helper_block.pks index 0b71b7067..a147d9f4f 100644 --- a/source/core/coverage/ut_coverage_helper_block.pks +++ b/source/core/coverage/ut_coverage_helper_block.pks @@ -1,7 +1,7 @@ create or replace package ut_coverage_helper_block authid current_user is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -16,11 +16,11 @@ create or replace package ut_coverage_helper_block authid current_user is limitations under the License. */ - procedure coverage_start(a_run_comment in varchar2,a_coverage_id out integer); + function coverage_start(a_run_comment in varchar2) return integer; procedure coverage_stop; - function get_raw_coverage_data(a_object_owner varchar2, a_object_name varchar2, a_coverage_id integer) return ut_coverage_helper.t_unit_line_calls; + function get_raw_coverage_data(a_object ut_coverage_helper.t_tmp_table_object, a_coverage_run_id raw) return ut_coverage_helper.t_unit_line_calls; end; / diff --git a/source/core/coverage/ut_coverage_helper_profiler.pkb b/source/core/coverage/ut_coverage_helper_profiler.pkb index 340a28ca3..f29291efb 100644 --- a/source/core/coverage/ut_coverage_helper_profiler.pkb +++ b/source/core/coverage/ut_coverage_helper_profiler.pkb @@ -1,7 +1,7 @@ create or replace package body ut_coverage_helper_profiler is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -31,9 +31,11 @@ create or replace package body ut_coverage_helper_profiler is type t_block_rows is table of t_block_row; - procedure coverage_start(a_run_comment varchar2,a_coverage_id out integer) is + function coverage_start(a_run_comment varchar2) return integer is + l_coverage_id integer; begin - dbms_profiler.start_profiler(run_comment => a_run_comment, run_number => a_coverage_id); + dbms_profiler.start_profiler(run_comment => a_run_comment, run_number => l_coverage_id); + return l_coverage_id; end; procedure coverage_pause is @@ -53,34 +55,33 @@ create or replace package body ut_coverage_helper_profiler is dbms_profiler.stop_profiler(); end; - function proftab_results(a_object_owner varchar2, a_object_name varchar2, a_coverage_id integer) return t_proftab_rows is - l_raw_coverage sys_refcursor; - l_coverage_rows t_proftab_rows; + function proftab_results(a_object ut_coverage_helper.t_tmp_table_object, a_coverage_run_id raw) return t_proftab_rows is + l_coverage_rows t_proftab_rows; begin - open l_raw_coverage for q'[select d.line#, + select /*+ no_parallel */ + d.line#, case when sum(d.total_occur) = 0 and sum(d.total_time) > 0 then 1 else sum(d.total_occur) end total_occur - from plsql_profiler_units u - join plsql_profiler_data d - on u.runid = d.runid - and u.unit_number = d.unit_number - where u.runid = :a_coverage_id - and u.unit_owner = :a_object_owner - and u.unit_name = :a_object_name - and u.unit_type not in ('PACKAGE SPEC', 'TYPE SPEC', 'ANONYMOUS BLOCK') - group by d.line#]' using a_coverage_id,a_object_owner,a_object_name; - - FETCH l_raw_coverage BULK COLLECT - INTO l_coverage_rows; - CLOSE l_raw_coverage; + bulk collect into l_coverage_rows + from plsql_profiler_units u + join plsql_profiler_data d + on u.runid = d.runid + and u.unit_number = d.unit_number + join ut_coverage_runs r + on r.line_coverage_id = u.runid + where r.coverage_run_id = a_coverage_run_id + and u.unit_owner = a_object.owner + and u.unit_name = a_object.name + and u.unit_type = a_object.type + group by d.line#; - RETURN l_coverage_rows; + return l_coverage_rows; end; - function get_raw_coverage_data(a_object_owner varchar2, a_object_name varchar2, a_coverage_id integer) return ut_coverage_helper.t_unit_line_calls is + function get_raw_coverage_data(a_object ut_coverage_helper.t_tmp_table_object, a_coverage_run_id raw) return ut_coverage_helper.t_unit_line_calls is l_tmp_data t_proftab_rows; l_results ut_coverage_helper.t_unit_line_calls; begin - l_tmp_data := proftab_results(a_object_owner, a_object_name, a_coverage_id); + l_tmp_data := proftab_results(a_object, a_coverage_run_id); for i in 1 .. l_tmp_data.count loop l_results(l_tmp_data(i).line).calls := l_tmp_data(i).calls; diff --git a/source/core/coverage/ut_coverage_helper_profiler.pks b/source/core/coverage/ut_coverage_helper_profiler.pks index db91326eb..0c54a83bf 100644 --- a/source/core/coverage/ut_coverage_helper_profiler.pks +++ b/source/core/coverage/ut_coverage_helper_profiler.pks @@ -1,7 +1,7 @@ create or replace package ut_coverage_helper_profiler authid definer is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ create or replace package ut_coverage_helper_profiler authid definer is limitations under the License. */ - procedure coverage_start(a_run_comment in varchar2,a_coverage_id out integer); + function coverage_start(a_run_comment in varchar2) return integer; procedure coverage_stop; @@ -24,7 +24,7 @@ create or replace package ut_coverage_helper_profiler authid definer is procedure coverage_resume; - function get_raw_coverage_data(a_object_owner varchar2, a_object_name varchar2, a_coverage_id integer) return ut_coverage_helper.t_unit_line_calls; + function get_raw_coverage_data(a_object ut_coverage_helper.t_tmp_table_object, a_coverage_run_id raw) return ut_coverage_helper.t_unit_line_calls; end; / diff --git a/source/core/coverage/ut_coverage_profiler.pkb b/source/core/coverage/ut_coverage_profiler.pkb index e4c9ab0af..663ceab7f 100644 --- a/source/core/coverage/ut_coverage_profiler.pkb +++ b/source/core/coverage/ut_coverage_profiler.pkb @@ -1,7 +1,7 @@ create or replace package body ut_coverage_profiler is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ create or replace package body ut_coverage_profiler is /** * Public functions */ - function get_coverage_data(a_coverage_options ut_coverage_options, a_coverage_id integer) return ut_coverage.t_coverage is + function get_coverage_data(a_coverage_options ut_coverage_options) return ut_coverage.t_coverage is l_line_calls ut_coverage_helper.t_unit_line_calls; l_result ut_coverage.t_coverage; l_new_unit ut_coverage.t_unit_coverage; @@ -34,7 +34,7 @@ create or replace package body ut_coverage_profiler is exit when l_source_objects_crsr%notfound; --get coverage data - l_line_calls := ut_coverage_helper_profiler.get_raw_coverage_data( l_source_object.owner, l_source_object.name, a_coverage_id); + l_line_calls := ut_coverage_helper_profiler.get_raw_coverage_data( l_source_object, a_coverage_options.coverage_run_id); --if there is coverage, we need to filter out the garbage (badly indicated data from dbms_profiler) if l_line_calls.count > 0 then diff --git a/source/core/coverage/ut_coverage_profiler.pks b/source/core/coverage/ut_coverage_profiler.pks index 4e4b8d9c0..9ce9a27f0 100644 --- a/source/core/coverage/ut_coverage_profiler.pks +++ b/source/core/coverage/ut_coverage_profiler.pks @@ -1,7 +1,7 @@ create or replace package ut_coverage_profiler authid current_user is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ create or replace package ut_coverage_profiler authid current_user is limitations under the License. */ - function get_coverage_data(a_coverage_options ut_coverage_options, a_coverage_id integer) return ut_coverage.t_coverage; + function get_coverage_data(a_coverage_options ut_coverage_options) return ut_coverage.t_coverage; end; / diff --git a/source/core/coverage/ut_coverage_reporter_base.tpb b/source/core/coverage/ut_coverage_reporter_base.tpb index 9e339347f..da2bd27ad 100644 --- a/source/core/coverage/ut_coverage_reporter_base.tpb +++ b/source/core/coverage/ut_coverage_reporter_base.tpb @@ -1,7 +1,7 @@ create or replace type body ut_coverage_reporter_base is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -19,7 +19,8 @@ create or replace type body ut_coverage_reporter_base is overriding final member procedure before_calling_run(self in out nocopy ut_coverage_reporter_base, a_run ut_run) as begin (self as ut_output_reporter_base).before_calling_run(a_run); - ut_coverage.coverage_start(a_coverage_options => a_run.coverage_options); + ut_coverage.coverage_start(a_coverage_run_id => a_run.coverage_options.coverage_run_id); + ut_coverage.coverage_pause(); end; overriding final member procedure before_calling_before_all(self in out nocopy ut_coverage_reporter_base, a_executable in ut_executable) is @@ -85,5 +86,28 @@ create or replace type body ut_coverage_reporter_base is ut_coverage.coverage_pause(); end; + final member function get_report( a_coverage_options ut_coverage_options, a_client_character_set varchar2 := null ) return ut_varchar2_rows pipelined is + l_reporter ut_coverage_reporter_base := self; + begin + ut_coverage_helper.cleanup_tmp_table(); + (l_reporter as ut_output_reporter_base).before_calling_run(null); + l_reporter.after_calling_run( ut_run( a_coverage_options => a_coverage_options, a_client_character_set => a_client_character_set ) ); + for i in (select /*+ no_parallel */ x.text from table(l_reporter.get_lines(1, 1)) x ) loop + pipe row (i.text); + end loop; + return; + end; + + final member function get_report_cursor( a_coverage_options ut_coverage_options, a_client_character_set varchar2 := null ) return sys_refcursor is + l_reporter ut_coverage_reporter_base := self; + l_result sys_refcursor; + begin + ut_coverage_helper.cleanup_tmp_table(); + (l_reporter as ut_output_reporter_base).before_calling_run(null); + l_reporter.after_calling_run( ut_run( a_coverage_options => a_coverage_options, a_client_character_set => a_client_character_set ) ); + open l_result for select /*+ no_parallel */ x.text from table(l_reporter.get_lines(1, 1)) x; + return l_result; + end; + end; / diff --git a/source/core/coverage/ut_coverage_reporter_base.tps b/source/core/coverage/ut_coverage_reporter_base.tps index 76206dd95..305c5d757 100644 --- a/source/core/coverage/ut_coverage_reporter_base.tps +++ b/source/core/coverage/ut_coverage_reporter_base.tps @@ -1,7 +1,7 @@ create or replace type ut_coverage_reporter_base under ut_output_reporter_base( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -36,8 +36,9 @@ create or replace type ut_coverage_reporter_base under ut_output_reporter_base( overriding final member procedure after_calling_after_each (self in out nocopy ut_coverage_reporter_base, a_executable in ut_executable), overriding final member procedure before_calling_after_all(self in out nocopy ut_coverage_reporter_base, a_executable in ut_executable), - overriding final member procedure after_calling_after_all (self in out nocopy ut_coverage_reporter_base, a_executable in ut_executable) - + overriding final member procedure after_calling_after_all (self in out nocopy ut_coverage_reporter_base, a_executable in ut_executable), + final member function get_report( a_coverage_options ut_coverage_options, a_client_character_set varchar2 := null ) return ut_varchar2_rows pipelined, + final member function get_report_cursor( a_coverage_options ut_coverage_options, a_client_character_set varchar2 := null ) return sys_refcursor ) not final not instantiable / diff --git a/source/core/coverage/ut_coverage_runs.sql b/source/core/coverage/ut_coverage_runs.sql new file mode 100644 index 000000000..78230240d --- /dev/null +++ b/source/core/coverage/ut_coverage_runs.sql @@ -0,0 +1,20 @@ +declare + l_tab_exist number; +begin + select count(*) into l_tab_exist + from all_tables + where table_name = 'UT_COVERAGE_RUNS' and owner = sys_context('USERENV','CURRENT_SCHEMA'); + if l_tab_exist = 0 then + execute immediate q'[create table ut_coverage_runs + ( + coverage_run_id raw(32) not null, + line_coverage_id number(38,0) unique not null, + block_coverage_id number(38,0) unique, + constraint ut_coverage_runs primary key (coverage_run_id, line_coverage_id) + ) organization index ]'; + execute immediate q'[comment on table ut_coverage_runs is + 'Map of block and line coverage runs for a test-run']'; + dbms_output.put_line('UT_COVERAGE_RUNS table created'); + end if; +end; +/ diff --git a/source/core/coverage/ut_coverage_sources_tmp.sql b/source/core/coverage/ut_coverage_sources_tmp.sql index bcc661a22..c091d5955 100644 --- a/source/core/coverage/ut_coverage_sources_tmp.sql +++ b/source/core/coverage/ut_coverage_sources_tmp.sql @@ -1,7 +1,7 @@ -create global temporary table ut_coverage_sources_tmp$( +create global temporary table ut_coverage_sources_tmp( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 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 @@ -15,52 +15,12 @@ create global temporary table ut_coverage_sources_tmp$( full_name varchar2(4000), owner varchar2(250), name varchar2(250), + type varchar2(250), line number(38,0), to_be_skipped varchar2(1), text varchar2(4000), - constraint ut_coverage_sources_tmp_pk primary key (owner,name,line) + constraint ut_coverage_sources_tmp_pk primary key (owner,name,type,line) ) on commit preserve rows; -create unique index ut_coverage_sources_tmp_uk on ut_coverage_sources_tmp$ (owner,name,to_be_skipped, line); - -declare - ex_nonedition_user exception; - ex_view_doesnt_exist exception; - pragma exception_init(ex_nonedition_user,-42314); - pragma exception_init(ex_view_doesnt_exist,-942); - v_view_source varchar2(32767); -begin - begin - execute immediate 'drop view ut_coverage_sources_tmp'; - exception - when ex_view_doesnt_exist then - null; - end; - v_view_source := ' ut_coverage_sources_tmp 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. -*/ -select full_name - ,owner - ,name - ,line - ,to_be_skipped - ,text - from ut_coverage_sources_tmp$'; - - execute immediate 'create or replace editioning view '||v_view_source; -exception - when ex_nonedition_user then - execute immediate 'create or replace view '||v_view_source; -end; -/ +--is this needed? +--create unique index ut_coverage_sources_tmp_uk on ut_coverage_sources_tmp$ (owner,name,to_be_skipped, line); diff --git a/source/core/events/ut_event_item.tps b/source/core/events/ut_event_item.tps index 398cc2ac0..c0ea653ea 100644 --- a/source/core/events/ut_event_item.tps +++ b/source/core/events/ut_event_item.tps @@ -1,7 +1,7 @@ create or replace type ut_event_item authid current_user as object ( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -21,6 +21,5 @@ create or replace type ut_event_item authid current_user as object ( * The true abstract type is ut_suite_item */ self_type varchar2(250 byte) - ) not final not instantiable / diff --git a/source/core/events/ut_event_listener.tps b/source/core/events/ut_event_listener.tps index fd6ae0486..bbcdbf218 100644 --- a/source/core/events/ut_event_listener.tps +++ b/source/core/events/ut_event_listener.tps @@ -1,7 +1,7 @@ create or replace type ut_event_listener authid current_user as object ( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/events/ut_event_manager.pkb b/source/core/events/ut_event_manager.pkb index 7ae0ad0b3..f51019421 100644 --- a/source/core/events/ut_event_manager.pkb +++ b/source/core/events/ut_event_manager.pkb @@ -1,7 +1,7 @@ create or replace package body ut_event_manager as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -21,24 +21,67 @@ create or replace package body ut_event_manager as type t_listener_numbers is table of boolean index by t_listener_number; type t_events_listeners is table of t_listener_numbers index by t_event_name; - g_event_listeners_index t_events_listeners; - g_listeners t_listeners; + type t_event_manager is record ( + event_listener_index t_events_listeners, + listeners t_listeners + ); + type t_event_managers is table of t_event_manager; + + g_event_listeners_index t_events_listeners; + g_listeners t_listeners; + g_suspended_event_managers t_event_managers; procedure initialize is begin + if g_listeners is not null and g_listeners.count > 0 then + if g_suspended_event_managers is null then + g_suspended_event_managers := t_event_managers(); + end if; + g_suspended_event_managers.extend; + g_suspended_event_managers(g_suspended_event_managers.count).event_listener_index := g_event_listeners_index; + g_suspended_event_managers(g_suspended_event_managers.count).listeners := g_listeners; + end if; g_event_listeners_index.delete; g_listeners := t_listeners(); end; - procedure trigger_event( a_event_name t_event_name, a_event_object ut_event_item ) is + procedure dispose_listeners is begin - if a_event_name is not null and g_event_listeners_index.exists(a_event_name) - -- disabled due to compiler warning: PLW-06023: invocation of IS NOT NULL computes trivial value --- and g_event_listeners_index(a_event_name) is not null - then - for listener_number in 1 .. g_event_listeners_index(a_event_name).count loop - g_listeners(listener_number).on_event(a_event_name, a_event_object); + if g_suspended_event_managers is not null and g_suspended_event_managers.count > 0 then + g_event_listeners_index := g_suspended_event_managers(g_suspended_event_managers.count).event_listener_index; + g_listeners := g_suspended_event_managers(g_suspended_event_managers.count).listeners; + g_suspended_event_managers.trim(1); + else + g_event_listeners_index.delete; + g_listeners := t_listeners(); + end if; + end; + + procedure trigger_event( a_event_name t_event_name, a_event_object ut_event_item := null ) is + + procedure trigger_listener_event( + a_listener_numbers t_listener_numbers, + a_event_name t_event_name, + a_event_object ut_event_item + ) is + l_listener_number t_listener_number := a_listener_numbers.first; + begin + while l_listener_number is not null loop + g_listeners(l_listener_number).on_event(a_event_name, a_event_object); + l_listener_number := a_listener_numbers.next(l_listener_number); end loop; + end; + begin + if a_event_name is not null then + if g_event_listeners_index.exists(gc_all) then + trigger_listener_event( g_event_listeners_index(gc_all), a_event_name, a_event_object ); + end if; + if g_event_listeners_index.exists(a_event_name) then + trigger_listener_event( g_event_listeners_index(a_event_name), a_event_name, a_event_object ); + end if; + if a_event_name = ut_event_manager.gc_finalize then + dispose_listeners(); + end if; end if; end; @@ -50,7 +93,7 @@ create or replace package body ut_event_manager as procedure add_events( a_event_names ut_varchar2_list, a_listener_pos binary_integer ) is begin for i in 1 .. a_event_names.count loop - add_event(a_event_names(i), a_listener_pos); + add_event( a_event_names(i), a_listener_pos ); end loop; end; @@ -70,10 +113,9 @@ create or replace package body ut_event_manager as if a_listener is not null then l_event_names := a_listener.get_supported_events(); if l_event_names is not empty then - add_events( l_event_names, add_listener(a_listener ) ); + add_events( l_event_names, add_listener( a_listener ) ); end if; end if; - end; end; diff --git a/source/core/events/ut_event_manager.pks b/source/core/events/ut_event_manager.pks index fa0da4a00..03b18b728 100644 --- a/source/core/events/ut_event_manager.pks +++ b/source/core/events/ut_event_manager.pks @@ -1,7 +1,7 @@ create or replace package ut_event_manager authid current_user as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -15,9 +15,48 @@ create or replace package ut_event_manager authid current_user as See the License for the specific language governing permissions and limitations under the License. */ + /* Constants: Event names */ subtype t_event_name is varchar2(250); - procedure trigger_event( a_event_name t_event_name, a_event_object ut_event_item ); + --capture all events + gc_all constant t_event_name := 'all'; + + gc_debug constant t_event_name := 'debug'; + + gc_initialize constant t_event_name := 'initialize'; + + gc_before_run constant t_event_name := 'before_run'; + gc_before_suite constant t_event_name := 'before_suite'; + + gc_before_before_all constant t_event_name := 'before_beforeall'; + gc_after_before_all constant t_event_name := 'after_beforeall'; + + gc_before_test constant t_event_name := 'beforetest'; + + gc_before_before_each constant t_event_name := 'before_beforeeach'; + gc_after_before_each constant t_event_name := 'after_beforeeach'; + gc_before_before_test constant t_event_name := 'before_beforetest'; + gc_after_before_test constant t_event_name := 'after_beforetest'; + + gc_before_test_execute constant t_event_name := 'before_test'; + gc_after_test_execute constant t_event_name := 'after_test'; + + gc_before_after_test constant t_event_name := 'before_aftertest'; + gc_after_after_test constant t_event_name := 'after_aftertest'; + gc_before_after_each constant t_event_name := 'before_aftereach'; + gc_after_after_each constant t_event_name := 'after_aftereach'; + + gc_after_test constant t_event_name := 'aftertest'; + + gc_before_after_all constant t_event_name := 'before_afterall'; + gc_after_after_all constant t_event_name := 'after_afterall'; + + gc_after_suite constant t_event_name := 'after_suite'; + gc_after_run constant t_event_name := 'after_run'; + + gc_finalize constant t_event_name := 'finalize'; + + procedure trigger_event( a_event_name t_event_name, a_event_object ut_event_item := null ); procedure initialize; diff --git a/source/core/output_buffers/ut_message_id_seq.sql b/source/core/output_buffers/ut_message_id_seq.sql deleted file mode 100644 index 3f0cd25c4..000000000 --- a/source/core/output_buffers/ut_message_id_seq.sql +++ /dev/null @@ -1 +0,0 @@ -create sequence ut_message_id_seq nocycle cache 100; diff --git a/source/core/output_buffers/ut_output_buffer_base.tpb b/source/core/output_buffers/ut_output_buffer_base.tpb new file mode 100644 index 000000000..20cec335e --- /dev/null +++ b/source/core/output_buffers/ut_output_buffer_base.tpb @@ -0,0 +1,155 @@ +create or replace type body ut_output_buffer_base is + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + */ + + member procedure init(self in out nocopy ut_output_buffer_base, a_output_id raw := null, a_self_type varchar2 := null) is + pragma autonomous_transaction; + l_exists int; + begin + cleanup_buffer(); + self.self_type := coalesce(a_self_type,self.self_type); + self.output_id := coalesce(a_output_id, self.output_id, sys_guid()); + self.start_date := coalesce(self.start_date, sysdate); + select /*+ no_parallel */ count(*) into l_exists from ut_output_buffer_info_tmp where output_id = self.output_id; + if ( l_exists > 0 ) then + update /*+ no_parallel */ ut_output_buffer_info_tmp set start_date = self.start_date where output_id = self.output_id; + else + insert /*+ no_parallel */ into ut_output_buffer_info_tmp(output_id, start_date) values (self.output_id, self.start_date); + end if; + commit; + dbms_lock.allocate_unique( self.output_id, self.lock_handle); + self.is_closed := 0; + end; + + member procedure lock_buffer(a_timeout_sec number := null) is + l_status integer; + begin + l_status := dbms_lock.request( self.lock_handle, dbms_lock.x_mode, 5, false ); + if l_status != 0 then + raise_application_error(-20000, 'Cannot allocate lock for output buffer of reporter. lock request status = '||l_status||', lock handle = '||self.lock_handle||', self.output_id ='||self.output_id); + end if; + end; + + member procedure close(self in out nocopy ut_output_buffer_base) is + l_status integer; + begin + l_status := dbms_lock.release( self.lock_handle ); + if l_status != 0 then + raise_application_error(-20000, 'Cannot release lock for output buffer of reporter. Lock_handle = '||self.lock_handle||' status = '||l_status); + end if; + self.is_closed := 1; + end; + + + member procedure remove_buffer_info(self in ut_output_buffer_base) is + pragma autonomous_transaction; + begin + delete from ut_output_buffer_info_tmp a + where a.output_id = self.output_id; + commit; + end; + + member function timeout_producer_not_started( a_producer_started boolean, a_already_waited_sec number, a_init_wait_sec number ) return boolean + is + l_result boolean := false; + begin + if not a_producer_started and a_already_waited_sec >= a_init_wait_sec then + if a_init_wait_sec > 0 then + self.remove_buffer_info(); + raise_application_error( + ut_utils.gc_out_buffer_timeout, + 'Timeout occurred while waiting for report data producer to start. Waited for: '||ut_utils.to_string( a_already_waited_sec )||' seconds.' + ); + else + l_result := true; + end if; + end if; + return l_result; + end; + + member function timeout_producer_not_finished(a_producer_finished boolean, a_already_waited_sec number, a_timeout_sec number) return boolean + is + l_result boolean := false; + begin + if not a_producer_finished and a_timeout_sec is not null and a_already_waited_sec >= a_timeout_sec then + if a_timeout_sec > 0 then + self.remove_buffer_info(); + raise_application_error( + ut_utils.gc_out_buffer_timeout, + 'Timeout occurred while waiting for more data from producer. Waited for: '||ut_utils.to_string( a_already_waited_sec )||' seconds.' + ); + else + l_result := true; + end if; + end if; + return l_result; + end; + + member function get_lock_status return integer is + l_result integer; + l_release_status integer; + begin + l_result := dbms_lock.request( self.lock_handle, dbms_lock.s_mode, 0, false ); + if l_result = 0 then + l_release_status := dbms_lock.release( self.lock_handle ); + end if; + return l_result; + end; + + member function get_lines_cursor(a_initial_timeout number := null, a_timeout_sec number := null) return sys_refcursor is + l_lines sys_refcursor; + begin + open l_lines for + select /*+ no_parallel */ text, item_type + from table(self.get_lines(a_initial_timeout, a_timeout_sec)); + return l_lines; + end; + + member procedure lines_to_dbms_output(self in ut_output_buffer_base, a_initial_timeout number := null, a_timeout_sec number := null) is + l_data sys_refcursor; + l_clob clob; + l_item_type varchar2(32767); + l_lines ut_varchar2_list; + begin + l_data := self.get_lines_cursor(a_initial_timeout, a_timeout_sec); + loop + fetch l_data into l_clob, l_item_type; + exit when l_data%notfound; + if dbms_lob.getlength(l_clob) > 32767 then + l_lines := ut_utils.clob_to_table(l_clob); + for i in 1 .. l_lines.count loop + dbms_output.put_line(l_lines(i)); + end loop; + else + dbms_output.put_line(l_clob); + end if; + end loop; + close l_data; + end; + + member procedure cleanup_buffer(self in ut_output_buffer_base, a_retention_time_sec natural := null) is + gc_buffer_retention_sec constant naturaln := coalesce(a_retention_time_sec, 60 * 60 * 24 * 5); -- 5 days + l_retention_days number := gc_buffer_retention_sec / (60 * 60 * 24); + l_max_retention_date date := sysdate - l_retention_days; + pragma autonomous_transaction; + begin + delete from ut_output_buffer_info_tmp i where i.start_date <= l_max_retention_date; + commit; + end; + +end; +/ \ No newline at end of file diff --git a/source/core/output_buffers/ut_output_buffer_base.tps b/source/core/output_buffers/ut_output_buffer_base.tps index f1d71c502..f2d9ec686 100644 --- a/source/core/output_buffers/ut_output_buffer_base.tps +++ b/source/core/output_buffers/ut_output_buffer_base.tps @@ -1,7 +1,7 @@ -create or replace type ut_output_buffer_base authid definer as object( +create or replace type ut_output_buffer_base force authid definer as object( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -17,11 +17,23 @@ create or replace type ut_output_buffer_base authid definer as object( */ output_id raw(32), - member procedure init(self in out nocopy ut_output_buffer_base), - not instantiable member procedure close(self in ut_output_buffer_base), - not instantiable member procedure send_line(self in ut_output_buffer_base, a_text varchar2), - not instantiable member function get_lines(a_initial_timeout natural := null, a_timeout_sec natural := null) return ut_varchar2_rows pipelined, - not instantiable member function get_lines_cursor(a_initial_timeout natural := null, a_timeout_sec natural := null) return sys_refcursor, - not instantiable member procedure lines_to_dbms_output(self in ut_output_buffer_base, a_initial_timeout natural := null, a_timeout_sec natural := null) + is_closed number(1,0), + start_date date, + lock_handle varchar2(30 byte), + self_type varchar2(250 byte), + member procedure init(self in out nocopy ut_output_buffer_base, a_output_id raw := null, a_self_type varchar2 := null), + member procedure lock_buffer(a_timeout_sec number := null), + member function timeout_producer_not_started( a_producer_started boolean, a_already_waited_sec number, a_init_wait_sec number ) return boolean, + member function timeout_producer_not_finished(a_producer_finished boolean, a_already_waited_sec number, a_timeout_sec number) return boolean, + member function get_lock_status return integer, + member function get_lines_cursor(a_initial_timeout number := null, a_timeout_sec number := null) return sys_refcursor, + member procedure lines_to_dbms_output(self in ut_output_buffer_base, a_initial_timeout number := null, a_timeout_sec number := null), + member procedure cleanup_buffer(self in ut_output_buffer_base, a_retention_time_sec natural := null), + member procedure remove_buffer_info(self in ut_output_buffer_base), + member procedure close(self in out nocopy ut_output_buffer_base), + not instantiable member procedure send_line(self in out nocopy ut_output_buffer_base, a_text varchar2, a_item_type varchar2 := null), + not instantiable member procedure send_lines(self in out nocopy ut_output_buffer_base, a_text_list ut_varchar2_rows, a_item_type varchar2 := null), + not instantiable member procedure send_clob(self in out nocopy ut_output_buffer_base, a_text clob, a_item_type varchar2 := null), + not instantiable member function get_lines(a_initial_timeout number := null, a_timeout_sec number := null) return ut_output_data_rows pipelined ) not final not instantiable / diff --git a/source/core/output_buffers/ut_output_buffer_info_tmp.sql b/source/core/output_buffers/ut_output_buffer_info_tmp.sql index 5880022f5..af730d394 100644 --- a/source/core/output_buffers/ut_output_buffer_info_tmp.sql +++ b/source/core/output_buffers/ut_output_buffer_info_tmp.sql @@ -1,7 +1,7 @@ -create table ut_output_buffer_info_tmp$( +create table ut_output_buffer_info_tmp( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 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 @@ -23,41 +23,3 @@ create table ut_output_buffer_info_tmp$( ) organization index nologging initrans 10 ; --- This is needed to be EBR ready as editioning view can only be created by edition enabled user -declare - ex_nonedition_user exception; - ex_view_doesnt_exist exception; - pragma exception_init(ex_nonedition_user,-42314); - pragma exception_init(ex_view_doesnt_exist,-942); - v_view_source varchar2(32767); -begin - begin - execute immediate 'drop view ut_output_buffer_info_tmp'; - exception - when ex_view_doesnt_exist then - null; - end; - v_view_source := ' ut_output_buffer_info_tmp as -/* -utPLSQL - Version 3 -Copyright 2016 - 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. -*/ -select output_id - ,start_date - from ut_output_buffer_info_tmp$'; - - execute immediate 'create or replace editioning view '||v_view_source; -exception - when ex_nonedition_user then - execute immediate 'create or replace view '||v_view_source; -end; -/ diff --git a/source/core/output_buffers/ut_output_buffer_tmp.sql b/source/core/output_buffers/ut_output_buffer_tmp.sql index e8127e237..1ab19e534 100644 --- a/source/core/output_buffers/ut_output_buffer_tmp.sql +++ b/source/core/output_buffers/ut_output_buffer_tmp.sql @@ -1,7 +1,7 @@ -create table ut_output_buffer_tmp$( +create table ut_output_buffer_tmp( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 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 @@ -20,50 +20,14 @@ create table ut_output_buffer_tmp$( output_id raw(32) not null, message_id number(38,0) not null, text varchar2(4000), + item_type varchar2(1000), is_finished number(1,0) default 0 not null, constraint ut_output_buffer_tmp_pk primary key(output_id, message_id), - constraint ut_output_buffer_tmp_ck check(is_finished = 0 and text is not null or is_finished = 1 and text is null), - constraint ut_output_buffer_fk1 foreign key (output_id) references ut_output_buffer_info_tmp$(output_id) -) organization index overflow nologging initrans 100 -; + constraint ut_output_buffer_tmp_ck check( + is_finished = 0 and (text is not null or item_type is not null ) + or is_finished = 1 and text is null and item_type is null ), + constraint ut_output_buffer_fk foreign key (output_id) references ut_output_buffer_info_tmp(output_id) on delete cascade +) organization index nologging initrans 100 + overflow nologging initrans 100; --- This is needed to be EBR ready as editioning view can only be created by edition enabled user -declare - ex_nonedition_user exception; - ex_view_doesnt_exist exception; - pragma exception_init(ex_nonedition_user,-42314); - pragma exception_init(ex_view_doesnt_exist,-942); - v_view_source varchar2(32767); -begin - begin - execute immediate 'drop view ut_output_buffer_tmp'; - exception - when ex_view_doesnt_exist then - null; - end; - v_view_source := ' ut_output_buffer_tmp 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. -*/ -select output_id - ,message_id - ,text - ,is_finished - from ut_output_buffer_tmp$'; - - execute immediate 'create or replace editioning view '||v_view_source; -exception - when ex_nonedition_user then - execute immediate 'create or replace view '||v_view_source; -end; -/ +create sequence ut_output_buffer_tmp_seq cache 20; diff --git a/source/core/output_buffers/ut_output_bulk_buffer.tpb b/source/core/output_buffers/ut_output_bulk_buffer.tpb new file mode 100644 index 000000000..cfc173e95 --- /dev/null +++ b/source/core/output_buffers/ut_output_bulk_buffer.tpb @@ -0,0 +1,160 @@ +create or replace type body ut_output_bulk_buffer is + /* + utPLSQL - Version 3 + Copyright 2016 - 2023 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + constructor function ut_output_bulk_buffer(self in out nocopy ut_output_bulk_buffer, a_output_id raw := null) return self as result is + begin + self.init(a_output_id, $$plsql_unit); + return; + end; + + overriding member procedure send_line(self in out nocopy ut_output_bulk_buffer, a_text varchar2, a_item_type varchar2 := null) is + pragma autonomous_transaction; + begin + if a_text is not null or a_item_type is not null then + if length(a_text) > ut_utils.gc_max_storage_varchar2_len then + self.send_lines( + ut_utils.convert_collection( + ut_utils.clob_to_table(a_text, ut_utils.gc_max_storage_varchar2_len) + ), + a_item_type + ); + else + insert /*+ no_parallel */ into ut_output_buffer_tmp(output_id, message_id, text, item_type) + values (self.output_id, ut_output_buffer_tmp_seq.nextval, a_text, a_item_type); + end if; + commit; + end if; + end; + + overriding member procedure send_lines(self in out nocopy ut_output_bulk_buffer, a_text_list ut_varchar2_rows, a_item_type varchar2 := null) is + pragma autonomous_transaction; + begin + insert /*+ no_parallel */ into ut_output_buffer_tmp(output_id, message_id, text, item_type) + select /*+ no_parallel */ self.output_id, ut_output_buffer_tmp_seq.nextval, t.column_value, a_item_type + from table(a_text_list) t + where t.column_value is not null or a_item_type is not null; + commit; + end; + + overriding member procedure send_clob(self in out nocopy ut_output_bulk_buffer, a_text clob, a_item_type varchar2 := null) is + pragma autonomous_transaction; + begin + if a_text is not null and a_text != empty_clob() or a_item_type is not null then + if length(a_text) > ut_utils.gc_max_storage_varchar2_len then + self.send_lines( + ut_utils.convert_collection( + ut_utils.clob_to_table(a_text, ut_utils.gc_max_storage_varchar2_len) + ), + a_item_type + ); + else + insert /*+ no_parallel */ into ut_output_buffer_tmp(output_id, message_id, text, item_type) + values (self.output_id, ut_output_buffer_tmp_seq.nextval, a_text, a_item_type); + end if; + commit; + end if; + end; + + overriding member procedure lines_to_dbms_output(self in ut_output_bulk_buffer, a_initial_timeout number := null, a_timeout_sec number := null) is + l_data sys_refcursor; + l_text ut_varchar2_rows; + l_item_type ut_varchar2_rows; + begin + l_data := self.get_lines_cursor(a_initial_timeout, a_timeout_sec); + loop + fetch l_data bulk collect into l_text, l_item_type limit 10000; + for idx in 1 .. l_text.count loop + dbms_output.put_line(l_text(idx)); + end loop; + exit when l_data%notfound; + end loop; + close l_data; + self.remove_buffer_info(); + end; + + overriding member function get_lines_cursor(a_initial_timeout number := null, a_timeout_sec number := null) return sys_refcursor is + lc_init_wait_sec constant number := coalesce(a_initial_timeout, 10 ); + l_already_waited_sec number(10,2) := 0; + l_sleep_time number(2,1); + l_exists integer; + l_finished boolean := false; + l_data_produced boolean := false; + l_producer_active boolean := false; + l_producer_started boolean := false; + l_producer_finished boolean := false; + l_results sys_refcursor; + begin + + while not l_finished loop + + if not l_data_produced then + select /*+ no_parallel */ count(1) into l_exists + from ut_output_buffer_tmp o + where o.output_id = self.output_id and rownum = 1; + l_data_produced := (l_exists = 1); + end if; + + l_sleep_time := case when l_already_waited_sec >= 1 then 0.5 else 0.1 end; + l_producer_active := (self.get_lock_status() <> 0); + l_producer_started := (l_producer_active or l_data_produced ) or l_producer_started; + l_producer_finished := (l_producer_started and not l_producer_active) or l_producer_finished; + l_finished := + self.timeout_producer_not_finished(l_producer_finished, l_already_waited_sec, a_timeout_sec) + or self.timeout_producer_not_started(l_producer_started, l_already_waited_sec, lc_init_wait_sec) + or l_producer_finished; + + dbms_lock.sleep(l_sleep_time); + l_already_waited_sec := l_already_waited_sec + l_sleep_time; + end loop; + + open l_results for + select /*+ no_parallel */ o.text, o.item_type + from ut_output_buffer_tmp o + where o.output_id = self.output_id + and o.text is not null + order by o.output_id, o.message_id; + + return l_results; + + end; + + /* Important note. + This function code is almost duplicated between two types for performance reasons. + The pipe row clause is much faster on VARCHAR2 then it is on clob. + That is the key reason for two implementations. + */ + overriding member function get_lines(a_initial_timeout number := null, a_timeout_sec number := null) return ut_output_data_rows pipelined is + l_data sys_refcursor; + l_text ut_varchar2_rows; + l_item_type ut_varchar2_rows; + begin + l_data := self.get_lines_cursor(a_initial_timeout, a_timeout_sec); + loop + fetch l_data bulk collect into l_text, l_item_type limit 10000; + for idx in 1 .. l_text.count loop + pipe row( ut_output_data_row(l_text(idx), l_item_type(idx)) ); + end loop; + exit when l_data%notfound; + end loop; + close l_data; + self.remove_buffer_info(); + return; + end; + +end; +/ diff --git a/source/core/output_buffers/ut_output_bulk_buffer.tps b/source/core/output_buffers/ut_output_bulk_buffer.tps new file mode 100644 index 000000000..d74d4ee14 --- /dev/null +++ b/source/core/output_buffers/ut_output_bulk_buffer.tps @@ -0,0 +1,27 @@ +create or replace type ut_output_bulk_buffer under ut_output_buffer_base ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2023 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + constructor function ut_output_bulk_buffer(self in out nocopy ut_output_bulk_buffer, a_output_id raw := null) return self as result, + overriding member procedure send_line(self in out nocopy ut_output_bulk_buffer, a_text varchar2, a_item_type varchar2 := null), + overriding member procedure send_lines(self in out nocopy ut_output_bulk_buffer, a_text_list ut_varchar2_rows, a_item_type varchar2 := null), + overriding member procedure send_clob(self in out nocopy ut_output_bulk_buffer, a_text clob, a_item_type varchar2 := null), + overriding member procedure lines_to_dbms_output(self in ut_output_bulk_buffer, a_initial_timeout number := null, a_timeout_sec number := null), + overriding member function get_lines_cursor(a_initial_timeout number := null, a_timeout_sec number := null) return sys_refcursor, + overriding member function get_lines(a_initial_timeout number := null, a_timeout_sec number := null) return ut_output_data_rows pipelined +) not final +/ diff --git a/source/core/output_buffers/ut_output_clob_buffer_tmp.sql b/source/core/output_buffers/ut_output_clob_buffer_tmp.sql new file mode 100644 index 000000000..9ff9f7413 --- /dev/null +++ b/source/core/output_buffers/ut_output_clob_buffer_tmp.sql @@ -0,0 +1,49 @@ +declare + v_table_sql varchar2(32767); + e_non_assm exception; + pragma exception_init(e_non_assm, -43853); +begin + v_table_sql := 'create table ut_output_clob_buffer_tmp( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + /* + * This table is not a global temporary table as it needs to allow cross-session data exchange + * It is used however as a temporary table with multiple writers. + * This is why it has very high initrans and has nologging + */ + output_id raw(32) not null, + message_id number(38,0) not null, + text clob, + item_type varchar2(1000), + is_finished number(1,0) default 0 not null, + constraint ut_output_clob_buffer_tmp_pk primary key(output_id, message_id), + constraint ut_output_clob_buffer_tmp_ck check( + is_finished = 0 and (text is not null or item_type is not null ) + or is_finished = 1 and text is null and item_type is null ), + constraint ut_output_clob_buffer_tmp_fk foreign key (output_id) references ut_output_buffer_info_tmp(output_id) on delete cascade +) nologging initrans 100 +'; + begin + execute immediate + v_table_sql || 'lob(text) store as securefile ut_output_text(retention none enable storage in row)'; + exception + when e_non_assm then + execute immediate + v_table_sql || 'lob(text) store as basicfile ut_output_text(pctversion 0 enable storage in row)'; + + end; +end; +/ + +create sequence ut_output_clob_buffer_tmp_seq cache 20; diff --git a/source/core/output_buffers/ut_output_clob_table_buffer.tpb b/source/core/output_buffers/ut_output_clob_table_buffer.tpb new file mode 100644 index 000000000..3d49ab08d --- /dev/null +++ b/source/core/output_buffers/ut_output_clob_table_buffer.tpb @@ -0,0 +1,134 @@ +create or replace type body ut_output_clob_table_buffer is + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + constructor function ut_output_clob_table_buffer(self in out nocopy ut_output_clob_table_buffer, a_output_id raw := null) return self as result is + begin + self.init(a_output_id, $$plsql_unit); + return; + end; + + overriding member procedure send_line(self in out nocopy ut_output_clob_table_buffer, a_text varchar2, a_item_type varchar2 := null) is + pragma autonomous_transaction; + begin + if a_text is not null or a_item_type is not null then + insert /*+ no_parallel */ into ut_output_clob_buffer_tmp(output_id, message_id, text, item_type) + values (self.output_id, ut_output_clob_buffer_tmp_seq.nextval, a_text, a_item_type); + end if; + commit; + end; + + overriding member procedure send_lines(self in out nocopy ut_output_clob_table_buffer, a_text_list ut_varchar2_rows, a_item_type varchar2 := null) is + pragma autonomous_transaction; + begin + insert /*+ no_parallel */ into ut_output_clob_buffer_tmp(output_id, message_id, text, item_type) + select /*+ no_parallel */ self.output_id, ut_output_clob_buffer_tmp_seq.nextval, t.column_value, a_item_type + from table(a_text_list) t + where t.column_value is not null or a_item_type is not null; + commit; + end; + + overriding member procedure send_clob(self in out nocopy ut_output_clob_table_buffer, a_text clob, a_item_type varchar2 := null) is + pragma autonomous_transaction; + begin + if a_text is not null and a_text != empty_clob() or a_item_type is not null then + insert /*+ no_parallel */ into ut_output_clob_buffer_tmp(output_id, message_id, text, item_type) + values (self.output_id, ut_output_clob_buffer_tmp_seq.nextval, a_text, a_item_type); + end if; + commit; + end; + + overriding member function get_lines(a_initial_timeout number := null, a_timeout_sec number := null) return ut_output_data_rows pipelined is + lc_init_wait_sec constant number := coalesce(a_initial_timeout, 10 ); + l_buffer_rowids ut_varchar2_rows; + l_buffer_data ut_output_data_rows; + l_finished_flags ut_integer_list; + l_already_waited_sec number(10,2) := 0; + l_finished boolean := false; + l_sleep_time number(2,1); + l_lock_status integer; + l_producer_started boolean := false; + l_producer_finished boolean := false; + procedure get_data_from_buffer_table( + a_buffer_data out nocopy ut_output_data_rows, + a_buffer_rowids out nocopy ut_varchar2_rows, + a_finished_flags out nocopy ut_integer_list + ) is + lc_bulk_limit constant integer := 5000; + begin + with ordered_buffer as ( + select /*+ no_parallel index(a) */ ut_output_data_row(a.text, a.item_type), rowidtochar(a.rowid), is_finished + from ut_output_clob_buffer_tmp a + where a.output_id = self.output_id + and a.message_id <= (select min(message_id) from ut_output_clob_buffer_tmp o where o.output_id = self.output_id) + lc_bulk_limit + order by a.message_id + ) + select /*+ no_parallel */ b.* + bulk collect into a_buffer_data, a_buffer_rowids, a_finished_flags + from ordered_buffer b; + end; + + procedure remove_read_data(a_buffer_rowids ut_varchar2_rows) is + pragma autonomous_transaction; + begin + forall i in 1 .. a_buffer_rowids.count + delete from ut_output_clob_buffer_tmp a + where rowid = chartorowid(a_buffer_rowids(i)); + commit; + end; + + begin + while not l_finished loop + + l_sleep_time := case when l_already_waited_sec >= 1 then 0.5 else 0.1 end; + l_lock_status := self.get_lock_status(); + get_data_from_buffer_table( l_buffer_data, l_buffer_rowids, l_finished_flags ); + + if l_buffer_data.count > 0 then + l_already_waited_sec := 0; + for i in 1 .. l_buffer_data.count loop + if l_buffer_data(i).text is not null then + pipe row( l_buffer_data(i) ); + elsif l_finished_flags(i) = 1 then + l_finished := true; + exit; + end if; + end loop; + remove_read_data(l_buffer_rowids); + else + --nothing fetched from output, wait. + dbms_lock.sleep(l_sleep_time); + l_already_waited_sec := l_already_waited_sec + l_sleep_time; + end if; + + l_producer_started := (l_lock_status <> 0 or l_buffer_data.count > 0) or l_producer_started; + l_producer_finished := (l_producer_started and l_lock_status = 0 and l_buffer_data.count = 0) or l_producer_finished; + + l_finished := + self.timeout_producer_not_finished(l_producer_finished, l_already_waited_sec, a_timeout_sec) + or self.timeout_producer_not_started(l_producer_started, l_already_waited_sec, lc_init_wait_sec) + or l_producer_finished + or l_finished; + + end loop; + + self.remove_buffer_info(); + return; + end; + +end; +/ diff --git a/source/core/output_buffers/ut_output_clob_table_buffer.tps b/source/core/output_buffers/ut_output_clob_table_buffer.tps new file mode 100644 index 000000000..191e64c01 --- /dev/null +++ b/source/core/output_buffers/ut_output_clob_table_buffer.tps @@ -0,0 +1,25 @@ +create or replace type ut_output_clob_table_buffer under ut_output_buffer_base ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + constructor function ut_output_clob_table_buffer(self in out nocopy ut_output_clob_table_buffer, a_output_id raw := null) return self as result, + overriding member procedure send_line(self in out nocopy ut_output_clob_table_buffer, a_text varchar2, a_item_type varchar2 := null), + overriding member procedure send_lines(self in out nocopy ut_output_clob_table_buffer, a_text_list ut_varchar2_rows, a_item_type varchar2 := null), + overriding member procedure send_clob(self in out nocopy ut_output_clob_table_buffer, a_text clob, a_item_type varchar2 := null), + overriding member function get_lines(a_initial_timeout number := null, a_timeout_sec number := null) return ut_output_data_rows pipelined +) not final +/ diff --git a/source/expectations/data_values/ut_data_value_object.tps b/source/core/output_buffers/ut_output_data_row.tps similarity index 65% rename from source/expectations/data_values/ut_data_value_object.tps rename to source/core/output_buffers/ut_output_data_row.tps index cf1dc631d..c5dd95e98 100644 --- a/source/expectations/data_values/ut_data_value_object.tps +++ b/source/core/output_buffers/ut_output_data_row.tps @@ -1,7 +1,7 @@ -create or replace type ut_data_value_object under ut_data_value_anydata( +create or replace type ut_output_data_row as object ( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ create or replace type ut_data_value_object under ut_data_value_anydata( See the License for the specific language governing permissions and limitations under the License. */ - constructor function ut_data_value_object(self in out nocopy ut_data_value_object, a_value anydata) return self as result, - overriding member function get_object_info return varchar2 + text clob, + item_type varchar2(1000) ) / diff --git a/source/core/output_buffers/ut_output_data_rows.tps b/source/core/output_buffers/ut_output_data_rows.tps new file mode 100644 index 000000000..097e9beff --- /dev/null +++ b/source/core/output_buffers/ut_output_data_rows.tps @@ -0,0 +1,19 @@ +create or replace type ut_output_data_rows as + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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_output_data_row +/ diff --git a/source/core/output_buffers/ut_output_table_buffer.tpb b/source/core/output_buffers/ut_output_table_buffer.tpb index 0cc68b76b..e8e2442a7 100644 --- a/source/core/output_buffers/ut_output_table_buffer.tpb +++ b/source/core/output_buffers/ut_output_table_buffer.tpb @@ -1,7 +1,7 @@ create or replace type body ut_output_table_buffer is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -18,141 +18,146 @@ create or replace type body ut_output_table_buffer is constructor function ut_output_table_buffer(self in out nocopy ut_output_table_buffer, a_output_id raw := null) return self as result is begin - self.output_id := coalesce(a_output_id, sys_guid()); - self.start_date := sysdate; - self.init(); - self.cleanup_buffer(); + self.init(a_output_id, $$plsql_unit); return; end; - overriding member procedure init(self in out nocopy ut_output_table_buffer) is + overriding member procedure send_line(self in out nocopy ut_output_table_buffer, a_text varchar2, a_item_type varchar2 := null) is pragma autonomous_transaction; - l_exists int; begin - select count(*) into l_exists from ut_output_buffer_info_tmp where output_id = self.output_id; - if ( l_exists > 0 ) then - update ut_output_buffer_info_tmp set start_date = self.start_date where output_id = self.output_id; - else - insert into ut_output_buffer_info_tmp(output_id, start_date) values (self.output_id, self.start_date); + if a_text is not null or a_item_type is not null then + if lengthb(a_text) > ut_utils.gc_max_storage_varchar2_len then + self.send_lines( + ut_utils.convert_collection( + ut_utils.clob_to_table(a_text, ut_utils.gc_max_storage_varchar2_len) + ), + a_item_type + ); + else + insert /*+ no_parallel */ into ut_output_buffer_tmp(output_id, message_id, text, item_type) + values (self.output_id, ut_output_buffer_tmp_seq.nextval, a_text, a_item_type); + end if; + commit; end if; - commit; end; - overriding member procedure close(self in ut_output_table_buffer) is + overriding member procedure send_lines(self in out nocopy ut_output_table_buffer, a_text_list ut_varchar2_rows, a_item_type varchar2 := null) is pragma autonomous_transaction; begin - insert into ut_output_buffer_tmp(output_id, message_id, is_finished) - values (self.output_id, ut_message_id_seq.nextval, 1); + insert /*+ no_parallel */ into ut_output_buffer_tmp(output_id, message_id, text, item_type) + select /*+ no_parallel */ self.output_id, ut_output_buffer_tmp_seq.nextval, t.column_value, a_item_type + from table(a_text_list) t + where t.column_value is not null or a_item_type is not null; commit; end; - overriding member procedure send_line(self in ut_output_table_buffer, a_text varchar2) is - l_text_list ut_varchar2_rows; + overriding member procedure send_clob(self in out nocopy ut_output_table_buffer, a_text clob, a_item_type varchar2 := null) is 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; + if a_text is not null and a_text != empty_clob() or a_item_type is not null then + if ut_utils.lengthb_clob(a_text) > ut_utils.gc_max_storage_varchar2_len then + self.send_lines( + ut_utils.convert_collection( + ut_utils.clob_to_table(a_text, ut_utils.gc_max_storage_varchar2_len) + ), + a_item_type + ); else - insert into ut_output_buffer_tmp(output_id, message_id, text) - values (self.output_id, ut_message_id_seq.nextval, a_text); + insert /*+ no_parallel */ into ut_output_buffer_tmp(output_id, message_id, text, item_type) + values (self.output_id, ut_output_buffer_tmp_seq.nextval, a_text, a_item_type); end if; commit; end if; end; - overriding member function get_lines(a_initial_timeout natural := null, a_timeout_sec natural := null) return ut_varchar2_rows pipelined is - l_buffer_data ut_varchar2_rows; - l_already_waited_for number(10,2) := 0; - l_finished boolean := false; - lc_init_wait_sec constant naturaln := coalesce(a_initial_timeout, 60 * 60 * 4 ); -- 4 hours - lc_max_wait_sec constant naturaln := coalesce(a_timeout_sec, 60 * 60 * 4); -- 4 hours - l_wait_for integer := lc_init_wait_sec; - lc_short_sleep_time constant number(1,1) := 0.1; --sleep for 100 ms between checks - lc_long_sleep_time constant number(1) := 1; --sleep for 1 s when waiting long - lc_long_wait_time constant number(1) := 1; --waiting more than 1 sec - l_sleep_time number(2,1) := lc_short_sleep_time; - function get_data_from_buffer return ut_varchar2_rows is - l_results ut_varchar2_rows; - pragma autonomous_transaction; - begin - delete from ( - select * - from ut_output_buffer_tmp where output_id = self.output_id order by message_id - ) - returning text bulk collect into l_results; - commit; - return l_results; - end; - + overriding member procedure lines_to_dbms_output(self in ut_output_table_buffer, a_initial_timeout number := null, a_timeout_sec number := null) is + l_data sys_refcursor; + l_text ut_varchar2_rows; + l_item_type ut_varchar2_rows; begin + l_data := self.get_lines_cursor(a_initial_timeout, a_timeout_sec); loop - l_buffer_data := get_data_from_buffer(); - --nothing fetched from output, wait and try again - if l_buffer_data.count = 0 then - dbms_lock.sleep(l_sleep_time); - l_already_waited_for := l_already_waited_for + l_sleep_time; - if l_already_waited_for > lc_long_wait_time then - l_sleep_time := lc_long_sleep_time; - end if; - else - --reset wait time - -- we wait lc_max_wait_sec for new message - l_wait_for := lc_max_wait_sec; - l_already_waited_for := 0; - l_sleep_time := lc_short_sleep_time; - for i in 1 .. l_buffer_data.count loop - if l_buffer_data(i) is not null then - pipe row(l_buffer_data(i)); - else + fetch l_data bulk collect into l_text, l_item_type limit 10000; + for idx in 1 .. l_text.count loop + dbms_output.put_line(l_text(idx)); + end loop; + exit when l_data%notfound; + end loop; + close l_data; + end; + + /* Important note. + This function code is almost duplicated between two types for performance reasons. + The pipe row clause is much faster on VARCHAR2 then it is on clob. + That is the key reason for two implementations. + */ + overriding member function get_lines(a_initial_timeout number := null, a_timeout_sec number := null) return ut_output_data_rows pipelined is + lc_init_wait_sec constant number := coalesce(a_initial_timeout, 10 ); + l_buffer_texts ut_varchar2_rows; + l_buffer_item_types ut_varchar2_rows; + l_finished_flags ut_integer_list; + l_already_waited_sec number(10,2) := 0; + l_finished boolean := false; + l_sleep_time number(2,1); + l_lock_status integer; + l_producer_started boolean := false; + l_producer_finished boolean := false; + + procedure get_data_from_buffer_table( + a_buffer_texts out nocopy ut_varchar2_rows, + a_buffer_item_types out nocopy ut_varchar2_rows, + a_finished_flags out nocopy ut_integer_list + ) is + lc_bulk_limit constant integer := 20000; + pragma autonomous_transaction; + begin + delete /*+ no_parallel */ from ( + select /*+ no_parallel */ * + from ut_output_buffer_tmp a + where a.output_id = self.output_id + and a.message_id <= (select min(message_id) from ut_output_buffer_tmp o where o.output_id = self.output_id) + lc_bulk_limit + order by a.message_id + ) d + returning d.text, d.item_type, d.is_finished + bulk collect into a_buffer_texts, a_buffer_item_types, a_finished_flags; + commit; + end; + begin + while not l_finished loop + + l_sleep_time := case when l_already_waited_sec >= 1 then 0.5 else 0.1 end; + l_lock_status := self.get_lock_status(); + get_data_from_buffer_table( l_buffer_texts, l_buffer_item_types, l_finished_flags ); + + if l_buffer_texts.count > 0 then + l_already_waited_sec := 0; + for i in 1 .. l_buffer_texts.count loop + if l_buffer_texts(i) is not null then + pipe row( ut_output_data_row(l_buffer_texts(i), l_buffer_item_types(i)) ); + elsif l_finished_flags(i) = 1 then l_finished := true; exit; end if; end loop; + else + --nothing fetched from output, wait. + dbms_lock.sleep(l_sleep_time); + l_already_waited_sec := l_already_waited_sec + l_sleep_time; end if; - exit when l_already_waited_for >= l_wait_for or l_finished; - end loop; - return; - end; - overriding member function get_lines_cursor(a_initial_timeout natural := null, a_timeout_sec natural := null) return sys_refcursor is - l_lines sys_refcursor; - begin - open l_lines for - select column_value as text - from table(self.get_lines(a_initial_timeout, a_timeout_sec)); - return l_lines; - end; + l_producer_started := (l_lock_status <> 0 or l_buffer_texts.count > 0) or l_producer_started; + l_producer_finished := (l_producer_started and l_lock_status = 0 and l_buffer_texts.count = 0) or l_producer_finished; - overriding member procedure lines_to_dbms_output(self in ut_output_table_buffer, a_initial_timeout natural := null, a_timeout_sec natural := null) is - l_lines sys_refcursor; - l_line varchar2(32767); - begin - l_lines := self.get_lines_cursor(a_initial_timeout, a_timeout_sec); - loop - fetch l_lines into l_line; - exit when l_lines%notfound; - dbms_output.put_line(l_line); - end loop; - close l_lines; - end; + l_finished := + self.timeout_producer_not_finished(l_producer_finished, l_already_waited_sec, a_timeout_sec) + or self.timeout_producer_not_started(l_producer_started, l_already_waited_sec, lc_init_wait_sec) + or l_producer_finished + or l_finished; - member procedure cleanup_buffer(self in ut_output_table_buffer, a_retention_time_sec natural := null) is - gc_buffer_retention_sec constant naturaln := coalesce(a_retention_time_sec, 60 * 60 * 24); -- 24 hours - l_retention_days number := gc_buffer_retention_sec / (60 * 60 * 24); - l_max_retention_date date := sysdate - l_retention_days; - pragma autonomous_transaction; - begin - delete from ut_output_buffer_tmp t - where t.output_id - in (select i.output_id from ut_output_buffer_info_tmp i where i.start_date <= l_max_retention_date); + end loop; - delete from ut_output_buffer_info_tmp i where i.start_date <= l_max_retention_date; - commit; + self.remove_buffer_info(); + return; end; end; diff --git a/source/core/output_buffers/ut_output_table_buffer.tps b/source/core/output_buffers/ut_output_table_buffer.tps index 96628de77..154ce4de6 100644 --- a/source/core/output_buffers/ut_output_table_buffer.tps +++ b/source/core/output_buffers/ut_output_table_buffer.tps @@ -1,7 +1,7 @@ create or replace type ut_output_table_buffer under ut_output_buffer_base ( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -16,14 +16,11 @@ create or replace type ut_output_table_buffer under ut_output_buffer_base ( limitations under the License. */ - start_date date, constructor function ut_output_table_buffer(self in out nocopy ut_output_table_buffer, a_output_id raw := null) return self as result, - overriding member procedure init(self in out nocopy ut_output_table_buffer), - overriding member procedure send_line(self in ut_output_table_buffer, a_text varchar2), - overriding member procedure close(self in ut_output_table_buffer), - overriding member function get_lines(a_initial_timeout natural := null, a_timeout_sec natural := null) return ut_varchar2_rows pipelined, - overriding member function get_lines_cursor(a_initial_timeout natural := null, a_timeout_sec natural := null) return sys_refcursor, - overriding member procedure lines_to_dbms_output(self in ut_output_table_buffer, a_initial_timeout natural := null, a_timeout_sec natural := null), - member procedure cleanup_buffer(self in ut_output_table_buffer, a_retention_time_sec natural := null) + overriding member procedure send_line(self in out nocopy ut_output_table_buffer, a_text varchar2, a_item_type varchar2 := null), + overriding member procedure send_lines(self in out nocopy ut_output_table_buffer, a_text_list ut_varchar2_rows, a_item_type varchar2 := null), + overriding member procedure send_clob(self in out nocopy ut_output_table_buffer, a_text clob, a_item_type varchar2 := null), + overriding member procedure lines_to_dbms_output(self in ut_output_table_buffer, a_initial_timeout number := null, a_timeout_sec number := null), + overriding member function get_lines(a_initial_timeout number := null, a_timeout_sec number := null) return ut_output_data_rows pipelined ) not final / diff --git a/source/core/session_context/ut_session_context.pkb b/source/core/session_context/ut_session_context.pkb new file mode 100644 index 000000000..a97505e9c --- /dev/null +++ b/source/core/session_context/ut_session_context.pkb @@ -0,0 +1,48 @@ +create or replace package body ut_session_context as + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + gc_context_name constant varchar2(30) := ut_utils.ut_owner()||'_INFO'; + + procedure set_context(a_name varchar2, a_value varchar2) is + begin + dbms_session.set_context( gc_context_name, a_name, a_value ); + end; + + procedure clear_context(a_name varchar2) is + begin + dbms_session.clear_context( namespace => gc_context_name, attribute => a_name ); + end; + + procedure clear_all_context is + begin + dbms_session.clear_all_context( namespace => gc_context_name ); + end; + + function is_ut_run return boolean is + l_paths varchar2(32767); + begin + l_paths := sys_context(gc_context_name, 'RUN_PATHS'); + return l_paths is not null; + end; + + function get_namespace return varchar2 is + begin + return gc_context_name; + end; + +end; +/ \ No newline at end of file diff --git a/source/core/session_context/ut_session_context.pks b/source/core/session_context/ut_session_context.pks new file mode 100644 index 000000000..63da3399e --- /dev/null +++ b/source/core/session_context/ut_session_context.pks @@ -0,0 +1,45 @@ +create or replace package ut_session_context as + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + */ + + /* + * Sets value of a context + */ + procedure set_context(a_name varchar2, a_value varchar2); + + /* + * Clears value of a context + */ + procedure clear_context(a_name varchar2); + + /* + * Clears entire context for utPLSQL run + */ + procedure clear_all_context; + + /* + * Returns true, if session context UT3_INFO is not empty + */ + function is_ut_run return boolean; + + /* + * Returns utPLSQL session context namespace name + */ + function get_namespace return varchar2; + +end; +/ \ No newline at end of file diff --git a/source/core/session_context/ut_session_info.tpb b/source/core/session_context/ut_session_info.tpb new file mode 100644 index 000000000..7d469651a --- /dev/null +++ b/source/core/session_context/ut_session_info.tpb @@ -0,0 +1,183 @@ +create or replace type body ut_session_info as + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + constructor function ut_session_info(self in out nocopy ut_session_info) return self as result is + begin + self.self_type := $$plsql_unit; + dbms_application_info.read_client_info( client_info ); + dbms_application_info.read_module( module, action ); + return; + end; + + -- run hooks + member procedure before_calling_run(self in out nocopy ut_session_info, a_run in ut_run) is + begin + ut_session_context.set_context( 'run_paths', ut_utils.to_string( ut_utils.table_to_clob( a_run.run_paths,',' ), null ) ); + ut_session_context.set_context( 'coverage_run_id', rawtohex( a_run.coverage_options.coverage_run_id ) ); + dbms_application_info.set_module( 'utPLSQL', null ); + end; + + member procedure after_calling_run(self in out nocopy ut_session_info, a_run in ut_run) is + begin + ut_session_context.clear_context( 'run_paths' ); + ut_session_context.clear_context( 'coverage_run_id' ); + dbms_application_info.set_module( module, action ); + dbms_application_info.set_client_info( client_info ); + end; + + -- suite hooks + member procedure before_calling_suite(self in out nocopy ut_session_info, a_suite in ut_logical_suite) is + begin + if a_suite is not of (ut_suite_context) then + ut_session_context.set_context( 'suite_path', a_suite.path ); + ut_session_context.set_context( 'suite_package', a_suite.object_owner||'.'||a_suite.object_name ); + ut_session_context.set_context( 'suite_description', a_suite.description ); + ut_session_context.set_context( 'suite_start_time', ut_utils.to_string(a_suite.start_time) ); + dbms_application_info.set_module( 'utPLSQL', a_suite.object_name ); + else + ut_session_context.set_context( 'context_name', a_suite.name ); + ut_session_context.set_context( 'context_path', a_suite.path); + ut_session_context.set_context( 'context_description', a_suite.description ); + ut_session_context.set_context( 'context_start_time', ut_utils.to_string(a_suite.start_time) ); + end if; + end; + + member procedure after_calling_suite(self in out nocopy ut_session_info, a_suite in ut_logical_suite) is + begin + if a_suite is not of (ut_suite_context) then + ut_session_context.clear_context( 'suite_package' ); + ut_session_context.clear_context( 'suite_path' ); + ut_session_context.clear_context( 'suite_description' ); + ut_session_context.clear_context( 'suite_start_time' ); + else + ut_session_context.clear_context( 'context_name' ); + ut_session_context.clear_context( 'context_path' ); + ut_session_context.clear_context( 'context_description' ); + ut_session_context.clear_context( 'context_start_time' ); + end if; + end; + + + member procedure before_calling_test(self in out nocopy ut_session_info, a_test in ut_test) is + begin + ut_session_context.set_context( 'test_name', a_test.object_owner||'.'||a_test.object_name||'.'||a_test.name ); + ut_session_context.set_context( 'test_description', a_test.description ); + ut_session_context.set_context( 'test_start_time', ut_utils.to_string(a_test.start_time) ); + end; + + member procedure after_calling_test (self in out nocopy ut_session_info, a_test in ut_test) is + begin + ut_session_context.clear_context( 'test_name' ); + ut_session_context.clear_context( 'test_description' ); + ut_session_context.clear_context( 'test_start_time' ); + end; + + member procedure before_calling_executable(self in out nocopy ut_session_info, a_executable in ut_executable) is + begin + ut_session_context.set_context( 'current_executable_type', a_executable.executable_type ); + ut_session_context.set_context( + 'current_executable_name', + a_executable.owner_name||'.'||a_executable.object_name||'.'||a_executable.procedure_name + ); + dbms_application_info.set_client_info( a_executable.procedure_name ); + end; + + member procedure after_calling_executable(self in out nocopy ut_session_info, a_executable in ut_executable) is + begin + ut_session_context.clear_context( 'current_executable_type' ); + ut_session_context.clear_context( 'current_executable_name' ); + dbms_application_info.set_client_info( null ); + end; + + member procedure on_finalize(self in out nocopy ut_session_info, a_run in ut_run) is + begin + dbms_application_info.set_client_info( client_info ); + dbms_application_info.set_module( module, action ); + ut_session_context.clear_all_context(); + end; + + overriding member function get_supported_events return ut_varchar2_list is + begin + return ut_varchar2_list( + ut_event_manager.gc_before_run, + ut_event_manager.gc_before_suite, + ut_event_manager.gc_before_test, + ut_event_manager.gc_before_before_all, + ut_event_manager.gc_before_before_each, + ut_event_manager.gc_before_before_test, + ut_event_manager.gc_before_test_execute, + ut_event_manager.gc_before_after_test, + ut_event_manager.gc_before_after_each, + ut_event_manager.gc_before_after_all, + ut_event_manager.gc_after_run, + ut_event_manager.gc_after_suite, + ut_event_manager.gc_after_test, + ut_event_manager.gc_after_before_all, + ut_event_manager.gc_after_before_each, + ut_event_manager.gc_after_before_test, + ut_event_manager.gc_after_test_execute, + ut_event_manager.gc_after_after_test, + ut_event_manager.gc_after_after_each, + ut_event_manager.gc_after_after_all, + ut_event_manager.gc_finalize + ); + end; + + overriding member procedure on_event( self in out nocopy ut_session_info, a_event_name varchar2, a_event_item ut_event_item) is + begin + case + when a_event_name in ( + ut_event_manager.gc_before_before_all, + ut_event_manager.gc_before_before_each, + ut_event_manager.gc_before_before_test, + ut_event_manager.gc_before_test_execute, + ut_event_manager.gc_before_after_test, + ut_event_manager.gc_before_after_each, + ut_event_manager.gc_before_after_all + ) + then before_calling_executable(treat(a_event_item as ut_executable)); + when a_event_name in ( + ut_event_manager.gc_after_before_all, + ut_event_manager.gc_after_before_each, + ut_event_manager.gc_after_before_test, + ut_event_manager.gc_after_test_execute, + ut_event_manager.gc_after_after_test, + ut_event_manager.gc_after_after_each, + ut_event_manager.gc_after_after_all + ) + then after_calling_executable(treat(a_event_item as ut_executable)); + when a_event_name = ut_event_manager.gc_before_test + then self.before_calling_test(treat(a_event_item as ut_test)); + when a_event_name = ut_event_manager.gc_after_test + then self.after_calling_test(treat(a_event_item as ut_test)); + when a_event_name = ut_event_manager.gc_after_suite + then after_calling_suite(treat(a_event_item as ut_logical_suite)); + when a_event_name = ut_event_manager.gc_before_suite + then before_calling_suite(treat(a_event_item as ut_logical_suite)); + when a_event_name = ut_event_manager.gc_before_run + then before_calling_run(treat(a_event_item as ut_run)); + when a_event_name = ut_event_manager.gc_after_run + then after_calling_run(treat(a_event_item as ut_run)); + when a_event_name = ut_event_manager.gc_finalize + then on_finalize(treat(a_event_item as ut_run)); + else null; + end case; + end; + +end; +/ \ No newline at end of file diff --git a/source/core/session_context/ut_session_info.tps b/source/core/session_context/ut_session_info.tps new file mode 100644 index 000000000..17e596d88 --- /dev/null +++ b/source/core/session_context/ut_session_info.tps @@ -0,0 +1,49 @@ +create or replace type ut_session_info under ut_event_listener ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + */ + + module varchar2(4000), + action varchar2(4000), + client_info varchar2(4000), + constructor function ut_session_info(self in out nocopy ut_session_info) return self as result, + + member procedure before_calling_run(self in out nocopy ut_session_info, a_run in ut_run), + member procedure after_calling_run (self in out nocopy ut_session_info, a_run in ut_run), + + member procedure before_calling_suite(self in out nocopy ut_session_info, a_suite in ut_logical_suite), + member procedure after_calling_suite(self in out nocopy ut_session_info, a_suite in ut_logical_suite), + + member procedure before_calling_executable(self in out nocopy ut_session_info, a_executable in ut_executable), + member procedure after_calling_executable (self in out nocopy ut_session_info, a_executable in ut_executable), + + member procedure before_calling_test(self in out nocopy ut_session_info, a_test in ut_test), + member procedure after_calling_test (self in out nocopy ut_session_info, a_test in ut_test), + + member procedure on_finalize(self in out nocopy ut_session_info, a_run in ut_run), + + /** + * Returns the list of events that are supported by particular implementation of the reporter + */ + overriding member function get_supported_events return ut_varchar2_list, + + /** + * Delegates execution of event into individual reporting procedures + */ + overriding member procedure on_event( self in out nocopy ut_session_info, a_event_name varchar2, a_event_item ut_event_item) + +) final +/ \ No newline at end of file diff --git a/source/core/types/ut_console_reporter_base.tpb b/source/core/types/ut_console_reporter_base.tpb index 70513223c..909e9355a 100644 --- a/source/core/types/ut_console_reporter_base.tpb +++ b/source/core/types/ut_console_reporter_base.tpb @@ -1,7 +1,7 @@ create or replace type body ut_console_reporter_base is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -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..a2c4b6b8c 100644 --- a/source/core/types/ut_console_reporter_base.tps +++ b/source/core/types/ut_console_reporter_base.tps @@ -1,7 +1,7 @@ create or replace type ut_console_reporter_base under ut_output_reporter_base( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -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_coverage_options.tpb b/source/core/types/ut_coverage_options.tpb new file mode 100644 index 000000000..a091802af --- /dev/null +++ b/source/core/types/ut_coverage_options.tpb @@ -0,0 +1,73 @@ +create or replace type body ut_coverage_options as + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + constructor function ut_coverage_options( + self in out nocopy ut_coverage_options, + coverage_run_id raw, + schema_names ut_varchar2_rows := null, + exclude_objects ut_varchar2_rows := null, + include_objects ut_varchar2_rows := null, + file_mappings ut_file_mappings := null, + include_schema_expr varchar2 := null, + include_object_expr varchar2 := null, + exclude_schema_expr varchar2 := null, + exclude_object_expr varchar2 := null + ) return self as result is + function to_ut_object_list(a_names ut_varchar2_rows, a_schema_names ut_varchar2_rows) return ut_object_names is + l_result ut_object_names; + l_object_name ut_object_name; + begin + if a_names is not empty then + l_result := ut_object_names(); + for i in 1 .. a_names.count loop + l_object_name := ut_object_name(a_names(i)); + if l_object_name.owner is null then + for i in 1 .. cardinality(a_schema_names) loop + l_result.extend; + l_result(l_result.last) := ut_object_name(a_schema_names(i)||'.'||l_object_name.name); + end loop; + else + l_result.extend; + l_result(l_result.last) := l_object_name; + end if; + end loop; + end if; + return l_result; + end; + begin + self.coverage_run_id := coverage_run_id; + self.file_mappings := file_mappings; + self.schema_names := schema_names; + self.exclude_objects := ut_object_names(); + + if exclude_objects is not empty then + self.exclude_objects := to_ut_object_list(exclude_objects, self.schema_names); + end if; + + self.include_objects := to_ut_object_list(include_objects, self.schema_names); + + self.include_schema_expr := include_schema_expr; + self.include_object_expr := include_object_expr; + self.exclude_schema_expr := exclude_schema_expr; + self.exclude_object_expr := exclude_object_expr; + + + return; + end; +end; +/ diff --git a/source/core/types/ut_coverage_options.tps b/source/core/types/ut_coverage_options.tps index 737ea1abb..a8e3d5129 100644 --- a/source/core/types/ut_coverage_options.tps +++ b/source/core/types/ut_coverage_options.tps @@ -1,7 +1,7 @@ create or replace type ut_coverage_options force as object ( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -16,9 +16,26 @@ create or replace type ut_coverage_options force as object ( limitations under the License. */ + coverage_run_id raw(32), schema_names ut_varchar2_rows, exclude_objects ut_object_names, include_objects ut_object_names, - file_mappings ut_file_mappings + file_mappings ut_file_mappings, + include_schema_expr varchar2(4000), + include_object_expr varchar2(4000), + exclude_schema_expr varchar2(4000), + exclude_object_expr varchar2(4000), + constructor function ut_coverage_options( + self in out nocopy ut_coverage_options, + coverage_run_id raw, + schema_names ut_varchar2_rows := null, + exclude_objects ut_varchar2_rows := null, + include_objects ut_varchar2_rows := null, + file_mappings ut_file_mappings := null, + include_schema_expr varchar2 := null, + include_object_expr varchar2 := null, + exclude_schema_expr varchar2 := null, + exclude_object_expr varchar2 := null + ) return self as result ) / diff --git a/source/core/types/ut_executable.tpb b/source/core/types/ut_executable.tpb index b41e75388..d2ce9b79d 100644 --- a/source/core/types/ut_executable.tpb +++ b/source/core/types/ut_executable.tpb @@ -1,7 +1,7 @@ create or replace type body ut_executable is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -29,9 +29,13 @@ create or replace type body ut_executable is return; end; - member function form_name return varchar2 is + member function form_name(a_skip_current_user_schema boolean := false) return varchar2 is + l_owner_name varchar2(250) := owner_name; begin - return ut_metadata.form_name(owner_name, object_name, procedure_name); + if a_skip_current_user_schema and sys_context('userenv', 'current_schema') = owner_name then + l_owner_name := null; + end if; + return ut_metadata.form_name(l_owner_name, object_name, procedure_name); end; member procedure do_execute(self in out nocopy ut_executable, a_item in out nocopy ut_suite_item) is @@ -71,10 +75,9 @@ create or replace type body ut_executable is begin if not ut_metadata.package_valid(self.owner_name, self.object_name) then - self.error_stack := l_message_part || 'package does not exist or is invalid: ' ||upper(self.owner_name||'.'||self.object_name); + self.error_stack := l_message_part || 'package '||upper(self.owner_name||'.'||self.object_name)||' does not exist or is invalid.'; elsif not ut_metadata.procedure_exists(self.owner_name, self.object_name, self.procedure_name) then - self.error_stack := l_message_part || 'procedure does not exist ' - || upper(self.owner_name || '.' || self.object_name || '.' ||self.procedure_name); + self.error_stack := l_message_part || 'procedure '||upper(self.owner_name || '.' || self.object_name || '.' ||self.procedure_name)||' does not exist.'; else l_result := false; end if; @@ -101,9 +104,6 @@ create or replace type body ut_executable is begin l_start_transaction_id := dbms_transaction.local_transaction_id(true); - -- report to application_info - ut_utils.set_client_info(self.procedure_name); - --listener - before call to executable ut_event_manager.trigger_event('before_'||self.executable_type, self); @@ -115,7 +115,7 @@ create or replace type body ut_executable is ' l_error_backtrace varchar2(32767);' || chr(10) || 'begin' || chr(10) || ' begin' || chr(10) || - ' ' || self.form_name() || ';' || chr(10) || + ' ' || self.form_name( a_skip_current_user_schema => true ) || ';' || chr(10) || ' exception' || chr(10) || ' when others then ' || chr(10) || ' l_error_stack := dbms_utility.format_error_stack;' || chr(10) || @@ -170,7 +170,6 @@ create or replace type body ut_executable is if l_start_transaction_id != l_end_transaction_id or l_end_transaction_id is null then a_item.add_transaction_invalidator(self.form_name()); end if; - ut_utils.set_client_info(null); return l_completed_without_errors; diff --git a/source/core/types/ut_executable.tps b/source/core/types/ut_executable.tps index 5fa4f3566..aaa5a3a72 100644 --- a/source/core/types/ut_executable.tps +++ b/source/core/types/ut_executable.tps @@ -1,7 +1,7 @@ create or replace type ut_executable under ut_event_item( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -25,8 +25,12 @@ 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 function form_name(a_skip_current_user_schema boolean := false) return varchar2, member procedure do_execute(self in out nocopy ut_executable, a_item in out nocopy ut_suite_item), /** * executes the defines executable diff --git a/source/core/types/ut_executable_test.tpb b/source/core/types/ut_executable_test.tpb index 09ffab55d..fa5872e04 100644 --- a/source/core/types/ut_executable_test.tpb +++ b/source/core/types/ut_executable_test.tpb @@ -1,4 +1,21 @@ create or replace type body ut_executable_test as + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + constructor function ut_executable_test( self in out nocopy ut_executable_test, a_owner varchar2, a_package varchar2, a_procedure_name varchar2, a_executable_type varchar2 @@ -14,7 +31,7 @@ create or replace type body ut_executable_test as member procedure do_execute( self in out nocopy ut_executable_test, a_item in out nocopy ut_suite_item, - a_expected_error_codes in ut_integer_list + a_expected_error_codes in ut_varchar2_rows ) is l_completed_without_errors boolean; begin @@ -23,10 +40,114 @@ create or replace type body ut_executable_test as member function do_execute( self in out nocopy ut_executable_test, a_item in out nocopy ut_suite_item, - a_expected_error_codes in ut_integer_list + a_expected_error_codes in ut_varchar2_rows ) return boolean is l_expected_except_message varchar2(4000); + l_expected_error_numbers ut_integer_list; + + function build_exception_numbers_list( + a_item in out nocopy ut_suite_item, + a_expected_error_codes in ut_varchar2_rows + ) return ut_integer_list is + l_exception_number integer; + l_exception_number_list ut_integer_list := ut_integer_list(); + c_regexp_for_exception_no constant varchar2(30) := '^-?[[:digit:]]{1,5}$'; + + c_integer_exception constant varchar2(1) := 'I'; + c_named_exception constant varchar2(1) := 'N'; + + function is_valid_qualified_name (a_name varchar2) return boolean is + l_name varchar2(500); + begin + l_name := dbms_assert.qualified_sql_name(a_name); + return true; + exception when others then + return false; + end; + + function check_exception_type(a_exception_name in varchar2) return varchar2 is + l_exception_type varchar2(50); + begin + --check if it is a predefined exception + begin + execute immediate 'begin null; exception when '||a_exception_name||' then null; end;'; + l_exception_type := c_named_exception; + exception + when others then + if dbms_utility.format_error_stack() like '%PLS-00485%' then + declare + e_invalid_number exception; + pragma exception_init ( e_invalid_number, -6502 ); + begin + execute immediate 'declare x integer := '||a_exception_name||'; begin null; end;'; + l_exception_type := c_integer_exception; + exception + when others then + null; + end; + end if; + end; + return l_exception_type; + end; + + function get_exception_number (a_exception_var in varchar2) return integer is + l_exc_no integer; + l_exc_type varchar2(50); + function remap_no_data_found (a_number integer) return integer is + begin + return case a_number when 100 then -1403 else a_number end; + end; + begin + l_exc_type := check_exception_type(a_exception_var); + + execute immediate + case l_exc_type + when c_integer_exception then + 'declare l_exception number; begin :l_exception := '||a_exception_var||'; end;' + when c_named_exception then + 'begin raise '||a_exception_var||'; exception when others then :l_exception := sqlcode; end;' + else + 'begin :l_exception := null; end;' + end + using out l_exc_no; + return remap_no_data_found(l_exc_no); + end; + + begin + if a_expected_error_codes is not empty then + for i in 1 .. a_expected_error_codes.count loop + /** + * Check if its a valid qualified name and if so try to resolve name to an exception number + */ + if is_valid_qualified_name(a_expected_error_codes(i)) then + l_exception_number := get_exception_number(a_expected_error_codes(i)); + elsif regexp_like(a_expected_error_codes(i), c_regexp_for_exception_no) then + l_exception_number := a_expected_error_codes(i); + end if; + + if l_exception_number is null then + a_item.put_warning( + 'Invalid parameter value "'||a_expected_error_codes(i)||'" for "--%throws" annotation. Parameter ignored.', + self.procedure_name, + a_item.line_no + ); + elsif l_exception_number >= 0 then + a_item.put_warning( + 'Invalid parameter value "'||a_expected_error_codes(i)||'" for "--%throws" annotation. Exception value must be a negative integer. Parameter ignored.', + self.procedure_name, + a_item.line_no + ); + else + l_exception_number_list.extend; + l_exception_number_list(l_exception_number_list.last) := l_exception_number; + end if; + l_exception_number := null; + end loop; + end if; + + return l_exception_number_list; + end; function failed_expec_errnum_message(a_expected_error_codes in ut_integer_list) return varchar is l_actual_error_no integer; l_expected_error_codes varchar2(4000); @@ -38,8 +159,8 @@ create or replace type body ut_executable_test as if self.error_stack is null then l_fail_message := 'Expected one of exceptions ('||l_expected_error_codes||') but nothing was raised.'; else - l_actual_error_no := regexp_substr(self.error_stack, '^[a-zA-Z]{3}(-[0-9]+)', subexpression=>1); - if not l_actual_error_no member of a_expected_error_codes then + l_actual_error_no := regexp_substr(self.error_stack, '^[[:alpha:]]{3}(-[0-9]+)', subexpression=>1); + if not l_actual_error_no member of a_expected_error_codes or l_actual_error_no is null then l_fail_message := 'Actual: '||l_actual_error_no||' was expected to '; if cardinality(a_expected_error_codes) > 1 then l_fail_message := l_fail_message || 'be one of: ('||l_expected_error_codes||')'; @@ -55,9 +176,9 @@ create or replace type body ut_executable_test as begin --Create a ut_executable object and call do_execute after that get the data to know the test's execution result self.do_execute(a_item); - - if a_expected_error_codes is not null and a_expected_error_codes is not empty then - l_expected_except_message := failed_expec_errnum_message(a_expected_error_codes); + l_expected_error_numbers := build_exception_numbers_list(a_item, a_expected_error_codes); + if l_expected_error_numbers is not null and l_expected_error_numbers is not empty then + l_expected_except_message := failed_expec_errnum_message( l_expected_error_numbers ); if l_expected_except_message is not null then ut_expectation_processor.add_expectation_result( diff --git a/source/core/types/ut_executable_test.tps b/source/core/types/ut_executable_test.tps index b11676c0c..42b6080df 100644 --- a/source/core/types/ut_executable_test.tps +++ b/source/core/types/ut_executable_test.tps @@ -1,7 +1,7 @@ create or replace type ut_executable_test authid current_user under ut_executable ( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -22,12 +22,12 @@ create or replace type ut_executable_test authid current_user under ut_executabl member procedure do_execute( self in out nocopy ut_executable_test, a_item in out nocopy ut_suite_item, - a_expected_error_codes in ut_integer_list + a_expected_error_codes in ut_varchar2_rows ), member function do_execute( self in out nocopy ut_executable_test, a_item in out nocopy ut_suite_item, - a_expected_error_codes in ut_integer_list + a_expected_error_codes in ut_varchar2_rows ) return boolean ) final; diff --git a/source/core/types/ut_executables.tps b/source/core/types/ut_executables.tps index a06e6c067..d6d52b3d2 100644 --- a/source/core/types/ut_executables.tps +++ b/source/core/types/ut_executables.tps @@ -1,7 +1,7 @@ create or replace type ut_executables as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/types/ut_expectation_result.tpb b/source/core/types/ut_expectation_result.tpb index 6714d48b6..0b3adf983 100644 --- a/source/core/types/ut_expectation_result.tpb +++ b/source/core/types/ut_expectation_result.tpb @@ -1,7 +1,7 @@ create or replace type body ut_expectation_result is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -21,9 +21,10 @@ create or replace type body ut_expectation_result is a_description varchar2, a_message clob, a_include_caller_info boolean := true ) return self as result is begin + self.self_type := $$plsql_unit; self.status := a_status; self.description := a_description; - self.message := a_message; + self.message := a_message; if self.status = ut_utils.gc_failure and a_include_caller_info then self.caller_info := ut_expectation_processor.who_called_expectation(dbms_utility.format_call_stack()); end if; diff --git a/source/core/types/ut_expectation_result.tps b/source/core/types/ut_expectation_result.tps index af819504d..d4b4c7548 100644 --- a/source/core/types/ut_expectation_result.tps +++ b/source/core/types/ut_expectation_result.tps @@ -1,7 +1,7 @@ -create or replace type ut_expectation_result authid current_user as object( +create or replace type ut_expectation_result under ut_event_item( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/types/ut_expectation_results.tps b/source/core/types/ut_expectation_results.tps index 942f9b398..e5e4c6223 100644 --- a/source/core/types/ut_expectation_results.tps +++ b/source/core/types/ut_expectation_results.tps @@ -1,7 +1,7 @@ create or replace type ut_expectation_results as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/types/ut_file_mapping.tpb b/source/core/types/ut_file_mapping.tpb index c5a82c09d..dab1e35c5 100644 --- a/source/core/types/ut_file_mapping.tpb +++ b/source/core/types/ut_file_mapping.tpb @@ -1,7 +1,7 @@ create or replace type body ut_file_mapping as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/types/ut_file_mapping.tps b/source/core/types/ut_file_mapping.tps index e046808d4..941d95283 100644 --- a/source/core/types/ut_file_mapping.tps +++ b/source/core/types/ut_file_mapping.tps @@ -1,7 +1,7 @@ create or replace type ut_file_mapping as object( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/types/ut_file_mappings.tps b/source/core/types/ut_file_mappings.tps index 6ff2604b3..240fb8dd7 100644 --- a/source/core/types/ut_file_mappings.tps +++ b/source/core/types/ut_file_mappings.tps @@ -1,7 +1,7 @@ create or replace type ut_file_mappings as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/types/ut_integer_list.tps b/source/core/types/ut_integer_list.tps index c1fc4de91..ec9a2a78f 100644 --- a/source/core/types/ut_integer_list.tps +++ b/source/core/types/ut_integer_list.tps @@ -1,7 +1,7 @@ create or replace type ut_integer_list as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/types/ut_key_value_pair.tps b/source/core/types/ut_key_value_pair.tps index ae1b9aba7..5a337e608 100644 --- a/source/core/types/ut_key_value_pair.tps +++ b/source/core/types/ut_key_value_pair.tps @@ -1,7 +1,7 @@ create or replace type ut_key_value_pair force as object( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/types/ut_key_value_pairs.tps b/source/core/types/ut_key_value_pairs.tps index c9bab9ec2..24bdded36 100644 --- a/source/core/types/ut_key_value_pairs.tps +++ b/source/core/types/ut_key_value_pairs.tps @@ -1,7 +1,7 @@ create or replace type ut_key_value_pairs as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/types/ut_logical_suite.tpb b/source/core/types/ut_logical_suite.tpb index 0443bf105..036d40d51 100644 --- a/source/core/types/ut_logical_suite.tpb +++ b/source/core/types/ut_logical_suite.tpb @@ -1,7 +1,7 @@ create or replace type body ut_logical_suite as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -16,46 +16,23 @@ 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 + overriding member procedure mark_as_skipped(self in out nocopy ut_logical_suite, a_skip_reason in varchar2) 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); + ut_event_manager.trigger_event(ut_event_manager.gc_before_suite, self); self.start_time := current_timestamp; for i in 1 .. self.items.count loop - self.items(i).mark_as_skipped(); + self.items(i).mark_as_skipped(coalesce(a_skip_reason,self.disabled_reason)); end loop; self.end_time := self.start_time; - ut_event_manager.trigger_event(ut_utils.gc_after_suite, self); + ut_event_manager.trigger_event(ut_event_manager.gc_after_suite, self); self.calc_execution_result(); end; - overriding member procedure set_rollback_type(self in out nocopy ut_logical_suite, a_rollback_type integer) is + overriding member procedure set_rollback_type(self in out nocopy ut_logical_suite, a_rollback_type integer, a_force boolean := false) is begin - self.rollback_type := coalesce(self.rollback_type, a_rollback_type); + self.rollback_type := case when a_force then a_rollback_type else coalesce(self.rollback_type, a_rollback_type) end; for i in 1 .. self.items.count loop - self.items(i).set_rollback_type(self.rollback_type); + self.items(i).set_rollback_type(self.rollback_type, a_force); end loop; end; @@ -66,7 +43,7 @@ create or replace type body ut_logical_suite as begin ut_utils.debug_log('ut_logical_suite.execute'); - ut_event_manager.trigger_event(ut_utils.gc_before_suite, self); + ut_event_manager.trigger_event(ut_event_manager.gc_before_suite, self); self.start_time := current_timestamp; for i in 1 .. self.items.count loop @@ -77,7 +54,7 @@ create or replace type body ut_logical_suite as self.calc_execution_result(); self.end_time := current_timestamp; - ut_event_manager.trigger_event(ut_utils.gc_after_suite, self); + ut_event_manager.trigger_event(ut_event_manager.gc_after_suite, self); return l_completed_without_errors; end; @@ -101,7 +78,7 @@ create or replace type body ut_logical_suite as overriding member procedure mark_as_errored(self in out nocopy ut_logical_suite, a_error_stack_trace varchar2) is begin ut_utils.debug_log('ut_logical_suite.fail'); - ut_event_manager.trigger_event(ut_utils.gc_before_suite, self); + ut_event_manager.trigger_event(ut_event_manager.gc_before_suite, self); self.start_time := current_timestamp; for i in 1 .. self.items.count loop -- execute the item (test or suite) @@ -109,7 +86,7 @@ create or replace type body ut_logical_suite as end loop; self.calc_execution_result(); self.end_time := self.start_time; - ut_event_manager.trigger_event(ut_utils.gc_after_suite, self); + ut_event_manager.trigger_event(ut_event_manager.gc_after_suite, self); end; overriding member function get_error_stack_traces return ut_varchar2_list is diff --git a/source/core/types/ut_logical_suite.tps b/source/core/types/ut_logical_suite.tps index 85bb80870..c4f2f699b 100644 --- a/source/core/types/ut_logical_suite.tps +++ b/source/core/types/ut_logical_suite.tps @@ -1,7 +1,7 @@ -create or replace type ut_logical_suite under ut_suite_item ( +create or replace type ut_logical_suite force under ut_suite_item ( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -21,13 +21,8 @@ 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 procedure mark_as_skipped(self in out nocopy ut_logical_suite, a_skip_reason in varchar2), + overriding member procedure set_rollback_type(self in out nocopy ut_logical_suite, a_rollback_type integer, a_force boolean := false), overriding member function do_execute(self in out nocopy ut_logical_suite) return boolean, overriding member procedure calc_execution_result(self in out nocopy ut_logical_suite), overriding member procedure mark_as_errored(self in out nocopy ut_logical_suite, a_error_stack_trace varchar2), diff --git a/source/core/types/ut_object_name.tpb b/source/core/types/ut_object_name.tpb index 299b6e269..76acc15bf 100644 --- a/source/core/types/ut_object_name.tpb +++ b/source/core/types/ut_object_name.tpb @@ -1,7 +1,7 @@ create or replace type body ut_object_name as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/types/ut_object_name.tps b/source/core/types/ut_object_name.tps index 12afa69dd..5f8f724c4 100644 --- a/source/core/types/ut_object_name.tps +++ b/source/core/types/ut_object_name.tps @@ -1,7 +1,7 @@ create or replace type ut_object_name as object ( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/types/ut_object_names.tps b/source/core/types/ut_object_names.tps index f46580172..03830be17 100644 --- a/source/core/types/ut_object_names.tps +++ b/source/core/types/ut_object_names.tps @@ -1,7 +1,7 @@ create or replace type ut_object_names as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/types/ut_output_reporter_base.tpb b/source/core/types/ut_output_reporter_base.tpb index 32e8b225b..48970be5a 100644 --- a/source/core/types/ut_output_reporter_base.tpb +++ b/source/core/types/ut_output_reporter_base.tpb @@ -1,7 +1,7 @@ create or replace type body ut_output_reporter_base is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -31,25 +31,35 @@ create or replace type body ut_output_reporter_base is overriding member procedure set_reporter_id(self in out nocopy ut_output_reporter_base, a_reporter_id raw) is begin self.id := a_reporter_id; - self.output_buffer.output_id := a_reporter_id; + self.output_buffer.init(a_reporter_id); end; - overriding member procedure before_calling_run(self in out nocopy ut_output_reporter_base, a_run in ut_run) is - l_output_table_buffer ut_output_table_buffer; + member function set_reporter_id(self in ut_output_reporter_base, a_reporter_id raw) return ut_output_reporter_base is + l_result ut_output_reporter_base := self; begin - (self as ut_reporter_base).before_calling_run(a_run); - l_output_table_buffer := treat(self.output_buffer as ut_output_table_buffer); + l_result.set_reporter_id(a_reporter_id); + return l_result; end; - member procedure print_text(self in out nocopy ut_output_reporter_base, a_text varchar2) is + member procedure print_text(self in out nocopy ut_output_reporter_base, a_text varchar2, a_item_type varchar2 := null) is begin - self.output_buffer.send_line(a_text); + self.output_buffer.send_line(a_text, a_item_type); end; - final member function get_lines(a_initial_timeout natural := null, a_timeout_sec natural) return ut_varchar2_rows pipelined is + member procedure print_text_lines(self in out nocopy ut_output_reporter_base, a_text_lines ut_varchar2_rows, a_item_type varchar2 := null) is begin - for i in (select column_value from table(self.output_buffer.get_lines(a_initial_timeout, a_timeout_sec))) loop - pipe row (i.column_value); + self.output_buffer.send_lines(a_text_lines, a_item_type); + end; + + member procedure print_clob(self in out nocopy ut_output_reporter_base, a_clob clob, a_item_type varchar2 := null) is + begin + self.output_buffer.send_clob( a_clob, a_item_type ); + end; + + final member function get_lines(a_initial_timeout natural := null, a_timeout_sec natural) return ut_output_data_rows pipelined is + begin + for i in (select /*+ no_parallel */ value(x) val from table(self.output_buffer.get_lines(a_initial_timeout, a_timeout_sec)) x ) loop + pipe row (i.val); end loop; end; @@ -63,20 +73,15 @@ create or replace type body ut_output_reporter_base is self.output_buffer.lines_to_dbms_output(a_initial_timeout, a_timeout_sec); end; - member procedure print_clob(self in out nocopy ut_output_reporter_base, a_clob clob) is - l_lines ut_varchar2_list; + overriding final member procedure on_finalize(self in out nocopy ut_output_reporter_base, a_run in ut_run) is begin - if a_clob is not null and dbms_lob.getlength(a_clob) > 0 then - l_lines := ut_utils.clob_to_table(a_clob); - for i in 1 .. l_lines.count loop - self.print_text(l_lines(i)); - end loop; - end if; + self.output_buffer.close(); end; - overriding final member procedure on_finalize(self in out nocopy ut_output_reporter_base, a_run in ut_run) is + overriding member procedure on_initialize(self in out nocopy ut_output_reporter_base, a_run in ut_run) is begin - self.output_buffer.close(); + self.output_buffer.lock_buffer(); + self.output_buffer.send_line(null, 'initialize'); end; end; diff --git a/source/core/types/ut_output_reporter_base.tps b/source/core/types/ut_output_reporter_base.tps index a0a9f63f6..21eed9957 100644 --- a/source/core/types/ut_output_reporter_base.tps +++ b/source/core/types/ut_output_reporter_base.tps @@ -1,7 +1,7 @@ create or replace type ut_output_reporter_base under ut_reporter_base( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -19,16 +19,17 @@ create or replace type ut_output_reporter_base under ut_reporter_base( constructor function ut_output_reporter_base(self in out nocopy ut_output_reporter_base) return self as result, member procedure init(self in out nocopy ut_output_reporter_base, a_self_type varchar2, a_output_buffer ut_output_buffer_base := null), overriding member procedure set_reporter_id(self in out nocopy ut_output_reporter_base, a_reporter_id raw), - overriding member procedure before_calling_run(self in out nocopy ut_output_reporter_base, a_run in ut_run), - - member procedure print_text(self in out nocopy ut_output_reporter_base, a_text varchar2), + member function set_reporter_id(self in ut_output_reporter_base, a_reporter_id raw) return ut_output_reporter_base, - member procedure print_clob(self in out nocopy ut_output_reporter_base, a_clob clob), + member procedure print_text(self in out nocopy ut_output_reporter_base, a_text varchar2, a_item_type varchar2 := null), + member procedure print_text_lines(self in out nocopy ut_output_reporter_base, a_text_lines ut_varchar2_rows, a_item_type varchar2 := null), + member procedure print_clob(self in out nocopy ut_output_reporter_base, a_clob clob, a_item_type varchar2 := null), - final member function get_lines(a_initial_timeout natural := null, a_timeout_sec natural := null) return ut_varchar2_rows pipelined, + final member function get_lines(a_initial_timeout natural := null, a_timeout_sec natural := null) return ut_output_data_rows pipelined, final member function get_lines_cursor(a_initial_timeout natural := null, a_timeout_sec natural := null) return sys_refcursor, final member procedure lines_to_dbms_output(self in ut_output_reporter_base, a_initial_timeout natural := null, a_timeout_sec natural := null), - overriding final member procedure on_finalize(self in out nocopy ut_output_reporter_base, a_run in ut_run) + overriding final member procedure on_finalize(self in out nocopy ut_output_reporter_base, a_run in ut_run), + overriding member procedure on_initialize(self in out nocopy ut_output_reporter_base, a_run in ut_run) ) not final not instantiable / diff --git a/source/core/types/ut_path_item.tpb b/source/core/types/ut_path_item.tpb new file mode 100644 index 000000000..6cdb2b8ad --- /dev/null +++ b/source/core/types/ut_path_item.tpb @@ -0,0 +1,42 @@ +create or replace type body ut_path_item as + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + constructor function ut_path_item(self in out nocopy ut_path_item, schema_name varchar2, object_name varchar2,procedure_name varchar2) return self as result is + begin + self.schema_name := schema_name; + self.object_name := object_name; + self.procedure_name := procedure_name; + return; + end; + + constructor function ut_path_item(self in out nocopy ut_path_item, schema_name varchar2,suite_path varchar2) return self as result is + begin + self.schema_name := schema_name; + self.suite_path := suite_path; + return; + end; + + constructor function ut_path_item(self in out nocopy ut_path_item, schema_name varchar2, object_name varchar2,procedure_name varchar2,suite_path varchar2) return self as result is + begin + self.schema_name := schema_name; + self.object_name := object_name; + self.procedure_name := procedure_name; + self.suite_path := suite_path; + return; + end; +end; +/ diff --git a/source/core/types/ut_path_item.tps b/source/core/types/ut_path_item.tps new file mode 100644 index 000000000..c8ec81be5 --- /dev/null +++ b/source/core/types/ut_path_item.tps @@ -0,0 +1,26 @@ +create or replace type ut_path_item as object ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + */ + schema_name varchar2(4000), + object_name varchar2(250), + procedure_name varchar2(250), + suite_path varchar2(4000), + constructor function ut_path_item(self in out nocopy ut_path_item, schema_name varchar2, object_name varchar2,procedure_name varchar2) return self as result, + constructor function ut_path_item(self in out nocopy ut_path_item, schema_name varchar2, suite_path varchar2) return self as result, + constructor function ut_path_item(self in out nocopy ut_path_item, schema_name varchar2, object_name varchar2,procedure_name varchar2,suite_path varchar2) return self as result +) +/ diff --git a/source/core/types/ut_path_items.tps b/source/core/types/ut_path_items.tps new file mode 100644 index 000000000..0c87cf28c --- /dev/null +++ b/source/core/types/ut_path_items.tps @@ -0,0 +1,19 @@ +create or replace type ut_path_items as + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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_path_item +/ diff --git a/source/core/types/ut_reporter_base.tpb b/source/core/types/ut_reporter_base.tpb index 487b7685e..3f8984331 100644 --- a/source/core/types/ut_reporter_base.tpb +++ b/source/core/types/ut_reporter_base.tpb @@ -1,7 +1,7 @@ create or replace type body ut_reporter_base is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -139,75 +139,79 @@ create or replace type body ut_reporter_base is overriding member function get_supported_events return ut_varchar2_list is begin return ut_varchar2_list( - ut_utils.gc_before_run, - ut_utils.gc_before_suite, - ut_utils.gc_before_test, - ut_utils.gc_before_before_all, - ut_utils.gc_before_before_each, - ut_utils.gc_before_before_test, - ut_utils.gc_before_test_execute, - ut_utils.gc_before_after_test, - ut_utils.gc_before_after_each, - ut_utils.gc_before_after_all, - ut_utils.gc_after_run, - ut_utils.gc_after_suite, - ut_utils.gc_after_test, - ut_utils.gc_after_before_all, - ut_utils.gc_after_before_each, - ut_utils.gc_after_before_test, - ut_utils.gc_after_test_execute, - ut_utils.gc_after_after_test, - ut_utils.gc_after_after_each, - ut_utils.gc_after_after_all, - ut_utils.gc_finalize + ut_event_manager.gc_initialize, + ut_event_manager.gc_before_run, + ut_event_manager.gc_before_suite, + ut_event_manager.gc_before_test, + ut_event_manager.gc_before_before_all, + ut_event_manager.gc_before_before_each, + ut_event_manager.gc_before_before_test, + ut_event_manager.gc_before_test_execute, + ut_event_manager.gc_before_after_test, + ut_event_manager.gc_before_after_each, + ut_event_manager.gc_before_after_all, + ut_event_manager.gc_after_run, + ut_event_manager.gc_after_suite, + ut_event_manager.gc_after_test, + ut_event_manager.gc_after_before_all, + ut_event_manager.gc_after_before_each, + ut_event_manager.gc_after_before_test, + ut_event_manager.gc_after_test_execute, + ut_event_manager.gc_after_after_test, + ut_event_manager.gc_after_after_each, + ut_event_manager.gc_after_after_all, + ut_event_manager.gc_finalize ); end; overriding member procedure on_event( self in out nocopy ut_reporter_base, a_event_name varchar2, a_event_item ut_event_item) is begin case a_event_name - when ut_utils.gc_before_run + when ut_event_manager.gc_initialize + then self.on_initialize(treat(a_event_item as ut_run)); + when ut_event_manager.gc_before_run then self.before_calling_run(treat(a_event_item as ut_run)); - when ut_utils.gc_before_suite + when ut_event_manager.gc_before_suite then self.before_calling_suite(treat(a_event_item as ut_logical_suite)); - when ut_utils.gc_before_before_all + when ut_event_manager.gc_before_before_all then self.before_calling_before_all(treat(a_event_item as ut_executable)); - when ut_utils.gc_before_before_each + when ut_event_manager.gc_before_before_each then self.before_calling_before_each(treat(a_event_item as ut_executable)); - when ut_utils.gc_before_test + when ut_event_manager.gc_before_test then self.before_calling_test(treat(a_event_item as ut_test)); - when ut_utils.gc_before_before_test + when ut_event_manager.gc_before_before_test then self.before_calling_before_test(treat(a_event_item as ut_executable)); - when ut_utils.gc_before_test_execute + when ut_event_manager.gc_before_test_execute then self.before_calling_test_execute(treat(a_event_item as ut_executable)); - when ut_utils.gc_before_after_test + when ut_event_manager.gc_before_after_test then self.before_calling_after_test(treat(a_event_item as ut_executable)); - when ut_utils.gc_before_after_each + when ut_event_manager.gc_before_after_each then self.before_calling_after_each(treat(a_event_item as ut_executable)); - when ut_utils.gc_before_after_all + when ut_event_manager.gc_before_after_all then self.before_calling_after_all(treat(a_event_item as ut_executable)); - when ut_utils.gc_after_run + when ut_event_manager.gc_after_run then self.after_calling_run(treat(a_event_item as ut_run)); - when ut_utils.gc_after_suite + when ut_event_manager.gc_after_suite then self.after_calling_suite(treat(a_event_item as ut_logical_suite)); - when ut_utils.gc_after_before_all + when ut_event_manager.gc_after_before_all then self.after_calling_before_all(treat(a_event_item as ut_executable)); - when ut_utils.gc_after_before_each + when ut_event_manager.gc_after_before_each then self.after_calling_before_each(treat(a_event_item as ut_executable)); - when ut_utils.gc_after_test + when ut_event_manager.gc_after_test then self.after_calling_test(treat(a_event_item as ut_test)); - when ut_utils.gc_after_before_test + when ut_event_manager.gc_after_before_test then self.after_calling_before_test(treat(a_event_item as ut_executable)); - when ut_utils.gc_after_test_execute + when ut_event_manager.gc_after_test_execute then self.after_calling_test_execute(treat(a_event_item as ut_executable)); - when ut_utils.gc_after_after_test + when ut_event_manager.gc_after_after_test then self.after_calling_after_test(treat(a_event_item as ut_executable)); - when ut_utils.gc_after_after_each + when ut_event_manager.gc_after_after_each then self.after_calling_after_each(treat(a_event_item as ut_executable)); - when ut_utils.gc_after_after_all + when ut_event_manager.gc_after_after_all then self.after_calling_after_all(treat(a_event_item as ut_executable)); - when ut_utils.gc_finalize + when ut_event_manager.gc_finalize then self.on_finalize(treat(a_event_item as ut_run)); + else null; end case; end; diff --git a/source/core/types/ut_reporter_base.tps b/source/core/types/ut_reporter_base.tps index 9543486f1..de157136e 100644 --- a/source/core/types/ut_reporter_base.tps +++ b/source/core/types/ut_reporter_base.tps @@ -1,7 +1,7 @@ create or replace type ut_reporter_base under ut_event_listener ( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -64,6 +64,9 @@ create or replace type ut_reporter_base under ut_event_listener ( -- This way, you may close all open outputs, files, connections etc. that need closing before the run finishes not instantiable member procedure on_finalize(self in out nocopy ut_reporter_base, a_run in ut_run), + -- This method is executed when run is getting initialized + not instantiable member procedure on_initialize(self in out nocopy ut_reporter_base, a_run in ut_run), + /** * Returns the list of events that are supported by particular implementation of the reporter */ diff --git a/source/expectations/data_values/ut_data_value_collection.tps b/source/core/types/ut_reporter_info.tps similarity index 65% rename from source/expectations/data_values/ut_data_value_collection.tps rename to source/core/types/ut_reporter_info.tps index 7c5d5285c..f09c42e07 100644 --- a/source/expectations/data_values/ut_data_value_collection.tps +++ b/source/core/types/ut_reporter_info.tps @@ -1,7 +1,7 @@ -create or replace type ut_data_value_collection under ut_data_value_anydata( +create or replace type ut_reporter_info as object ( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -15,9 +15,9 @@ create or replace type ut_data_value_collection under ut_data_value_anydata( See the License for the specific language governing permissions and limitations under the License. */ - - constructor function ut_data_value_collection(self in out nocopy ut_data_value_collection, a_value anydata) return self as result, - overriding member function is_empty return boolean - + object_name varchar2(250), + is_output_reporter varchar2(1), + is_instantiable varchar2(1), + is_final varchar2(1) ) / diff --git a/source/core/types/ut_reporters.tps b/source/core/types/ut_reporters.tps index 7df85c2f3..a2802bb26 100644 --- a/source/core/types/ut_reporters.tps +++ b/source/core/types/ut_reporters.tps @@ -1,7 +1,7 @@ create or replace type ut_reporters as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/types/ut_reporters_info.tps b/source/core/types/ut_reporters_info.tps new file mode 100644 index 000000000..82c264f36 --- /dev/null +++ b/source/core/types/ut_reporters_info.tps @@ -0,0 +1,19 @@ +create or replace type ut_reporters_info as + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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_reporter_info; +/ \ No newline at end of file diff --git a/source/core/types/ut_results_counter.tpb b/source/core/types/ut_results_counter.tpb index 2378bf640..811389e0e 100644 --- a/source/core/types/ut_results_counter.tpb +++ b/source/core/types/ut_results_counter.tpb @@ -1,7 +1,7 @@ create or replace type body ut_results_counter as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/types/ut_results_counter.tps b/source/core/types/ut_results_counter.tps index c3ed97d71..913ae0967 100644 --- a/source/core/types/ut_results_counter.tps +++ b/source/core/types/ut_results_counter.tps @@ -1,7 +1,7 @@ create or replace type ut_results_counter as object( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/types/ut_run.tpb b/source/core/types/ut_run.tpb index 0db9f38c0..660c88791 100644 --- a/source/core/types/ut_run.tpb +++ b/source/core/types/ut_run.tpb @@ -1,7 +1,7 @@ create or replace type body ut_run as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -18,35 +18,28 @@ create or replace type body ut_run as constructor function ut_run( self in out nocopy ut_run, - a_items ut_suite_items, - a_run_paths ut_varchar2_list := null, - a_schema_names ut_varchar2_rows := null, - a_exclude_objects ut_object_names := null, - a_include_objects ut_object_names := null, - a_project_file_mappings ut_file_mappings := null, - a_test_file_mappings ut_file_mappings := null, - a_client_character_set varchar2 := null + a_items ut_suite_items := null, + a_run_paths ut_varchar2_list := null, + a_coverage_options ut_coverage_options := null, + a_test_file_mappings ut_file_mappings := null, + a_client_character_set varchar2 := null, + a_random_test_order_seed positive := null, + a_run_tags varchar2 := null ) return self as result is - l_coverage_schema_names ut_varchar2_rows; - l_coverage_options ut_coverage_options; - l_exclude_objects ut_object_names; - begin + begin self.run_paths := a_run_paths; + self.run_tags := a_run_tags; self.self_type := $$plsql_unit; self.items := a_items; self.client_character_set := lower(a_client_character_set); + self.random_test_order_seed := a_random_test_order_seed; self.results_count := ut_results_counter(); self.test_file_mappings := coalesce(a_test_file_mappings, ut_file_mappings()); - self.coverage_options := ut_coverage_options( - a_schema_names, - a_exclude_objects, - a_include_objects, - a_project_file_mappings - ); + self.coverage_options := a_coverage_options; return; end; - overriding member procedure mark_as_skipped(self in out nocopy ut_run) is + overriding member procedure mark_as_skipped(self in out nocopy ut_run,a_skip_reason in varchar2) is begin null; end; @@ -56,7 +49,7 @@ create or replace type body ut_run as begin ut_utils.debug_log('ut_run.execute'); - ut_event_manager.trigger_event(ut_utils.gc_before_run, self); + ut_event_manager.trigger_event(ut_event_manager.gc_before_run, self); self.start_time := current_timestamp; -- clear anything that might stay in the session's cache @@ -70,11 +63,19 @@ create or replace type body ut_run as self.end_time := current_timestamp; - ut_event_manager.trigger_event(ut_utils.gc_after_run, self); + ut_event_manager.trigger_event(ut_event_manager.gc_after_run, self); return l_completed_without_errors; end; + overriding member procedure set_rollback_type(self in out nocopy ut_run, a_rollback_type integer, a_force boolean := false) is + begin + self.rollback_type := case when a_force then a_rollback_type else coalesce(self.rollback_type, a_rollback_type) end; + for i in 1 .. self.items.count loop + self.items(i).set_rollback_type(self.rollback_type, a_force); + end loop; + end; + overriding member procedure calc_execution_result(self in out nocopy ut_run) is l_result integer(1); begin @@ -93,19 +94,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_run.tps b/source/core/types/ut_run.tps index 5dc8e0399..1878a2d46 100644 --- a/source/core/types/ut_run.tps +++ b/source/core/types/ut_run.tps @@ -1,7 +1,7 @@ create or replace type ut_run under ut_suite_item ( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -21,22 +21,24 @@ create or replace type ut_run under ut_suite_item ( project_name varchar2(4000), items ut_suite_items, run_paths ut_varchar2_list, + run_tags varchar2(4000), coverage_options ut_coverage_options, test_file_mappings ut_file_mappings, client_character_set varchar2(100), + random_test_order_seed number(38,0), constructor function ut_run( self in out nocopy ut_run, - a_items ut_suite_items, - a_run_paths ut_varchar2_list := null, - a_schema_names ut_varchar2_rows := null, - a_exclude_objects ut_object_names := null, - a_include_objects ut_object_names := null, - a_project_file_mappings ut_file_mappings := null, - a_test_file_mappings ut_file_mappings := null, - a_client_character_set varchar2 := null + a_items ut_suite_items := null, + a_run_paths ut_varchar2_list := null, + a_coverage_options ut_coverage_options := null, + a_test_file_mappings ut_file_mappings := null, + a_client_character_set varchar2 := null, + a_random_test_order_seed positive := null, + a_run_tags varchar2 := null ) return self as result, - overriding member procedure mark_as_skipped(self in out nocopy ut_run), + overriding member procedure mark_as_skipped(self in out nocopy ut_run,a_skip_reason in varchar2), overriding member function do_execute(self in out nocopy ut_run) return boolean, + overriding member procedure set_rollback_type(self in out nocopy ut_run, a_rollback_type integer, a_force boolean := false), overriding member procedure calc_execution_result(self in out nocopy ut_run), overriding member procedure mark_as_errored(self in out nocopy ut_run, a_error_stack_trace varchar2), overriding member function get_error_stack_traces return ut_varchar2_list, diff --git a/source/core/types/ut_run_info.tpb b/source/core/types/ut_run_info.tpb new file mode 100644 index 000000000..6edc0f109 --- /dev/null +++ b/source/core/types/ut_run_info.tpb @@ -0,0 +1,48 @@ +create or replace type body ut_run_info as + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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 andTEST_GET_REPORTERS_LIST + limitations under the License. + */ + constructor function ut_run_info(self in out nocopy ut_run_info) return self as result is + l_ut_owner varchar2(250) := ut_utils.ut_owner; + begin + self.self_type := $$plsql_unit; + execute immediate + 'select /*+ no_parallel */ '||l_ut_owner||'.ut.version() from dual' + into self.ut_version; + + dbms_utility.db_version( self.db_version, self.db_compatibility ); + db_os_type := dbms_utility.port_string(); + + execute immediate + 'select /*+ no_parallel */ '||l_ut_owner||'.ut_key_value_pair(x.product, x.version) from product_component_version x' + bulk collect into self.db_component_version; + + execute immediate + 'select /*+ no_parallel */ '||l_ut_owner||'.ut_key_value_pair(x.parameter, x.value) + from nls_session_parameters x' + bulk collect into self.nls_session_params; + + execute immediate + 'select /*+ no_parallel */ '||l_ut_owner||'.ut_key_value_pair(x.parameter, x.value) from nls_instance_parameters x' + bulk collect into self.nls_instance_params; + + execute immediate + 'select /*+ no_parallel */ '||l_ut_owner||'.ut_key_value_pair(x.parameter, x.value) from nls_database_parameters x' + bulk collect into self.nls_db_params; + return; + end; +end; +/ diff --git a/source/core/types/ut_run_info.tps b/source/core/types/ut_run_info.tps new file mode 100644 index 000000000..4a3da691f --- /dev/null +++ b/source/core/types/ut_run_info.tps @@ -0,0 +1,28 @@ +create or replace type ut_run_info under ut_event_item ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + */ + ut_version varchar2(4000), + db_version varchar2(4000), + db_compatibility varchar2(4000), + db_os_type varchar2(4000), + db_component_version ut_key_value_pairs, + nls_session_params ut_key_value_pairs, + nls_instance_params ut_key_value_pairs, + nls_db_params ut_key_value_pairs, + constructor function ut_run_info(self in out nocopy ut_run_info) return self as result +); +/ diff --git a/source/core/types/ut_stack.tpb b/source/core/types/ut_stack.tpb new file mode 100644 index 000000000..b5f4e8747 --- /dev/null +++ b/source/core/types/ut_stack.tpb @@ -0,0 +1,58 @@ +create or replace type body ut_stack as + /* + utPLSQL - Version 3 + Copyright 2016 - 2023 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + constructor function ut_stack( self in out nocopy ut_stack) return self as result is + begin + self.tokens := ut_varchar2_list(); + self.top := 0; + return; + end ut_stack; + + member function peek(self in out nocopy ut_stack) return varchar2 is + l_token varchar2(32767); + begin + if self.tokens.count =0 or self.tokens is null then + l_token := null; + else + l_token := self.tokens(self.tokens.last); + end if; + return l_token; + end; + + member procedure push(self in out nocopy ut_stack, a_token varchar2) is + begin + self.tokens.extend; + self.tokens(self.tokens.last) := a_token; + self.top := self.tokens.count; + end push; + + member procedure pop(self in out nocopy ut_stack,a_cnt in integer default 1) is + begin + self.tokens.trim(a_cnt); + self.top := self.tokens.count; + end pop; + + member function pop(self in out nocopy ut_stack) return varchar2 is + l_token varchar2(32767) := self.tokens(self.tokens.last); + begin + self.pop(); + return l_token; + end; +end; +/ + diff --git a/source/core/types/ut_stack.tps b/source/core/types/ut_stack.tps new file mode 100644 index 000000000..23112fdde --- /dev/null +++ b/source/core/types/ut_stack.tps @@ -0,0 +1,26 @@ +create or replace type ut_stack as object ( + top integer, + tokens ut_varchar2_list, + /* + utPLSQL - Version 3 + Copyright 2016 - 2023 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + constructor function ut_stack( self in out nocopy ut_stack) return self as result, + member function peek(self in out nocopy ut_stack) return varchar2, + member procedure push(self in out nocopy ut_stack, a_token varchar2), + member procedure pop(self in out nocopy ut_stack,a_cnt in integer default 1), + member function pop(self in out nocopy ut_stack) return varchar2 +) +/ \ No newline at end of file diff --git a/source/core/types/ut_suite.tpb b/source/core/types/ut_suite.tpb index 9d9a60e8d..e3a4687d8 100644 --- a/source/core/types/ut_suite.tpb +++ b/source/core/types/ut_suite.tpb @@ -1,7 +1,7 @@ create or replace type body ut_suite as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -17,14 +17,16 @@ 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, + a_tags ut_varchar2_rows := null ) 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(); + self.tags := coalesce(a_tags,ut_varchar2_rows()); return; end; @@ -41,13 +43,11 @@ create or replace type body ut_suite as begin ut_utils.debug_log('ut_suite.execute'); - ut_utils.set_action(self.object_name); - if self.get_disabled_flag() then - self.mark_as_skipped(); + self.mark_as_skipped(a_skip_reason => self.disabled_reason); else - ut_event_manager.trigger_event(ut_utils.gc_before_suite, self); self.start_time := current_timestamp; + ut_event_manager.trigger_event(ut_event_manager.gc_before_suite, self); l_suite_savepoint := self.create_savepoint_if_needed(); @@ -78,11 +78,9 @@ create or replace type body ut_suite as self.calc_execution_result(); self.end_time := current_timestamp; - ut_event_manager.trigger_event(ut_utils.gc_after_suite, self); + ut_event_manager.trigger_event(ut_event_manager.gc_after_suite, self); end if; - ut_utils.set_action(null); - return l_no_errors; end; diff --git a/source/core/types/ut_suite.tps b/source/core/types/ut_suite.tps index f56d95c08..ff7f3e171 100644 --- a/source/core/types/ut_suite.tps +++ b/source/core/types/ut_suite.tps @@ -1,7 +1,7 @@ create or replace type ut_suite under ut_logical_suite ( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -27,7 +27,8 @@ 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, + a_tags ut_varchar2_rows := null ) 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_cache_row.tps b/source/core/types/ut_suite_cache_row.tps new file mode 100644 index 000000000..c147a8757 --- /dev/null +++ b/source/core/types/ut_suite_cache_row.tps @@ -0,0 +1,41 @@ +create or replace type ut_suite_cache_row as object ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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 number(22,0), + self_type varchar2(250 byte), + path varchar2(1000 byte), + object_owner varchar2(250 byte), + object_name varchar2(250 byte), + name varchar2(250 byte), + line_no number, + parse_time timestamp (6), + description varchar2(4000 byte), + rollback_type number, + disabled_flag number, + disabled_reason varchar2(4000 byte), + warnings ut_varchar2_rows, + before_all_list ut_executables, + after_all_list ut_executables, + before_each_list ut_executables, + before_test_list ut_executables, + after_each_list ut_executables, + after_test_list ut_executables, + expected_error_codes ut_varchar2_rows, + tags ut_varchar2_rows, + item ut_executable_test +) +/ \ No newline at end of file diff --git a/source/core/types/ut_suite_cache_rows.tps b/source/core/types/ut_suite_cache_rows.tps new file mode 100644 index 000000000..9b6919df5 --- /dev/null +++ b/source/core/types/ut_suite_cache_rows.tps @@ -0,0 +1,19 @@ +create type ut_suite_cache_rows as + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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_cache_row +/ \ No newline at end of file diff --git a/source/core/types/ut_suite_context.tpb b/source/core/types/ut_suite_context.tpb index a4add114b..be92e6fc9 100644 --- a/source/core/types/ut_suite_context.tpb +++ b/source/core/types/ut_suite_context.tpb @@ -1,7 +1,7 @@ create or replace type body ut_suite_context as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -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..5e3d20f87 100644 --- a/source/core/types/ut_suite_context.tps +++ b/source/core/types/ut_suite_context.tps @@ -1,7 +1,7 @@ create or replace type ut_suite_context under ut_suite ( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -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..648f10dd1 100644 --- a/source/core/types/ut_suite_item.tpb +++ b/source/core/types/ut_suite_item.tpb @@ -1,7 +1,7 @@ create or replace type body ut_suite_item as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -16,20 +16,17 @@ 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); + self.disabled_reason := null; end; member function get_disabled_flag return boolean is @@ -37,9 +34,9 @@ create or replace type body ut_suite_item as return ut_utils.int_to_boolean(self.disabled_flag); end; - member procedure set_rollback_type(self in out nocopy ut_suite_item, a_rollback_type integer) is + member procedure set_rollback_type(self in out nocopy ut_suite_item, a_rollback_type integer, a_force boolean := false) is begin - self.rollback_type := coalesce(self.rollback_type, a_rollback_type); + self.rollback_type := case when a_force then a_rollback_type else coalesce(self.rollback_type, a_rollback_type) end; end; member function get_rollback_type return integer is @@ -47,7 +44,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(); @@ -65,18 +62,26 @@ final member procedure do_execute(self in out nocopy ut_suite_item) is member procedure rollback_to_savepoint(self in out nocopy ut_suite_item, a_savepoint varchar2) is ex_savepoint_not_exists exception; + l_transaction_invalidators clob; pragma exception_init(ex_savepoint_not_exists, -1086); + l_savepoint varchar2(250); begin if get_rollback_type() = ut_utils.gc_rollback_auto and a_savepoint is not null then - execute immediate 'rollback to ' || a_savepoint; + l_savepoint := sys.dbms_assert.qualified_sql_name(a_savepoint); + execute immediate 'rollback to ' || l_savepoint; end if; exception when ex_savepoint_not_exists then + l_transaction_invalidators := + lower( ut_utils.indent_lines( ut_utils.table_to_clob( self.get_transaction_invalidators() ), 2, true ) ); + if length(l_transaction_invalidators) > 3000 then + l_transaction_invalidators := substr(l_transaction_invalidators,1,3000)||'...'; + end if; put_warning( 'Unable to perform automatic rollback after test' - || case when self_type like '%SUITE' then ' suite' end || '. ' + || case when self_type like '%SUITE' then ' suite' when self_type like '%CONTEXT' then ' context' end || '. ' ||'An implicit or explicit commit/rollback occurred in procedures:'||chr(10) - ||lower(ut_utils.indent_lines(ut_utils.table_to_clob(self.get_transaction_invalidators()), 2, true))||chr(10) + ||l_transaction_invalidators||chr(10) ||'Use the "--%rollback(manual)" annotation or remove commit/rollback/ddl statements that are causing the issue.' ); end; @@ -93,6 +98,16 @@ final member procedure do_execute(self in out nocopy ut_suite_item) is self.results_count.increase_warning_count; end; + member procedure put_warning(self in out nocopy ut_suite_item, a_message varchar2, a_procedure_name varchar2, a_line_no integer) is + l_result varchar2(1000); + begin + l_result := self.object_owner || '.' || self.object_name ; + if a_procedure_name is not null then + l_result := l_result || '.' || a_procedure_name ; + end if; + put_warning( a_message || chr( 10 ) || 'at package "' || upper(l_result) || '", line ' || a_line_no ); + end; + member function get_transaction_invalidators return ut_varchar2_list is begin return transaction_invalidators; diff --git a/source/core/types/ut_suite_item.tps b/source/core/types/ut_suite_item.tps index 52b6a2a19..8184f2a63 100644 --- a/source/core/types/ut_suite_item.tps +++ b/source/core/types/ut_suite_item.tps @@ -1,7 +1,7 @@ create or replace type ut_suite_item force under ut_event_item ( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -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) */ @@ -36,7 +36,7 @@ create or replace type ut_suite_item force under ut_event_item ( /** * Full path of the invocation of the item (including the items name itself) */ - path varchar2(4000 byte), + path varchar2(1000 byte), /** * The type of the rollback behavior */ @@ -45,18 +45,33 @@ 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), + /** + * Indicates reason whysa test is to be disabled by execution + */ + disabled_reason varchar2(4000), + /** + * 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), + /** + * Hold list of tags assign to test + */ + tags ut_varchar2_rows, + 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), + not instantiable member procedure mark_as_skipped(self in out nocopy ut_suite_item, a_skip_reason in varchar2), + member procedure set_rollback_type(self in out nocopy ut_suite_item, a_rollback_type integer, a_force boolean := false), member function get_rollback_type return integer, member function create_savepoint_if_needed return varchar2, member procedure rollback_to_savepoint(self in out nocopy ut_suite_item, a_savepoint varchar2), @@ -73,7 +88,8 @@ create or replace type ut_suite_item force under ut_event_item ( not instantiable member procedure mark_as_errored(self in out nocopy ut_suite_item, a_error_stack_trace varchar2), not instantiable member function get_error_stack_traces return ut_varchar2_list, not instantiable member function get_serveroutputs return clob, - member procedure put_warning(self in out nocopy ut_suite_item, a_message varchar2) + member procedure put_warning(self in out nocopy ut_suite_item, a_message varchar2), + member procedure put_warning(self in out nocopy ut_suite_item, a_message varchar2, a_procedure_name varchar2, a_line_no integer) ) not final not instantiable / diff --git a/source/core/types/ut_suite_items.tps b/source/core/types/ut_suite_items.tps index ff5709ca8..615283446 100644 --- a/source/core/types/ut_suite_items.tps +++ b/source/core/types/ut_suite_items.tps @@ -1,7 +1,7 @@ create or replace type ut_suite_items as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/types/ut_test.tpb b/source/core/types/ut_test.tpb index f6495ecd6..946f8990d 100644 --- a/source/core/types/ut_test.tpb +++ b/source/core/types/ut_test.tpb @@ -1,7 +1,7 @@ create or replace type body ut_test as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -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_varchar2_rows := null, a_tags ut_varchar2_rows := 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(); @@ -31,18 +31,20 @@ create or replace type body ut_test as self.all_expectations := ut_expectation_results(); self.failed_expectations := ut_expectation_results(); self.expected_error_codes := a_expected_error_codes; + self.tags := coalesce(a_tags,ut_varchar2_rows()); return; end; - overriding member procedure mark_as_skipped(self in out nocopy ut_test) is + overriding member procedure mark_as_skipped(self in out nocopy ut_test, a_skip_reason in varchar2) is begin - ut_event_manager.trigger_event(ut_utils.gc_before_test, self); + ut_event_manager.trigger_event(ut_event_manager.gc_before_test, self); self.start_time := current_timestamp; self.result := ut_utils.gc_disabled; + self.disabled_reason := coalesce(a_skip_reason,self.disabled_reason); ut_utils.debug_log('ut_test.execute - disabled'); self.results_count.set_counter_values(self.result); self.end_time := self.start_time; - ut_event_manager.trigger_event(ut_utils.gc_after_test, self); + ut_event_manager.trigger_event(ut_event_manager.gc_after_test, self); end; overriding member function do_execute(self in out nocopy ut_test) return boolean is @@ -53,10 +55,10 @@ create or replace type body ut_test as ut_utils.debug_log('ut_test.execute'); if self.get_disabled_flag() then - mark_as_skipped(); + mark_as_skipped(self.disabled_reason); else - ut_event_manager.trigger_event(ut_utils.gc_before_test, self); self.start_time := current_timestamp; + ut_event_manager.trigger_event(ut_event_manager.gc_before_test, self); l_savepoint := self.create_savepoint_if_needed(); @@ -91,13 +93,13 @@ create or replace type body ut_test as self.calc_execution_result(); self.end_time := current_timestamp; - ut_event_manager.trigger_event(ut_utils.gc_after_test, self); + ut_event_manager.trigger_event(ut_event_manager.gc_after_test, self); end if; return l_no_errors; 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 +109,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); @@ -117,12 +119,12 @@ create or replace type body ut_test as overriding member procedure mark_as_errored(self in out nocopy ut_test, a_error_stack_trace varchar2) is begin ut_utils.debug_log('ut_test.fail'); - ut_event_manager.trigger_event(ut_utils.gc_before_test, self); + ut_event_manager.trigger_event(ut_event_manager.gc_before_test, self); self.start_time := current_timestamp; self.parent_error_stack_trace := a_error_stack_trace; self.calc_execution_result(); self.end_time := self.start_time; - ut_event_manager.trigger_event(ut_utils.gc_after_test, self); + ut_event_manager.trigger_event(ut_event_manager.gc_after_test, self); end; overriding member function get_error_stack_traces(self ut_test) return ut_varchar2_list is @@ -162,5 +164,15 @@ create or replace type body ut_test as end loop; return l_outputs; end; + + member function get_failed_expectation_lines return ut_varchar2_rows is + l_results ut_varchar2_rows; + begin + for i in 1 .. failed_expectations.count loop + ut_utils.append_to_list( l_results, ut_utils.convert_collection( failed_expectations(i).get_result_lines() ) ); + ut_utils.append_to_list( l_results, failed_expectations(i).caller_info ); + end loop; + return l_results; + end; end; / diff --git a/source/core/types/ut_test.tps b/source/core/types/ut_test.tps index d26e220b9..dbba64961 100644 --- a/source/core/types/ut_test.tps +++ b/source/core/types/ut_test.tps @@ -1,7 +1,7 @@ -create or replace type ut_test under ut_suite_item ( +create or replace type ut_test force under ut_suite_item ( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -54,16 +54,17 @@ create or replace type ut_test under ut_suite_item ( /** *Holds the expected error codes list when the user use the annotation throws */ - expected_error_codes ut_integer_list, + expected_error_codes ut_varchar2_rows, 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_varchar2_rows := null, a_tags ut_varchar2_rows := null ) return self as result, - overriding member procedure mark_as_skipped(self in out nocopy ut_test), + overriding member procedure mark_as_skipped(self in out nocopy ut_test, a_skip_reason in varchar2), overriding member function do_execute(self in out nocopy ut_test) return boolean, overriding member procedure calc_execution_result(self in out nocopy ut_test), overriding member procedure mark_as_errored(self in out nocopy ut_test, a_error_stack_trace varchar2), overriding member function get_error_stack_traces(self ut_test) return ut_varchar2_list, - overriding member function get_serveroutputs return clob + overriding member function get_serveroutputs return clob, + member function get_failed_expectation_lines return ut_varchar2_rows ) / diff --git a/source/core/types/ut_varchar2_list.tps b/source/core/types/ut_varchar2_list.tps index f324a2842..f0b5df509 100644 --- a/source/core/types/ut_varchar2_list.tps +++ b/source/core/types/ut_varchar2_list.tps @@ -1,7 +1,7 @@ create or replace type ut_varchar2_list as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/types/ut_varchar2_rows.tps b/source/core/types/ut_varchar2_rows.tps index ba8962378..e7fa29c29 100644 --- a/source/core/types/ut_varchar2_rows.tps +++ b/source/core/types/ut_varchar2_rows.tps @@ -1,7 +1,7 @@ create or replace type ut_varchar2_rows as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/ut_dbms_output_cache.sql b/source/core/ut_dbms_output_cache.sql index 2102ab4ee..e61b403c8 100644 --- a/source/core/ut_dbms_output_cache.sql +++ b/source/core/ut_dbms_output_cache.sql @@ -1,6 +1,6 @@ /* utPLSQL - Version 3 -Copyright 2016 - 2018 utPLSQL Project +Copyright 2016 - 2021 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 @@ -19,7 +19,7 @@ limitations under the License. declare l_tab_exist number; begin - select count(*) into l_tab_exist from + select /*+ no_parallel */ count(*) into l_tab_exist from (select table_name from all_tables where table_name = 'UT_DBMS_OUTPUT_CACHE' and owner = sys_context('USERENV','CURRENT_SCHEMA') union all select synonym_name from all_synonyms where synonym_name = 'UT_DBMS_OUTPUT_CACHE' and owner = sys_context('USERENV','CURRENT_SCHEMA')); diff --git a/source/core/ut_expectation_processor.pkb b/source/core/ut_expectation_processor.pkb index 45dfb7dee..c165a9ee5 100644 --- a/source/core/ut_expectation_processor.pkb +++ b/source/core/ut_expectation_processor.pkb @@ -1,7 +1,7 @@ create or replace package body ut_expectation_processor as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -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; @@ -73,30 +73,43 @@ create or replace package body ut_expectation_processor as l_expectations_results(l_expectations_results.last) := g_expectations_called(i); end if; end loop; - ut_utils.debug_log('ut_expectation_processor.get_failed_expectations: l_expectations_results.count='||g_expectations_called.count); + ut_utils.debug_log('ut_expectation_processor.get_failed_expectations: l_expectations_results.count='||l_expectations_results.count); return l_expectations_results; end get_failed_expectations; procedure add_expectation_result(a_expectation_result ut_expectation_result) is - begin - ut_utils.debug_log('ut_expectation_processor.add_expectation_result'); - g_expectations_called.extend; - g_expectations_called(g_expectations_called.last) := a_expectation_result; + l_results ut_varchar2_list; + begin + if ut_session_context.is_ut_run then + ut_event_manager.trigger_event(ut_event_manager.gc_debug, a_expectation_result); + g_expectations_called.extend; + g_expectations_called(g_expectations_called.last) := a_expectation_result; + else + l_results := a_expectation_result.get_result_lines(); + dbms_output.put_line( upper( ut_utils.test_result_to_char( a_expectation_result.status ) ) || ''); + for i in 1 .. l_results.count loop + dbms_output.put_line( ' ' || l_results(i) ); + end loop; + if a_expectation_result.caller_info is not null then + dbms_output.put_line( ut_utils.indent_lines( a_expectation_result.caller_info, 2, true) ); + end if; + end if; end; procedure report_failure(a_message in varchar2) is begin add_expectation_result(ut_expectation_result(ut_utils.gc_failure, null, a_message)); end; - + function get_session_parameters return tt_nls_params is l_session_params tt_nls_params; begin - select nsp.parameter, nsp.value + select /*+ no_parallel */ nsp.parameter, nsp.value bulk collect into l_session_params from nls_session_parameters nsp where parameter - in ( 'NLS_DATE_FORMAT', 'NLS_TIMESTAMP_FORMAT', 'NLS_TIMESTAMP_TZ_FORMAT'); + in ( 'NLS_DATE_FORMAT', 'NLS_TIMESTAMP_FORMAT', 'NLS_TIMESTAMP_TZ_FORMAT') + order by 1; return l_session_params; end; @@ -113,7 +126,6 @@ create or replace package body ut_expectation_processor as when insuf_privs then NULL; end; - execute immediate 'alter session set nls_date_format = '''||ut_utils.gc_date_format||''''; execute immediate 'alter session set nls_timestamp_format = '''||ut_utils.gc_timestamp_format||''''; execute immediate 'alter session set nls_timestamp_tz_format = '''||ut_utils.gc_timestamp_tz_format||''''; end; @@ -138,28 +150,55 @@ create or replace package body ut_expectation_processor as function who_called_expectation(a_call_stack varchar2) return varchar2 is l_caller_stack_line varchar2(4000); + l_call_stack varchar2(4000); l_line_no integer; l_owner varchar2(1000); l_object_name varchar2(1000); - l_object_full_name varchar2(1000); l_result varchar2(4000); -- in 12.2 format_call_stack reportes not only package name, but also the procedure name -- when 11g and 12c reports only package name - c_expectation_search_pattern constant varchar2(500) := - '(.*\.(UT_EXPECTATION[A-Z0-9#_$]*|UT|UTASSERT2?)(\.[A-Z0-9#_$]+)?\s+)+(.*)'; + function cut_header_and_expectations( a_stack varchar2 ) return varchar2 is + begin + return regexp_substr( a_stack, '(.*\.(UT_EQUAL|UT_BE_WITHIN[[:alnum:]$#_]*|UT_EXPECTATION[[:alnum:]$#_]*|UT|UTASSERT2?)(\.[[:alnum:]$#_]+)?\s+)+((.|\s)*)', 1, 1, 'm', 4); + end; + function cut_address_columns( a_stack varchar2 ) return varchar2 is + begin + return regexp_replace( a_stack, '^(0x)?[[:digit:]abcdef]+\s+', '', 1, 0, 'mi' ); + end; + function cut_framework_stack( a_stack varchar2 ) return varchar2 is + begin + return regexp_replace( + a_stack, + '[0-9]+\s+anonymous\s+block\s+[0-9]+\s+package\s+body\s+sys\.dbms_sql(\.execute)?\s+[0-9]+\s+[[:alnum:]_$# ]+\.ut_executable.*', + '', + 1, 1, 'mni' + ); + end; + function format_stack( a_stack varchar2 ) return varchar2 is + begin + return regexp_replace( + a_stack, + '([0-9]+)\s+(.* )?((anonymous block)|(([[:alnum:]$#_]+\.[[:alnum:]$#_]+(\.([[:alnum:]$#_])+)?)))', + 'at "\3", line \1', 1, 0, 'i' + ); + end; begin - l_caller_stack_line := regexp_substr( a_call_stack, c_expectation_search_pattern, 1, 1, 'm', 4); + l_call_stack := cut_header_and_expectations( a_call_stack ); + l_call_stack := cut_address_columns( l_call_stack ); + l_call_stack := cut_framework_stack( l_call_stack ); + l_call_stack := format_stack( l_call_stack ); + l_caller_stack_line := regexp_substr(l_call_stack,'^(.*)'); if l_caller_stack_line like '%.%' then - l_line_no := to_number( regexp_substr(l_caller_stack_line,'(0x)?[0-9a-f]+\s+(\d+)',subexpression => 2) ); - l_owner := regexp_substr(l_caller_stack_line,'([A-Za-z0-9$#_]+)\.([A-Za-z0-9$#_]|\.)+',subexpression => 1); - l_object_name := regexp_substr(l_caller_stack_line,'([A-Za-z0-9$#_]+)\.([A-Za-z0-9$#_]+)',subexpression => 2); - l_object_full_name := regexp_substr(l_caller_stack_line,'([A-Za-z0-9$#_]+)\.(([A-Za-z0-9$#_]|\.)+)',subexpression => 2); - if l_owner is not null and l_object_name is not null and l_line_no is not null then - l_result := 'at "' || l_owner || '.' || l_object_full_name || '", line '|| l_line_no || ' ' - || ut_metadata.get_source_definition_line(l_owner, l_object_name, l_line_no); - end if; + l_line_no := to_number( regexp_substr( l_caller_stack_line, ', line (\d+)', subexpression => 1 ) ); + l_owner := regexp_substr( l_caller_stack_line, 'at "([[:alnum:]$#_]+)\.(([[:alnum:]$#_]+)(\.([[:alnum:]$#_]+))?)", line (\d+)', subexpression => 1 ); + l_object_name := regexp_substr( l_caller_stack_line, 'at "([[:alnum:]$#_]+)\.(([[:alnum:]$#_]+)(\.([[:alnum:]$#_]+))?)", line (\d+)', subexpression => 3 ); + l_result := + l_caller_stack_line || ' ' || rtrim(ut_metadata.get_source_definition_line(l_owner, l_object_name, l_line_no),chr(10)) + || replace( l_call_stack, l_caller_stack_line ); + else + l_result := l_call_stack; end if; - return l_result; + return rtrim(l_result,chr(10)); end; procedure add_warning(a_messsage varchar2) is @@ -176,7 +215,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..dd9187526 100644 --- a/source/core/ut_expectation_processor.pks +++ b/source/core/ut_expectation_processor.pks @@ -1,7 +1,7 @@ create or replace package ut_expectation_processor authid current_user as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -35,7 +35,7 @@ create or replace package ut_expectation_processor authid current_user as procedure add_expectation_result(a_expectation_result ut_expectation_result); procedure report_failure(a_message in varchar2); - + procedure set_xml_nls_params; procedure reset_nls_params; @@ -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_file_mapper.pkb b/source/core/ut_file_mapper.pkb index 35233b57b..425360533 100644 --- a/source/core/ut_file_mapper.pkb +++ b/source/core/ut_file_mapper.pkb @@ -1,7 +1,7 @@ create or replace package body ut_file_mapper is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/ut_file_mapper.pks b/source/core/ut_file_mapper.pks index 5402ef6e8..adc4c983f 100644 --- a/source/core/ut_file_mapper.pks +++ b/source/core/ut_file_mapper.pks @@ -1,7 +1,7 @@ create or replace package ut_file_mapper authid current_user is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/core/ut_metadata.pkb b/source/core/ut_metadata.pkb index 30b0da64e..360b7b97d 100644 --- a/source/core/ut_metadata.pkb +++ b/source/core/ut_metadata.pkb @@ -1,7 +1,7 @@ create or replace package body ut_metadata as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -21,33 +21,6 @@ create or replace package body ut_metadata as g_cached_object varchar2(500); ------------------------------ --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 - l_dblink varchar2(200); - l_part1_type number; - l_object_number number; - begin - l_name := form_name(a_owner, a_object, a_procedure_name); - - dbms_utility.name_resolve(name => l_name - ,context => l_context - ,schema => a_owner - ,part1 => a_object - ,part2 => a_procedure_name - ,dblink => l_dblink - ,part1_type => l_part1_type - ,object_number => l_object_number); - - end do_resolve; - function form_name(a_owner_name varchar2, a_object varchar2, a_subprogram varchar2 default null) return varchar2 is l_name varchar2(200); begin @@ -63,25 +36,16 @@ create or replace package body ut_metadata as function package_valid(a_owner_name varchar2, a_package_name in varchar2) return boolean as l_cnt number; - 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; - l_package_name := a_package_name; - - do_resolve(l_schema, l_package_name, l_procedure_name); - - execute immediate q'[select count(decode(status, 'VALID', 1, null)) / count(*) + execute immediate q'[select /*+ no_parallel */ count(*) from ]'||l_view_name||q'[ - where owner = :l_schema - and object_name = :l_package_name - and object_type in ('PACKAGE')]' - into l_cnt using l_schema, l_package_name; - - -- expect both package and body to be valid + where owner = :a_owner_name + and object_name = :a_package_name + and object_type = 'PACKAGE' + and status = 'VALID']' + into l_cnt using upper(a_owner_name), upper(a_package_name); return l_cnt = 1; exception when others then @@ -91,22 +55,12 @@ create or replace package body ut_metadata as function procedure_exists(a_owner_name varchar2, a_package_name in varchar2, a_procedure_name in varchar2) return boolean as l_cnt number; - l_schema varchar2(200); - l_package_name varchar2(200); - l_procedure_name varchar2(200); l_view_name varchar2(200) := get_dba_view('dba_procedures'); begin - - l_schema := a_owner_name; - l_package_name := a_package_name; - l_procedure_name := a_procedure_name; - - do_resolve(l_schema, l_package_name, l_procedure_name); - execute immediate - 'select count(*) from '||l_view_name - ||' where owner = :l_schema and object_name = :l_package_name and procedure_name = :l_procedure_name' - into l_cnt using l_schema, l_package_name, l_procedure_name; + 'select /*+ no_parallel */ count(*) from '||l_view_name + ||' where owner = :l_schema and object_name = :l_package_name and procedure_name = :l_procedure_name and rownum = 1' + into l_cnt using a_owner_name, a_package_name, a_procedure_name; --expect one method only for the package with that name. return l_cnt = 1; @@ -116,15 +70,14 @@ 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 if not nvl(c_key = g_cached_object, false) then g_cached_object := c_key; execute immediate - 'select trim(text) text + 'select /*+ no_parallel */ trim(text) text from '||l_view_name||q'[ s where s.owner = :a_owner and s.name = :a_object_name @@ -148,22 +101,63 @@ 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_has_execute_any varchar2(1); + begin + select /*+ no_parallel */ decode( count( 1 ), 0, 'N', 'Y' ) + into l_has_execute_any + from dual + where + exists( + select 1 + from + role_sys_privs + join session_roles + using ( role ) + where privilege = 'EXECUTE ANY PROCEDURE' + ) or + exists( + select 1 + from user_sys_privs + where privilege = 'EXECUTE ANY PROCEDURE' + ); + return l_has_execute_any = 'Y'; + 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 l_cnt number; c_current_schema constant all_tables.owner%type := sys_context('USERENV','CURRENT_SCHEMA'); begin - select count(*) + select /*+ no_parallel */ count(*) into l_cnt from all_objects t where t.object_name = a_object_name @@ -172,6 +166,170 @@ create or replace package body ut_metadata as return l_cnt > 0; end; + function is_collection (a_anytype_code in integer) return boolean is + begin + return coalesce(a_anytype_code in (dbms_types.typecode_varray,dbms_types.typecode_table,dbms_types.typecode_namedcollection),false); + end; + + function is_collection (a_owner varchar2, a_type_name varchar2) return boolean is + begin + return is_collection( + get_anytype_members_info( + get_user_defined_type(a_owner, a_type_name) + ).type_code + ); + end; + + function get_attr_elem_info( a_anytype anytype, a_pos pls_integer := null ) + return t_anytype_elem_info_rec is + l_result t_anytype_elem_info_rec; + begin + if a_anytype is not null then + l_result.type_code := a_anytype.getattreleminfo( + pos => a_pos, + prec => l_result.precision, + scale => l_result.scale, + len => l_result.length, + csid => l_result.char_set_id, + csfrm => l_result.char_set_frm, + attr_elt_type => l_result.attr_elt_type, + aname => l_result.attribute_name + ); + end if; + return l_result; + end; + + function get_anytype_members_info( a_anytype anytype ) + return t_anytype_members_rec is + l_result t_anytype_members_rec; + begin + if a_anytype is not null then + l_result.type_code := a_anytype.getinfo( + prec => l_result.precision, + scale => l_result.scale, + len => l_result.length, + csid => l_result.char_set_id, + csfrm => l_result.char_set_frm, + schema_name => l_result.schema_name, + type_name => l_result.type_name, + version => l_result.version, + numelems => l_result.elements_count + ); + end if; + return l_result; + end; + + function get_user_defined_type(a_owner varchar2, a_type_name varchar2) return anytype is + l_anytype anytype; + not_found exception; + pragma exception_init(not_found,-22303); + begin + if a_type_name is not null then + begin + if ut_metadata.is_object_visible('GETANYTYPEFROMPERSISTENT') then + execute immediate 'begin :l_anytype := getanytypefrompersistent( :a_owner, :a_type_name ); end;' + using out l_anytype, in nvl(a_owner,sys_context('userenv','current_schema')), in a_type_name; + else + execute immediate 'begin :l_anytype := anytype.getpersistent( :a_owner, :a_type_name ); end;' + using out l_anytype, in nvl(a_owner,sys_context('userenv','current_schema')), in a_type_name; + end if; + exception + when not_found then + null; + end; + end if; + return l_anytype; + end; + + function get_collection_element(a_anydata in anydata) return varchar2 + is + l_anytype anytype; + l_nested_type t_anytype_members_rec; + l_elements_rec t_anytype_elem_info_rec; + l_type_code integer; + begin + l_type_code := a_anydata.gettype(l_anytype); + if is_collection(l_type_code) then + l_elements_rec := get_attr_elem_info(l_anytype); + if l_elements_rec.attr_elt_type is null then + l_nested_type := get_anytype_members_info(l_anytype); + else + l_nested_type := get_anytype_members_info(l_elements_rec.attr_elt_type); + end if; + end if; + return l_nested_type.schema_name || '.' ||l_nested_type.type_name; + end; + + function has_collection_members (a_anydata in anydata) return boolean is + l_anytype anytype; + l_elements_rec t_anytype_elem_info_rec; + l_type_code integer; + begin + l_type_code := a_anydata.gettype(l_anytype); + l_elements_rec := get_attr_elem_info(l_anytype); + return l_elements_rec.attr_elt_type is not null; + end; + + function get_anydata_typename(a_data_value anydata) return varchar2 + is + begin + return case when a_data_value is not null then lower(a_data_value.gettypename()) else 'undefined' end; + end; + + function is_anytype_null(a_value in anydata, a_compound_type in varchar2) return number is + l_result integer := 0; + l_anydata_sql varchar2(4000); + l_compound_type varchar2(250); + begin + if a_value is not null then + l_compound_type := sys.dbms_assert.qualified_sql_name(a_compound_type); + l_anydata_sql := ' + declare + l_data '||get_anydata_typename(a_value)||'; + l_value anydata := :a_value; + l_status integer; + begin + l_status := l_value.get'||l_compound_type||'(l_data); + :l_data_is_null := case when l_data is null then 1 else 0 end; + end;'; + execute immediate l_anydata_sql using in a_value, out l_result; + else + l_result := 1; + end if; + return l_result; + end; + + function get_object_name(a_full_object_name in varchar2) return varchar2 is + l_result varchar2(250); + begin + l_result := regexp_substr( + a_full_object_name, + '^([[:alnum:]$#_]+|".*?")\.([[:alnum:]$#_]+|".*?")', subexpression => 2 + ); + if not l_result like '"%"' then + l_result := upper(l_result); + end if; + return ut_utils.qualified_sql_name(l_result); + end; + + function get_anydata_compound_type(a_data_value anydata) return varchar2 is + l_result varchar2(30); + l_type anytype; + l_type_code integer; + begin + if a_data_value is not null then + l_type_code := a_data_value.gettype(l_type); + if l_type_code in (dbms_types.typecode_table, dbms_types.typecode_varray, dbms_types.typecode_namedcollection, + dbms_types.typecode_object) then + if l_type_code = dbms_types.typecode_object then + l_result := 'object'; + else + l_result := 'collection'; + end if; + end if; + end if; + return l_result; + end; end; / diff --git a/source/core/ut_metadata.pks b/source/core/ut_metadata.pks index 121524a0b..27bfa5d30 100644 --- a/source/core/ut_metadata.pks +++ b/source/core/ut_metadata.pks @@ -1,7 +1,7 @@ create or replace package ut_metadata authid current_user as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -20,6 +20,31 @@ create or replace package ut_metadata authid current_user as * Common package for all code that reads from the system tables. */ + type t_anytype_members_rec is record ( + type_code pls_integer, + schema_name varchar2(128), + type_name varchar2(128), + length pls_integer, + elements_count pls_integer, + version varchar2(32767), + precision pls_integer, + scale pls_integer, + char_set_id pls_integer, + char_set_frm pls_integer + ); + + type t_anytype_elem_info_rec is record ( + type_code pls_integer, + attribute_name varchar2(260), + length pls_integer, + version varchar2(32767), + precision pls_integer, + scale pls_integer, + char_set_id pls_integer, + char_set_frm pls_integer, + attr_elt_type anytype + ); + /** * Forms correct object/subprogram name to call as owner.object[.subprogram] * @@ -39,18 +64,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 - * - */ - procedure do_resolve(a_owner in out nocopy varchar2, a_object in out nocopy varchar2, a_procedure_name in out nocopy varchar2); - /** * Return the text of the source line for a given object (body). It excludes package spec and type spec */ @@ -64,16 +77,93 @@ 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 */ function package_exists_in_cur_schema(a_object_name varchar2) return boolean; + /** + * Returns true if given typecode is a collection typecode + */ + function is_collection(a_anytype_code in integer) return boolean; + + /** + * Returns true if given object is a collection + */ + function is_collection(a_owner varchar2, a_type_name varchar2) return boolean; + + /** + * Returns a descriptor of anytype + */ + function get_anytype_members_info( a_anytype anytype ) return t_anytype_members_rec; + + /** + * Returns a descriptor of anytype attribute + */ + function get_attr_elem_info( a_anytype anytype, a_pos pls_integer := null ) return t_anytype_elem_info_rec; + + /** + * Returns ANYTYPE descriptor of an object type + */ + function get_user_defined_type(a_owner varchar2, a_type_name varchar2) return anytype; + + /** + * Return fully qualified name of the object from collection, if not collection returns null + */ + function get_collection_element(a_anydata in anydata) return varchar2; + + /** + * Check if collection got elements + */ + function has_collection_members (a_anydata in anydata) return boolean; + + /** + * Get typename from anydata + */ + function get_anydata_typename(a_data_value anydata) return varchar2; + + /** + * Is anydata object/collection is null + */ + function is_anytype_null(a_value in anydata, a_compound_type in varchar2) return number; + + /** + * Get object name from fully qualified name e.g ut3.test -> test + */ + function get_object_name(a_full_object_name in varchar2) return varchar2; + + /** + * Based on anydata decide if its a object or collection + */ + function get_anydata_compound_type(a_data_value anydata) return varchar2; + end ut_metadata; / diff --git a/source/core/ut_savepoint_seq.sql b/source/core/ut_savepoint_seq.sql new file mode 100644 index 000000000..5b0cda35e --- /dev/null +++ b/source/core/ut_savepoint_seq.sql @@ -0,0 +1,15 @@ +create sequence ut_savepoint_seq + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + start with 1 cache 20 minvalue 1 maxvalue 99999999999999999 cycle; \ No newline at end of file diff --git a/source/core/ut_suite_builder.pkb b/source/core/ut_suite_builder.pkb index 8558b4331..ebb113370 100644 --- a/source/core/ut_suite_builder.pkb +++ b/source/core/ut_suite_builder.pkb @@ -1,7 +1,7 @@ create or replace package body ut_suite_builder is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ create or replace package body ut_suite_builder is gc_suite constant t_annotation_name := 'suite'; gc_suitepath constant t_annotation_name := 'suitepath'; + gc_tags constant t_annotation_name := 'tags'; gc_test constant t_annotation_name := ut_utils.gc_test_execute; gc_disabled constant t_annotation_name := 'disabled'; gc_displayname constant t_annotation_name := 'displayname'; @@ -35,6 +36,7 @@ create or replace package body ut_suite_builder is gc_throws constant t_annotation_name := 'throws'; gc_rollback constant t_annotation_name := 'rollback'; gc_context constant t_annotation_name := 'context'; + gc_name constant t_annotation_name := 'name'; gc_endcontext constant t_annotation_name := 'endcontext'; type tt_annotations is table of t_annotation_name; @@ -43,6 +45,7 @@ create or replace package body ut_suite_builder is := tt_annotations( gc_suite, gc_suitepath, + gc_tags, gc_test, gc_disabled, gc_displayname, @@ -55,25 +58,18 @@ create or replace package body ut_suite_builder is gc_throws, gc_rollback, gc_context, + gc_name, 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 +80,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,24 +117,19 @@ create or replace package body ut_suite_builder is a_annotations.by_line.delete(a_start_pos, a_end_pos); end; - ----------------------------------------------- - -- Processing annotations - ----------------------------------------------- - function get_qualified_object_name( - a_suite ut_suite_item, a_procedure_name t_object_name - ) return varchar2 is - l_result varchar2(1000); + procedure add_items_to_list(a_list in out nocopy ut_suite_items, a_items ut_suite_items) is begin - if a_suite is not null then - l_result := upper( a_suite.object_owner || '.' || a_suite.object_name ); - if a_procedure_name is not null then - l_result := l_result || upper( '.' || a_procedure_name ); - end if; - end if; - return l_result; + for i in 1 .. a_items.count loop + a_list.extend(); + a_list(a_list.last) := a_items(i); + end loop; end; + ----------------------------------------------- + -- Processing annotations + ----------------------------------------------- + procedure add_annotation_ignored_warning( a_suite in out nocopy ut_suite_item, a_annotation t_annotation_name, @@ -147,8 +139,9 @@ create or replace package body ut_suite_builder is ) is begin a_suite.put_warning( - replace(a_message,'%%%','"--%'||a_annotation||'"') || ' Annotation ignored.' - || chr( 10 ) || 'at "' || get_qualified_object_name(a_suite, a_procedure_name) || '", line ' || a_line_no + replace(a_message,'%%%','"--%'||a_annotation||'"')|| ' Annotation ignored.', + a_procedure_name, + a_line_no ); end; @@ -165,174 +158,104 @@ create or replace package body ut_suite_builder is procedure add_to_throws_numbers_list( a_suite in out nocopy ut_suite, - a_list in out nocopy ut_integer_list, + a_list in out nocopy ut_varchar2_rows, a_procedure_name t_object_name, a_throws_ann_text tt_annotation_texts ) is l_annotation_pos binary_integer; - function is_valid_qualified_name (a_name varchar2) return boolean is - l_name varchar2(500); - begin - l_name := dbms_assert.qualified_sql_name(a_name); - return true; - exception when others then - return false; - end; - - function check_exception_type(a_exception_name in varchar2) return varchar2 is - l_exception_type varchar2(50); - begin - --check if it is a predefined exception - begin - execute immediate 'begin null; exception when '||a_exception_name||' then null; end;'; - l_exception_type := gc_named_exception; - exception - when others then - if dbms_utility.format_error_stack() like '%PLS-00485%' then - begin - execute immediate 'declare x positiven := -('||a_exception_name||'); begin null; end;'; - l_exception_type := gc_integer_exception; - exception - when others then - --invalid exception number (positive) - --TODO add warning for this value - null; - end; - end if; - end; - return l_exception_type; - end; - - 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; - end; - begin - l_exc_type := check_exception_type(a_exception_var); - - if l_exc_type is not null then - - execute immediate - case l_exc_type - when gc_integer_exception then - 'declare - l_exception number; - begin - :l_exception := '||a_exception_var||'; ' - when gc_named_exception then - 'begin - raise '||a_exception_var||'; - exception - when others then - :l_exception := sqlcode; ' - end || - 'end;' - using out l_exc_no; - - end if; - return remap_no_data_found(l_exc_no); - end; - - function build_exception_numbers_list( - a_suite in out nocopy ut_suite, - a_procedure_name t_object_name, - a_line_no integer, - a_annotation_text in varchar2 - ) return ut_integer_list is - l_throws_list ut_varchar2_list; - l_exception_number integer; - 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*/ - 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 - loop - /** - * Check if its a valid qualified name and if so try to resolve name to an exception number - */ - if is_valid_qualified_name(l_throws_list(i)) then - l_exception_number := get_exception_number(l_throws_list(i)); - elsif regexp_like(l_throws_list(i), c_regexp_for_exception_no) then - l_exception_number := l_throws_list(i); - end if; - - if l_exception_number is null then - a_suite.put_warning( - 'Invalid parameter value "'||l_throws_list(i)||'" for "--%throws" annotation. Parameter ignored.' - || chr( 10 ) || 'at "' || get_qualified_object_name(a_suite, a_procedure_name) || '", line ' || a_line_no - ); - else - l_exception_number_list.extend; - l_exception_number_list(l_exception_number_list.last) := l_exception_number; - end if; - l_exception_number := null; - end loop; - - return l_exception_number_list; - end; - begin - a_list := ut_integer_list(); l_annotation_pos := a_throws_ann_text.first; while l_annotation_pos is not null loop if a_throws_ann_text(l_annotation_pos) is null then a_suite.put_warning( - '"--%throws" annotation requires a parameter. Annotation ignored.' - || chr( 10 ) || 'at "' || get_qualified_object_name(a_suite, a_procedure_name) || '", line ' || l_annotation_pos + '"--%throws" annotation requires a parameter. Annotation ignored.', + a_procedure_name, + l_annotation_pos ); else - a_list := - a_list multiset union - build_exception_numbers_list( - a_suite, - a_procedure_name, - l_annotation_pos, - a_throws_ann_text(l_annotation_pos) - ); + ut_utils.append_to_list( + a_list, + ut_utils.convert_collection( ut_utils.trim_list_elements ( ut_utils.string_to_table( a_throws_ann_text(l_annotation_pos), ',' ) ) ) + ); end if; l_annotation_pos := a_throws_ann_text.next(l_annotation_pos); end loop; end; + procedure add_tags_to_suite_item( + a_suite in out nocopy ut_suite, + a_tags_ann_text tt_annotation_texts, + a_list in out nocopy ut_varchar2_rows, + a_procedure_name t_object_name := null + ) is + l_annotation_pos binary_integer; + l_tags_list ut_varchar2_list := ut_varchar2_list(); + l_tag_items ut_varchar2_list; + begin + l_annotation_pos := a_tags_ann_text.first; + while l_annotation_pos is not null loop + if a_tags_ann_text(l_annotation_pos) is null then + a_suite.put_warning( + '"--%tags" annotation requires a tag value populated. Annotation ignored.', + a_procedure_name, + l_annotation_pos + ); + else + l_tag_items := ut_utils.trim_list_elements(ut_utils.string_to_table(a_tags_ann_text(l_annotation_pos),',')); + if l_tag_items is not empty then + for i in 1 .. l_tag_items.count loop + if regexp_like(l_tag_items(i),'^[^-](\S)+$') then + l_tags_list.extend(); + l_tags_list(l_tags_list.last) := l_tag_items(i); + else + a_suite.put_warning( + 'Invalid value "'||l_tag_items(i)||'" for "--%tags" annotation. See documentation for details on valid tag values. Annotation value ignored.', + a_procedure_name, + l_annotation_pos + ); + end if; + end loop; + end if; + end if; + l_annotation_pos := a_tags_ann_text.next(l_annotation_pos); + end loop; + --remove empty strings from table list e.g. tag1,,tag2 and convert to rows + a_list := ut_utils.convert_collection( ut_utils.filter_list(set(l_tags_list),ut_utils.gc_word_no_space) ); + 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, a_package_name t_object_name, a_annotation_texts tt_annotation_texts, - a_event_name ut_utils.t_event_name + a_event_name ut_event_manager.t_event_name ) return tt_executables is l_executables ut_executables; l_result tt_executables; @@ -382,18 +305,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 +325,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 +347,41 @@ 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 +391,64 @@ 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_tags) then + add_tags_to_suite_item(a_suite, l_proc_annotations( gc_tags), l_test.tags, a_procedure_name); + end if; + + 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)); + + if l_proc_annotations.exists(gc_disabled) then + l_annotation_texts := l_proc_annotations( gc_disabled); + --take the last definition if more than one was provided + l_test.disabled_reason := l_annotation_texts(l_annotation_texts.first); + end if; + + a_suite_items.extend; + a_suite_items( a_suite_items.last ) := l_test; - a_tests(a_proc_annotations(gc_test).first) := 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 +456,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 +465,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 +515,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_tests_to_items( 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 @@ -627,136 +564,250 @@ create or replace package body ut_suite_builder is l_after_each_list := add_executables( a_suite.object_owner, a_suite.object_name, a_annotations.by_name(gc_aftereach), gc_aftereach ); end if; + if a_annotations.by_name.exists(gc_tags) then + add_tags_to_suite_item(a_suite, a_annotations.by_name(gc_tags),a_suite.tags); + end if; + a_suite.disabled_flag := ut_utils.boolean_to_int(a_annotations.by_name.exists(gc_disabled)); - + if a_annotations.by_name.exists(gc_disabled) then + a_suite.disabled_reason := a_annotations.by_name(gc_disabled)(a_annotations.by_name(gc_disabled).first); + end if; + --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_next_annotation_of_type( + a_start_position t_annotation_position, + a_annotation_type varchar2, + a_package_annotations in tt_annotations_by_name + ) return t_annotation_position is + l_result t_annotation_position; + begin + if a_package_annotations.exists(a_annotation_type) then + l_result := a_package_annotations(a_annotation_type).first; + while l_result <= a_start_position loop + l_result := a_package_annotations(a_annotation_type).next(l_result); + end loop; + end if; + return l_result; + end; - procedure add_suite_contexts( - a_suite in out nocopy ut_suite, - a_annotations in out nocopy t_annotations_info + function get_endcontext_position( + a_context_ann_pos t_annotation_position, + a_package_annotations in tt_annotations_by_line + ) return t_annotation_position is + l_result t_annotation_position; + l_open_count integer := 1; + l_idx t_annotation_position := a_package_annotations.next(a_context_ann_pos); + begin + while l_open_count > 0 and l_idx is not null loop + if ( a_package_annotations(l_idx).name = gc_context ) then + l_open_count := l_open_count+1; + elsif ( a_package_annotations(l_idx).name = gc_endcontext ) then + l_open_count := l_open_count-1; + l_result := l_idx; + end if; + l_idx := a_package_annotations.next(l_idx); + end loop; + if ( l_open_count > 0 ) then + l_result := null; + end if; + return l_result; + end; + + function has_nested_context( + a_context_ann_pos t_annotation_position, + a_package_annotations in tt_annotations_by_name + ) return boolean is + l_next_endcontext_pos t_annotation_position := 0; + l_next_context_pos t_annotation_position := 0; + begin + if ( a_package_annotations.exists(gc_endcontext) and a_package_annotations.exists(gc_context)) then + l_next_endcontext_pos := get_next_annotation_of_type(a_context_ann_pos, gc_endcontext, a_package_annotations); + l_next_context_pos := a_package_annotations(gc_context).next(a_context_ann_pos); + end if; + return ( l_next_context_pos < l_next_endcontext_pos ); + 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; + 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_context_items( + a_parent in out nocopy ut_suite, + a_annotations in out nocopy t_annotations_info, + a_suite_items out nocopy ut_suite_items, + a_parent_context_pos in integer := 0, + a_parent_end_context_pos in integer default null ) is - l_context_pos t_annotation_position; - l_end_context_pos t_annotation_position; - l_context_name t_object_name; - 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; + l_context_pos t_annotation_position; + l_next_context_pos t_annotation_position; + l_end_context_pos t_annotation_position; + l_ctx_annotations t_annotations_info; + l_context ut_suite_context; + l_context_no binary_integer := 1; + l_context_items ut_suite_items; + type tt_context_names is table of boolean index by t_object_name; + l_used_context_names tt_context_names; + l_context_name t_object_name; + l_default_context_name t_object_name; + function get_context_name( + a_parent in out nocopy ut_suite, + a_start_position binary_integer + ) return varchar2 is + l_result t_annotation_name; + l_found boolean; + l_end_position binary_integer; + l_annotation_pos binary_integer; + l_context_names tt_annotation_texts; 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); + if a_annotations.by_name.exists(gc_name) then + l_context_names := a_annotations.by_name( gc_name ); + -- Maximum end-position to look for %name annotation is either the next %context or the next %endcontext annotation + l_end_position := + least( + coalesce( get_next_annotation_of_type(a_start_position, gc_endcontext, a_annotations.by_name), a_annotations.by_line.last ), + coalesce( get_next_annotation_of_type(a_start_position, gc_context, a_annotations.by_name), a_annotations.by_line.last ) + ); + l_annotation_pos := l_context_names.first; + + while l_annotation_pos is not null loop + if l_annotation_pos > a_start_position and l_annotation_pos < l_end_position then + if l_found then + add_annotation_ignored_warning(a_parent, gc_name,'Duplicate annotation %%%.', l_annotation_pos); + else + l_result := l_context_names(l_annotation_pos); + end if; + l_found := true; + end if; + l_annotation_pos := l_context_names.next(l_annotation_pos); 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; - begin + a_suite_items := ut_suite_items(); if not a_annotations.by_name.exists(gc_context) then return; end if; - l_context_pos := a_annotations.by_name( gc_context).first; + l_context_pos := a_annotations.by_name( gc_context).next(a_parent_context_pos); 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; + l_default_context_name := 'nested_context_#'||l_context_no; + l_context_name := null; + l_end_context_pos := get_endcontext_position(l_context_pos, a_annotations.by_line ); + l_next_context_pos := a_annotations.by_name(gc_context).next(l_context_pos); + l_context_name := get_context_name(a_parent, l_context_pos); + if not regexp_like( l_context_name, '^(\w|[$#])+$' ) or l_context_name is null then + if not regexp_like( l_context_name, '^(\w|[$#])+$' ) then + a_parent.put_warning( + 'Invalid value "'||l_context_name||'" for context name.' || + ' Context name ignored and fallback to auto-name "'||l_default_context_name||'" ', + null, + l_context_pos + ); + end if; + l_context_name := l_default_context_name; + end if; + if l_used_context_names.exists(l_context_name) then + add_annotation_ignored_warning( + a_parent, gc_name, + 'Context name "'||l_context_name||'" already used in this scope. Name must be unique.' || + ' Using fallback name '||l_default_context_name||'.', l_context_pos ); + l_context_name := l_default_context_name; end if; + l_used_context_names(l_context_name) := true; - --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); + l_context := ut_suite_context(a_parent.object_owner, a_parent.object_name, l_context_name, l_context_pos ); + l_context.path := a_parent.path||'.'||l_context_name; + l_context.description := coalesce( a_annotations.by_line( l_context_pos ).text, l_context_name ); + l_context.parse_time := a_annotations.parse_time; - l_context_name := coalesce( - l_ctx_annotations.by_line( l_context_pos ).text - , gc_context||'_'||l_context_no - ); + --if nested context found + if has_nested_context(l_context_pos, a_annotations.by_name) then + get_context_items( l_context, a_annotations, l_context_items, l_context_pos, l_end_context_pos ); + else + l_context_items := ut_suite_items(); + end if; - l_context := ut_suite_context(a_suite.object_owner, a_suite.object_name, l_context_name ); + if l_end_context_pos is null then + a_parent.put_warning( + 'Missing "--%endcontext" annotation for a "--%context" annotation. The end of package is considered end of context.', + null, + l_context_pos + ); + l_end_context_pos := a_annotations.by_line.last; + end if; - l_context.path := a_suite.path||'.'||l_context_name; - l_context.description := l_ctx_annotations.by_line( l_context_pos ).text; + --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); warning_on_duplicate_annot( l_context, l_ctx_annotations.by_name, gc_context ); - populate_suite_contents( l_context, l_ctx_annotations ); - - a_suite.add_item(l_context); - + add_tests_to_items( 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; -- remove annotations within context after processing them delete_annotations_range(a_annotations, l_context_pos, l_end_context_pos); exit when not a_annotations.by_name.exists( gc_context); l_context_pos := a_annotations.by_name( gc_context).next( l_context_pos); + -- don't go on when the next context is outside the parent's context boundaries + if (a_parent_end_context_pos <= l_context_pos ) then + l_context_pos := null; + end if; l_context_no := l_context_no + 1; end loop; end; - procedure warning_on_incomplete_context( + procedure warning_on_extra_endcontext( a_suite in out nocopy ut_suite, a_package_ann_index tt_annotations_by_name ) is l_annotation_pos t_annotation_position; begin - if a_package_ann_index.exists(gc_context) then - l_annotation_pos := a_package_ann_index(gc_context).first; - while l_annotation_pos is not null loop - add_annotation_ignored_warning( - a_suite, gc_context, 'Invalid annotation %%%. Cannot find following "--%endcontext".', - l_annotation_pos - ); - l_annotation_pos := a_package_ann_index(gc_context).next(l_annotation_pos); - end loop; - end if; if a_package_ann_index.exists(gc_endcontext) then l_annotation_pos := a_package_ann_index(gc_endcontext).first; while l_annotation_pos is not null loop add_annotation_ignored_warning( - a_suite, gc_endcontext, 'Invalid annotation %%%. Cannot find preceding "--%context".', + a_suite, gc_endcontext, 'Extra %%% annotation found. Cannot find corresponding "--%context".', l_annotation_pos ); l_annotation_pos := a_package_ann_index(gc_endcontext).next(l_annotation_pos); @@ -784,140 +835,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 - if l_annotations.by_name.exists( gc_suite) then + 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; - --create an incomplete suite - l_suite := ut_suite(l_annotations.owner, l_annotations.name); - l_annotation_pos := l_annotations.by_name( gc_suite).first; + 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 + l_annotations := convert_package_annotations( a_annotated_object ); + + 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_context_items( l_suite, l_annotations, a_suite_items ); + --create suite tests and add + add_tests_to_items( 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 ); + warning_on_extra_endcontext( l_suite, l_annotations.by_name ); + 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..352601a6d 100644 --- a/source/core/ut_suite_builder.pks +++ b/source/core/ut_suite_builder.pks @@ -1,7 +1,7 @@ create or replace package ut_suite_builder authid current_user is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -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..182caabd0 --- /dev/null +++ b/source/core/ut_suite_cache.sql @@ -0,0 +1,38 @@ +create table ut_suite_cache + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + */ + of ut_suite_cache_row + 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_throws + nested table tags store as ut_suite_cache_tags return as locator +/ + +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 +/ diff --git a/source/core/ut_suite_cache_manager.pkb b/source/core/ut_suite_cache_manager.pkb new file mode 100644 index 000000000..6d621c339 --- /dev/null +++ b/source/core/ut_suite_cache_manager.pkb @@ -0,0 +1,502 @@ +create or replace package body ut_suite_cache_manager is + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + */ + + /* + * Private code + */ + cursor c_get_bulk_cache_suite(cp_suite_items in ut_suite_cache_rows) is + with + suite_items as ( + select /*+ cardinality(c 500) */ value(c) as obj + from table(cp_suite_items) c), + suitepaths as ( + select distinct substr(c.obj.path,1,instr(c.obj.path,'.',-1)-1) as suitepath, + c.obj.path as path, + c.obj.object_owner as object_owner + from suite_items c + where c.obj.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 ut_executables) as x, + cast(null as ut_varchar2_rows) as y, + cast(null as ut_executable_test) as z + from suitepath_part p + where p.path + not in (select s.path from suitepaths s) + ), + logical_suites as ( + select ut_suite_cache_row( + null, + s.self_type, s.path, s.object_owner, s.object_name, + s.object_name, null, null, null, null, 0,null, + ut_varchar2_rows(), + s.x, s.x, s.x, s.x, s.x, s.x, + s.y, null, s.z + ) as obj + from logical_suite_data s + ) + select /*+ no_parallel */ obj from suite_items + union all + select /*+ no_parallel */ obj from logical_suites; + + function get_missing_cache_objects(a_object_owner varchar2) return ut_varchar2_rows is + l_result ut_varchar2_rows; + l_data ut_annotation_objs_cache_info; + begin + l_data := ut_annotation_cache_manager.get_cached_objects_list(a_object_owner, 'PACKAGE'); + + select /*+ no_parallel */ i.object_name + bulk collect into l_result + from ut_suite_cache_package i + where not exists ( + select 1 from table(l_data) o + where o.object_owner = i.object_owner + and o.object_name = i.object_name + and o.object_type = 'PACKAGE' + ) + and i.object_owner = a_object_owner; + return l_result; + end; + + function group_paths_by_schema(a_paths ut_varchar2_list) return ut_path_items is + c_package_path_regex constant varchar2(100) := '^([[:alnum:]$#_]+)(\.([[:alnum:]$#_\*]+))?(\.([[:alnum:]$#_\*]+))?$'; + l_results ut_path_items := ut_path_items(); + l_path_item ut_path_item; + i pls_integer; + begin + i := a_paths.first; + while (i is not null) loop + l_results.extend; + if a_paths(i) like '%:%' then + l_path_item := ut_path_item(schema_name => upper(regexp_substr(a_paths(i),'^[^.:]+')), + suite_path => ltrim(regexp_substr(a_paths(i),'[.:].*$'),':')); + l_results(l_results.last) := l_path_item; + else + l_path_item := ut_path_item(schema_name => regexp_substr(a_paths(i), c_package_path_regex, subexpression => 1), + object_name => regexp_substr(a_paths(i), c_package_path_regex, subexpression => 3), + procedure_name => regexp_substr(a_paths(i), c_package_path_regex, subexpression => 5)); + l_results(l_results.last) := l_path_item; + end if; + i := a_paths.next(i); + end loop; + + return l_results; + end; + + /* + First SQL queries for objects where procedure is null or its only wildcard. + We split that due to fact that we can use func min to combine rows. + + Second union is responsible expanding paths where the procedure filter is given + We cannot select min here as filter can cover only half of tests within + package. Even if the filter doesnt return anything we still capture a proc filter + name for error reporting later on. + + Third SQL cover scenario where a suitapath only is populated and wildcard is given + + Fourth SQL cover scenario where suitepath is populated with no filters + */ + function expand_paths(a_schema_paths ut_path_items) return ut_path_items is + l_schema_paths ut_path_items:= ut_path_items(); + begin + with + schema_paths as ( + select * from table(a_schema_paths) + ), + paths_for_object as ( + select /*+ no_parallel */ min(path) as suite_path,sp.schema_name as schema_name,nvl(c.object_name,sp.object_name) as object_name, + null as procedure_name + from schema_paths sp left outer join ut_suite_cache c + on ( c.object_owner = upper(sp.schema_name) + and c.object_name like replace(upper(sp.object_name),'*','%')) + where sp.suite_path is null and sp.object_name is not null + and ( sp.procedure_name is null or sp.procedure_name = '*') + group by sp.schema_name,nvl(c.object_name,sp.object_name) + ), + paths_for_procedures as ( + select /*+ no_parallel */ path as suite_path,sp.schema_name as schema_name,nvl(c.object_name,sp.object_name) as object_name, + nvl(c.name,sp.procedure_name) as procedure_name + from schema_paths sp left outer join ut_suite_cache c + on ( c.object_owner = upper(sp.schema_name) + and c.object_name like replace(upper(sp.object_name),'*','%') + and c.name like nvl(replace(upper(sp.procedure_name),'*','%'), c.name)) + where sp.suite_path is null and sp.object_name is not null + and (sp.procedure_name is not null and sp.procedure_name != '*') + ), + paths_for_suite_path_with_ast as ( + select /*+ no_parallel */ nvl(c.path,sp.suite_path) as suite_path,sp.schema_name,sp.object_name,sp.procedure_name as procedure_name + from schema_paths sp left outer join ut_suite_cache c on + ( c.object_owner = upper(sp.schema_name) + --and c.path like replace(sp.suite_path,'*','%')) + and regexp_like(c.path,'^'||replace(sp.suite_path,'*','[[:alnum:]$#_]*'))) + where sp.suite_path is not null and instr(sp.suite_path,'*') > 0 + ), + straigth_suite_paths as ( + select /*+ no_parallel */ sp.suite_path as suite_path,sp.schema_name,sp.object_name,sp.procedure_name as procedure_name + from schema_paths sp + where + (sp.suite_path is not null and instr(sp.suite_path,'*') = 0) + or + (sp.suite_path is null and sp.object_name is null) + ), + all_suitepaths_together as ( + select * from paths_for_object + union all + select * from paths_for_procedures + union all + select * from paths_for_suite_path_with_ast + union all + select * from straigth_suite_paths + ) + select ut_path_item(schema_name,object_name,procedure_name,suite_path) + bulk collect into l_schema_paths + from + (select schema_name,object_name,procedure_name,suite_path, + row_number() over ( partition by schema_name,object_name,procedure_name,suite_path order by 1) as r_num + from all_suitepaths_together) + where r_num = 1 ; + return l_schema_paths; + end; + + /* + Get a suite items rows that matching our criteria like + path,object_name etc. + We need to consider also an wildcard character on our procedures and object + names. + Were the path is populated we need to make sure we dont return duplicates + as the wildcard can produce multiple results from same path and + parents and child for each can be same resulting in duplicates + */ + function get_suite_items ( + a_schema_paths ut_path_items + ) return ut_suite_cache_rows is + l_suite_items ut_suite_cache_rows := ut_suite_cache_rows(); + begin + select obj bulk collect into l_suite_items + from ( + select /*+ cardinality(c 500) */ value(c) as obj,row_number() over ( partition by path,object_owner order by path,object_owner asc) as r_num + from ut_suite_cache c, + table(a_schema_paths) sp + where c.object_owner = upper(sp.schema_name) + and ((sp.suite_path is not null and sp.suite_path||'.' like c.path||'.%' /*all parents and self*/ + or + ( + c.path||'.' like sp.suite_path||'.%' /*all children and self*/ + and c.object_name like nvl(upper(sp.object_name),c.object_name) + and c.name like nvl(upper(sp.procedure_name),c.name) + )) + or + ( sp.suite_path is null + and c.object_name = nvl(upper(sp.object_name),c.object_name) + and c.name = nvl(upper(sp.procedure_name),c.name)))) where r_num =1; + return l_suite_items; + end; + + /* + We will sort a suites in hierarchical structure. + Sorting from bottom to top so when we consolidate + we will go in proper order. + For random seed we will add an extra sort that can be null. + The object owner is irrelevant on joing via path as we already + resolved a list of test we want to use so as long they share a suitepath + they are correct. + */ + procedure sort_and_randomize_tests( + a_suite_rows in out ut_suite_cache_rows, + a_random_seed positive := null) + is + l_suite_rows ut_suite_cache_rows; + begin + with + extract_parent_child as ( + select s.path, substr(s.path,1,instr(s.path,'.',-1,1)-1) as parent_path,s.object_owner, + case when a_random_seed is null then s.line_no end line_no, + case when a_random_seed is not null then ut_utils.hash_suite_path(s.path, a_random_seed) end random_seed + from table(a_suite_rows) s), + t1(path,parent_path,object_owner,line_no,random_seed) as ( + --Anchor member + select s.path, parent_path,s.object_owner,s.line_no,random_seed + from extract_parent_child s + where parent_path is null + union all + --Recursive member + select t2.path, t2.parent_path,t2.object_owner,t2.line_no,t2.random_seed + from t1,extract_parent_child t2 + where t2.parent_path = t1.path + and t2.object_owner = t1.object_owner) + search depth first by line_no desc,random_seed desc nulls last set order1 + select value(i) as obj + bulk collect into l_suite_rows + from t1 c + join table(a_suite_rows) i on i.object_owner = c.object_owner and i.path = c.path + order by order1 desc; + + a_suite_rows := l_suite_rows; + end; + + /* + * Public code + */ + + function get_schema_paths(a_paths in ut_varchar2_list) return ut_path_items is + begin + return expand_paths(group_paths_by_schema(a_paths)); + end; + + function get_cached_suite_rows( + a_suites_filtered ut_suite_cache_rows + ) return ut_suite_cache_rows is + l_results ut_suite_cache_rows := ut_suite_cache_rows(); + begin + + open c_get_bulk_cache_suite(a_suites_filtered); + fetch c_get_bulk_cache_suite bulk collect into l_results; + close c_get_bulk_cache_suite; + + return l_results; + end; + + function get_schema_parse_time(a_schema_name varchar2) return timestamp result_cache is + l_cache_parse_time timestamp; + begin + select /*+ no_parallel */ min(t.parse_time) + into l_cache_parse_time + from ut_suite_cache_schema t + where object_owner = upper(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 /*+ no_parallel */ 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 /*+ no_parallel */ ut_suite_cache_schema t + set t.parse_time = greatest(t.parse_time,a_parse_time) + where object_owner = l_object_owner; + + if sql%rowcount = 0 then + insert /*+ no_parallel */ into ut_suite_cache_schema + (object_owner, parse_time) + values (l_object_owner, a_parse_time); + end if; + + update /*+ no_parallel */ 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 /*+ no_parallel */ 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 /*+ no_parallel */ into ut_suite_cache t + ( + id, self_type, path, object_owner, object_name, name, + line_no, parse_time, description, + rollback_type, disabled_flag,disabled_reason, warnings, + before_all_list, after_all_list, + before_each_list, after_each_list, + before_test_list, after_test_list, + expected_error_codes, tags, + 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 /*+ no_parallel */ 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.disabled_reason as disabled_reason, 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, s.i.tags tags, + null item + from suites s; + + insert /*+ no_parallel */ into ut_suite_cache t + ( + id, self_type, path, object_owner, object_name, name, + line_no, parse_time, description, + rollback_type, disabled_flag,disabled_reason, warnings, + before_all_list, after_all_list, + before_each_list, after_each_list, + before_test_list, after_test_list, + expected_error_codes, tags, + 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 /*+ no_parallel */ 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.disabled_reason as disabled_reason, 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.tags as test_tags, + s.t.item as item + from tests s; + + end if; + end if; + commit; + end; + + procedure remove_missing_objs_from_cache(a_schema_name varchar2) is + l_objects ut_varchar2_rows; + pragma autonomous_transaction; + begin + l_objects := get_missing_cache_objects(a_schema_name); + + if l_objects is not empty then + delete /*+ no_parallel */ from ut_suite_cache i + where i.object_owner = a_schema_name + and i.object_name in ( select /*+ no_parallel */ column_value from table (l_objects) ); + + delete /*+ no_parallel */ from ut_suite_cache_package i + where i.object_owner = a_schema_name + and i.object_name in ( select /*+ no_parallel */ column_value from table (l_objects) ); + end if; + + commit; + end; + + function get_cached_suite_info( + a_schema_paths ut_path_items + ) return ut_suite_cache_rows is + begin + return get_cached_suite_rows(get_suite_items(a_schema_paths)); + end; + + function get_suite_items_info( + a_suite_cache_items ut_suite_cache_rows + ) return ut_suite_items_info is + l_results ut_suite_items_info; + begin + select /*+ no_parallel */ ut_suite_item_info( + c.object_owner, c.object_name, c.name, + c.description, c.self_type, c.line_no, + c.path, c.disabled_flag, c.disabled_reason, c.tags + ) + bulk collect into l_results + from table(a_suite_cache_items) c; + return l_results; + end; + + function get_cached_packages( + a_schema_names ut_varchar2_rows + ) return ut_object_names is + l_results ut_object_names; + begin + select /*+ no_parallel */ ut_object_name( c.object_owner, c.object_name ) + bulk collect into l_results + from ut_suite_cache_package c + join table ( a_schema_names ) s + on c.object_owner = upper(s.column_value); + return l_results; + end; + + function suite_item_exists( + a_owner_name varchar2, + a_package_name varchar2, + a_procedure_name varchar2 + ) return boolean is + l_count integer; + begin + if a_procedure_name is not null then + select /*+ no_parallel */ count( 1 ) into l_count from dual + where exists( + select 1 + from ut_suite_cache c + where c.object_owner = a_owner_name + and c.object_name = a_package_name + and c.name = a_procedure_name + ); + elsif a_package_name is not null then + select /*+ no_parallel */ count( 1 ) into l_count from dual + where exists( + select 1 + from ut_suite_cache c + where c.object_owner = a_owner_name + and c.object_name = a_package_name + ); + else + select /*+ no_parallel */ count( 1 ) into l_count from dual + where exists( + select 1 + from ut_suite_cache c + where c.object_owner = a_owner_name + ); + end if; + + return l_count > 0; + end; + +end; +/ diff --git a/source/core/ut_suite_cache_manager.pks b/source/core/ut_suite_cache_manager.pks new file mode 100644 index 000000000..81b1e0136 --- /dev/null +++ b/source/core/ut_suite_cache_manager.pks @@ -0,0 +1,101 @@ +create or replace package ut_suite_cache_manager authid definer is + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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 + */ + + /* + * Saves suite items for individual package in suite cache + */ + procedure save_object_cache( + a_object_owner varchar2, + a_object_name varchar2, + a_parse_time timestamp, + a_suite_items ut_suite_items + ); + + /* + * Returns time when schema was last saved in cache + */ + function get_schema_parse_time(a_schema_name varchar2) return timestamp result_cache; + + /* + * Removes packages that are no longer annotated from cache + */ + procedure remove_missing_objs_from_cache(a_schema_name varchar2); + + /* + * We will sort a suites in hierarchical structure. + * Sorting from bottom to top so when we consolidate + * we will go in proper order. + */ + procedure sort_and_randomize_tests( + a_suite_rows in out ut_suite_cache_rows, + a_random_seed positive := null); + + /* + * Retrieves suite items data from cache. + * Returned data is not filtered by user access rights. + * Not to be used publicly. Used internally for building suites at runtime. + */ + function get_cached_suite_rows( + a_suites_filtered ut_suite_cache_rows + ) return ut_suite_cache_rows; + + function get_schema_paths(a_paths in ut_varchar2_list) return ut_path_items; + + /* + * Retrieves suite item info rows from cache. + * Returned data is not filtered by user access rights. + * Not to be used publicly. Used internally for building suites info. + */ + function get_cached_suite_info( + a_schema_paths ut_path_items + ) return ut_suite_cache_rows; + + function get_suite_items_info( + a_suite_cache_items ut_suite_cache_rows + ) return ut_suite_items_info; + + function get_suite_items ( + a_schema_paths ut_path_items + ) return ut_suite_cache_rows; + + /* + * Retrieves list of cached suite packages. + * Returned data is not filtered by user access rights. + * Not to be used publicly. Used internally. + */ + function get_cached_packages( + a_schema_names ut_varchar2_rows + ) return ut_object_names; + + /* + * Returns true if given suite item exists in cache. + * Returned data is not filtered by user access rights. + * Not to be used publicly. Used internally. + */ + function suite_item_exists( + a_owner_name varchar2, + a_package_name varchar2, + a_procedure_name varchar2 + ) return boolean; + +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..7a146ff83 --- /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 - 2021 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..636816e65 --- /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 - 2021 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..e1e560286 --- /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 - 2021 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..c418de638 100644 --- a/source/core/ut_suite_manager.pkb +++ b/source/core/ut_suite_manager.pkb @@ -1,7 +1,7 @@ create or replace package body ut_suite_manager is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -16,119 +16,13 @@ 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 tt_schema_suites_list is table of t_schema_cache index by varchar2(128 char); - - g_schema_suites tt_schema_suites_list; - - - type t_schema_paths is table of ut_varchar2_list index by varchar2(4000 char); - + gc_suitpath_error_message constant varchar2(100) := 'Suitepath exceeds 1000 CHAR on: '; + cursor c_cached_suites_cursor is select * from table(ut_suite_cache_rows()); + type tt_cached_suites is table of c_cached_suites_cursor%rowtype; + type t_cached_suites_cursor is ref cursor return c_cached_suites_cursor%rowtype; + 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 @@ -137,14 +31,15 @@ create or replace package body ut_suite_manager is else for i in 1 .. a_paths.count loop l_path := a_paths(i); - if l_path is null or not (regexp_like(l_path, '^[A-Za-z0-9$#_]+(\.[A-Za-z0-9$#_]+){0,2}$') or regexp_like(l_path, '^([A-Za-z0-9$#_]+)?:[A-Za-z0-9$#_]+(\.[A-Za-z0-9$#_]+)*$')) then + if l_path is null or not ( + regexp_like(l_path, '^[[:alnum:]$#_\*]+(\.[[:alnum:]$#_\*]+){0,2}$') or regexp_like(l_path, '^([[:alnum:]$#_]+)?:[[:alnum:]$#_\*]+(\.[[:alnum:]$#_\*]+)*$')) then raise_application_error(ut_utils.gc_invalid_path_format, 'Invalid path format: ' || nvl(l_path, 'NULL')); end if; end loop; 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,15 +55,15 @@ 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); for i in 1 .. a_paths.count loop --if path is suite-path - if regexp_like(a_paths(i), '^([A-Za-z0-9$#_]+)?:') then + if regexp_like(a_paths(i), '^([[:alnum:]$#_]+)?:') then --get schema name / path - l_schema := regexp_substr(a_paths(i), '^([A-Za-z0-9$#_]+)?:',subexpression => 1); + l_schema := regexp_substr(a_paths(i), '^([[:alnum:]$#_]+)?:',subexpression => 1); -- transform ":path1[.path2]" to "schema:path1[.path2]" if l_schema is not null then l_schema := sys.dbms_assert.schema_name(upper(l_schema)); @@ -180,12 +75,14 @@ create or replace package body ut_suite_manager is -- get schema name / object.[procedure] name -- When path is one of: schema or schema.package[.object] or package[.object] -- transform it back to schema[.package[.object]] + -- Object name or procedure is allowed to have filter char + -- However this is not allowed on schema begin - l_object := regexp_substr(a_paths(i), '^[A-Za-z0-9$#_]+'); + l_object := regexp_substr(a_paths(i), '^[[:alnum:]$#_\*]+'); l_schema := sys.dbms_assert.schema_name(upper(l_object)); exception when sys.dbms_assert.invalid_schema_name then - if ut_metadata.package_exists_in_cur_schema(upper(l_object)) then + if l_object like '%*%' or ut_metadata.package_exists_in_cur_schema(upper(l_object)) then a_paths(i) := c_current_schema || '.' || a_paths(i); l_schema := c_current_schema; else @@ -196,6 +93,7 @@ create or replace package body ut_suite_manager is l_schema_names.extend; l_schema_names(l_schema_names.last) := l_schema; end loop; + return l_schema_names; end; @@ -205,175 +103,527 @@ 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 sort_by_seq_no( + a_list ut_executables + ) return ut_executables is + l_results ut_executables := ut_executables(); begin - l_paths := a_paths; - return resolve_schema_names(l_paths); + 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; + end if; + 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); - 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; + 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; - 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; + 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, disabled_reason => a_rows(a_idx).disabled_reason, + 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), tags => a_rows(a_idx).tags + ) + 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, disabled_reason => a_rows(a_idx).disabled_reason, + 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), tags => a_rows(a_idx).tags + ) + 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, disabled_reason => a_rows(a_idx).disabled_reason, + 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), tags => a_rows(a_idx).tags + ) + 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, disabled_reason => a_rows(a_idx).disabled_reason, + 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), tags => a_rows(a_idx).tags + ) + 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, disabled_reason => a_rows(a_idx).disabled_reason, + 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), tags => null + ) + 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, disabled_reason => a_rows(a_idx).disabled_reason, + 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(), tags => null + ) + 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, disabled_reason => a_rows(a_idx).disabled_reason, + 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, + tags => a_rows(a_idx).tags + ); + 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_filtered_cursor( + a_unfiltered_rows in ut_suite_cache_rows, + a_skip_all_objects boolean := false + ) + return ut_suite_cache_rows is + l_result ut_suite_cache_rows := ut_suite_cache_rows(); begin - if a_suite is of (ut_logical_suite) then - l_suite := treat(a_suite as ut_logical_suite); + if ut_metadata.user_has_execute_any_proc() or a_skip_all_objects then + l_result := a_unfiltered_rows; + else + select obj bulk collect into l_result + from ( + select /*+ no_parallel */ value(c) as obj from table(a_unfiltered_rows) c + where sys_context( 'userenv', 'current_user' ) = upper(c.object_owner) + union all + select /*+ no_parallel */ value(c) as obj from table(a_unfiltered_rows) c + where sys_context( 'userenv', 'current_user' ) != upper(c.object_owner) + and ( exists + ( select 1 + from all_objects a + where a.object_name = c.object_name + and a.owner = c.object_owner + and a.object_type = 'PACKAGE' + ) + or c.self_type = 'UT_LOGICAL_SUITE')); + end if; + return l_result; + end; - 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'); + procedure reconcile_paths_and_suites( + a_schema_paths ut_path_items, + a_filtered_rows ut_suite_cache_rows + ) is + begin + for i in ( select /*+ no_parallel */ sp.schema_name,sp.object_name,sp.procedure_name, + sp.suite_path,sc.path + from table(a_schema_paths) sp left outer join + table(a_filtered_rows) sc on + (( upper(sp.schema_name) = upper(sc.object_owner) and upper(sp.object_name) = upper(sc.object_name) + and nvl(upper(sp.procedure_name),sc.name) = sc.name ) + or (sc.path = sp.suite_path)) + where sc.path is null) + loop + if i.suite_path is not null then + raise_application_error(ut_utils.gc_suite_package_not_found,'No suite packages found for path '||i.schema_name||':'||i.suite_path|| '.'); + elsif i.procedure_name is not null then + raise_application_error(ut_utils.gc_suite_package_not_found,'Suite test '||i.schema_name||'.'||i.object_name|| '.'||i.procedure_name||' does not exist'); + elsif i.object_name is not null then + raise_application_error(ut_utils.gc_suite_package_not_found,'Suite package '||i.schema_name||'.'||i.object_name|| ' does not exist'); end if; + end loop; + end; - l_suite.items := l_items; - a_suite := l_suite; - end if; - end filter_suite_by_path; + function get_cached_suite_data( + a_schema_paths ut_path_items, + a_random_seed positive, + a_tags varchar2 := null, + a_skip_all_objects boolean := false + ) return t_cached_suites_cursor is + l_unfiltered_rows ut_suite_cache_rows; + l_tag_filter_applied ut_suite_cache_rows; + l_filtered_rows ut_suite_cache_rows; + l_result t_cached_suites_cursor; + begin + l_unfiltered_rows := ut_suite_cache_manager.get_suite_items(a_schema_paths); + + l_tag_filter_applied := ut_suite_tag_filter.apply(l_unfiltered_rows,a_tags); + l_filtered_rows := get_filtered_cursor(ut_suite_cache_manager.get_cached_suite_rows(l_tag_filter_applied),a_skip_all_objects); + reconcile_paths_and_suites(a_schema_paths,l_filtered_rows); + + ut_suite_cache_manager.sort_and_randomize_tests(l_filtered_rows,a_random_seed); + + open l_result for + select * from table(l_filtered_rows); + return l_result; + end; + + function can_skip_all_objects_scan( + a_owner_name varchar2 + ) return boolean is + begin + return sys_context( 'userenv', 'current_user' ) = upper(a_owner_name) or ut_metadata.user_has_execute_any_proc(); + end; - 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); + 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; + + l_bad_suitepath_obj ut_varchar2_list := ut_varchar2_list(); + ex_string_too_small exception; + pragma exception_init (ex_string_too_small,-06502); 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); + ut_event_manager.trigger_event('build_and_cache_suites - start'); + loop + fetch a_annotated_objects bulk collect into l_annotated_objects limit 10; + + for i in 1 .. l_annotated_objects.count loop + begin + ut_suite_builder.create_suite_item_list( l_annotated_objects( i ), l_suite_items ); + exception + when ex_string_too_small then + ut_utils.append_to_list(l_bad_suitepath_obj,a_owner_name||'.'||l_annotated_objects( i ).object_name); + end; + 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; + + --Check for any invalid suitepath objects + if l_bad_suitepath_obj.count > 0 then + raise_application_error( + ut_utils.gc_value_too_large, + ut_utils.to_string(gc_suitpath_error_message||ut_utils.table_to_clob(l_bad_suitepath_obj,',')) + ); 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'); + ut_event_manager.trigger_event('build_and_cache_suites - end'); 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 refresh_cache( + a_owner_name varchar2 + ) is + l_annotations_cursor sys_refcursor; + l_suite_cache_time timestamp; + l_owner_name varchar2(128) := upper(a_owner_name); 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, '.'); + ut_event_manager.trigger_event('refresh_cache - start'); + l_suite_cache_time := ut_suite_cache_manager.get_schema_parse_time(l_owner_name); + l_annotations_cursor := ut_annotation_manager.get_annotated_objects( + l_owner_name, 'PACKAGE', l_suite_cache_time + ); + + build_and_cache_suites(l_owner_name, l_annotations_cursor); + + if can_skip_all_objects_scan(l_owner_name) or ut_metadata.is_object_visible( 'dba_objects') then + ut_suite_cache_manager.remove_missing_objs_from_cache( l_owner_name ); end if; - return l_path; + + ut_event_manager.trigger_event('refresh_cache - end'); 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_paths( + a_schema_paths ut_path_items, + a_suites in out nocopy ut_suite_items, + a_random_seed positive, + a_tags varchar2 := null + ) 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; + reconstruct_from_cache( + a_suites, + get_cached_suite_data( + a_schema_paths, + a_random_seed, + a_tags + ) + ); + 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(); + l_schema_paths ut_path_items; + begin + build_and_cache_suites(a_owner_name, a_annotated_objects); + l_schema_paths := ut_path_items(ut_path_item(a_owner_name,a_object_name,a_procedure_name,a_path)); + reconstruct_from_cache( + l_suites, + get_cached_suite_data( + l_schema_paths, + null, + null, + a_skip_all_objects + ) + ); + return l_suites; + end; + + function get_schema_ut_packages(a_schema_names ut_varchar2_rows, a_schema_name_expr varchar2) return ut_object_names is + l_schema_names ut_varchar2_rows := a_schema_names; + begin + if a_schema_name_expr is not null then + select username + bulk collect into l_schema_names + from all_users + where regexp_like(username,a_schema_name_expr,'i'); + end if; + + for i in 1 .. l_schema_names.count loop + refresh_cache(l_schema_names(i)); end loop; - return l_result; + + return ut_suite_cache_manager.get_cached_packages( l_schema_names ); end; - function configure_execution_by_path(a_paths in ut_varchar2_list) return ut_suite_items is + 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 ut_varchar2_list, a_random_seed positive := null) 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 ut_varchar2_list, + a_suites out nocopy ut_suite_items, + a_random_seed positive := null, + a_tags varchar2 := null + ) is l_paths ut_varchar2_list := a_paths; - l_path varchar2(32767); + l_schema_names ut_varchar2_rows; + l_schema_paths ut_path_items; l_schema varchar2(4000); - l_suites_info t_schema_suites_info; - l_index varchar2(4000 char); - l_suite ut_logical_suite; - l_objects_to_run ut_suite_items; - l_schema_paths t_schema_paths; begin + ut_event_manager.trigger_event('configure_execution_by_path - start'); + 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_names := resolve_schema_names(l_paths); - l_schema := l_schema_paths.first; + --refresh cache + l_schema := l_schema_names.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; - end if; - end loop; - l_schema := l_schema_paths.next(l_schema); + refresh_cache(upper(l_schema_names(l_schema))); + l_schema := l_schema_names.next(l_schema); end loop; + l_schema_paths := ut_suite_cache_manager.get_schema_paths(l_paths); + + --We will get a single list of paths rather than loop by loop. + add_suites_for_paths( + l_schema_paths, + a_suites, + a_random_seed, + a_tags + ); + --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; + ut_event_manager.trigger_event('configure_execution_by_path - end'); end configure_execution_by_path; + function get_suites_info( + a_paths ut_varchar2_list + ) return sys_refcursor is + l_result sys_refcursor; + l_all_suite_info ut_suite_items_info; + l_schema_names ut_varchar2_rows; + l_schema_paths ut_path_items; + l_paths ut_varchar2_list := a_paths; + l_schema varchar2(4000); + l_unfiltered_rows ut_suite_cache_rows; + l_filtered_rows ut_suite_cache_rows; + + begin + l_schema_names := resolve_schema_names(l_paths); + --refresh cache + l_schema := l_schema_names.first; + while l_schema is not null loop + refresh_cache(upper(l_schema_names(l_schema))); + l_schema := l_schema_names.next(l_schema); + end loop; + l_schema_paths := ut_suite_cache_manager.get_schema_paths(l_paths); + l_unfiltered_rows := ut_suite_cache_manager.get_cached_suite_info(l_schema_paths); + l_filtered_rows := get_filtered_cursor(l_unfiltered_rows); + l_all_suite_info := ut_suite_cache_manager.get_suite_items_info(l_filtered_rows); + open l_result for + select /*+ no_parallel */ value(c) + from table(l_all_suite_info) c + order by c.object_owner, c.object_name, c.item_line_no; + + return l_result; + end; + + function suite_item_exists( + a_owner_name varchar2, + a_package_name varchar2 := null, + a_procedure_name varchar2 := null + ) return boolean is + l_count integer := 1; + l_item_exists boolean; + l_owner_name varchar2(250) := upper(a_owner_name); + l_package_name varchar2(250) := upper(a_package_name); + l_procedure_name varchar2(250) := upper(a_procedure_name); + begin + + refresh_cache(l_owner_name); + l_item_exists := ut_suite_cache_manager.suite_item_exists( l_owner_name, l_package_name, l_procedure_name ); + if not can_skip_all_objects_scan( l_owner_name ) and l_package_name is not null then + select /*+ no_parallel */ count(1) + into l_count + from dual c + where exists + ( select 1 + from all_objects a + where a.object_name = l_package_name + and a.owner = l_owner_name + and a.object_type = 'PACKAGE' + ); + end if; + + return l_count > 0 and l_item_exists; + end; + end ut_suite_manager; / diff --git a/source/core/ut_suite_manager.pks b/source/core/ut_suite_manager.pks index 3fde7f6b5..07539139a 100644 --- a/source/core/ut_suite_manager.pks +++ b/source/core/ut_suite_manager.pks @@ -1,7 +1,7 @@ create or replace package ut_suite_manager authid current_user is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -24,11 +24,13 @@ create or replace package ut_suite_manager authid current_user is * @private * * Returns a list of Unit Test packages that exist in a given database schema + * IMPORTANT! The returned list is not filtered by user privileges. + * To be used internally only. * * @param a_schema_names list of schemas to return the information for * @return array containing unit test schema and object names */ - function get_schema_ut_packages(a_schema_names ut_varchar2_rows) return ut_object_names; + function get_schema_ut_packages(a_schema_names ut_varchar2_rows, a_schema_name_expr varchar2) return ut_object_names; /** * Builds a hierarchical suites based on given suite-paths @@ -37,7 +39,22 @@ create or replace package ut_suite_manager authid current_user is * @return array containing root suites-ready to be executed * */ - function configure_execution_by_path(a_paths in ut_varchar2_list) return ut_suite_items; + --TODO:Zerknij czy mozna wywalic + function configure_execution_by_path(a_paths ut_varchar2_list, a_random_seed positive := null) 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, + a_random_seed in positive := null, + a_tags in varchar2 := null + ); /** * Cleanup paths by removing leading/trailing whitespace and making paths lowercase @@ -45,5 +62,45 @@ create or replace package ut_suite_manager authid current_user is */ 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_paths list of paths to be resolved and return a suites. + */ + function get_suites_info( + a_paths ut_varchar2_list + ) 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 + ) return boolean; + + end ut_suite_manager; / diff --git a/source/core/ut_suite_tag_filter.pkb b/source/core/ut_suite_tag_filter.pkb new file mode 100644 index 000000000..2d9436301 --- /dev/null +++ b/source/core/ut_suite_tag_filter.pkb @@ -0,0 +1,295 @@ +create or replace package body ut_suite_tag_filter is + /* + utPLSQL - Version 3 + Copyright 2016 - 2023 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. + */ + + /** + * Constants use in postfix and infix transformations + */ + gc_operators constant ut_varchar2_list := ut_varchar2_list('|','&','!'); + gc_unary_operators constant ut_varchar2_list := ut_varchar2_list('!'); -- right side associative operator + gc_binary_operators constant ut_varchar2_list := ut_varchar2_list('|','&'); -- left side associative operator + gc_reserved_tag_words constant ut_varchar2_list := ut_varchar2_list('none','any'); + gc_tags_column_name constant varchar2(250) := 'tags'; + gc_exception_msg constant varchar2(200) := 'Invalid tag expression'; + + type t_precedence_table is table of number index by varchar2(1); + g_precedence t_precedence_table; + + function tokenize_tags_string(a_tags in varchar2) return ut_varchar2_list is + l_tags_tokens ut_varchar2_list := ut_varchar2_list(); + begin + --Tokenize a string into operators and tags + select regexp_substr(a_tags,'([^!()|&]+)|([!()|&])', 1, level) as string_parts + bulk collect into l_tags_tokens + from dual connect by regexp_substr (a_tags, '([^!()|&]+)|([!()|&])', 1, level) is not null; + + return l_tags_tokens; + end; + + /* + To support a legact tag notation + , = OR + - = NOT + we will perform a replace of that characters into + new notation. + | = OR + & = AND + ! = NOT + */ + function replace_legacy_tag_notation(a_tags varchar2 + ) return varchar2 is + l_tags ut_varchar2_list := ut_utils.string_to_table(a_tags,','); + l_tags_include varchar2(4000); + l_tags_exclude varchar2(4000); + l_return_tag varchar2(4000); + begin + if instr(a_tags,',') > 0 or instr(a_tags,'-') > 0 then + + select '('||listagg( t.column_value,'|') + within group( order by column_value)||')' + into l_tags_include + from table(l_tags) t + where t.column_value not like '-%'; + + select '('||listagg( replace(t.column_value,'-','!'),' & ') + within group( order by column_value)||')' + into l_tags_exclude + from table(l_tags) t + where t.column_value like '-%'; + + + l_return_tag:= + case + when l_tags_include <> '()' and l_tags_exclude <> '()' + then l_tags_include || ' & ' || l_tags_exclude + when l_tags_include <> '()' + then l_tags_include + when l_tags_exclude <> '()' + then l_tags_exclude + end; + else + l_return_tag := a_tags; + end if; + return l_return_tag; + end; + + /* + https://stackoverflow.com/questions/29634992/shunting-yard-validate-expression + */ + function shunt_logical_expression(a_tags in ut_varchar2_list) return ut_varchar2_list is + l_operator_stack ut_stack := ut_stack(); + l_rnp_tokens ut_varchar2_list := ut_varchar2_list(); + l_token varchar2(32767); + l_expect_operand boolean := true; + l_expect_operator boolean := false; + l_idx pls_integer; + begin + l_idx := a_tags.first; + --Exuecute modified shunting algorithm + WHILE (l_idx is not null) loop + l_token := a_tags(l_idx); + if (l_token member of gc_operators and l_token member of gc_binary_operators) then + if not(l_expect_operator) then + raise_application_error(ut_utils.gc_invalid_tag_expression, gc_exception_msg); + end if; + while l_operator_stack.top > 0 and (g_precedence(l_operator_stack.peek) > g_precedence(l_token)) loop + l_rnp_tokens.extend; + l_rnp_tokens(l_rnp_tokens.last) := l_operator_stack.pop; + end loop; + l_operator_stack.push(a_tags(l_idx)); + l_expect_operand := true; + l_expect_operator:= false; + elsif (l_token member of gc_operators and l_token member of gc_unary_operators) then + if not(l_expect_operand) then + raise_application_error(ut_utils.gc_invalid_tag_expression, gc_exception_msg); + end if; + l_operator_stack.push(a_tags(l_idx)); + l_expect_operand := true; + l_expect_operator:= false; + elsif l_token = '(' then + if not(l_expect_operand) then + raise_application_error(ut_utils.gc_invalid_tag_expression, gc_exception_msg); + end if; + l_operator_stack.push(a_tags(l_idx)); + l_expect_operand := true; + l_expect_operator:= false; + elsif l_token = ')' then + if not(l_expect_operator) then + raise_application_error(ut_utils.gc_invalid_tag_expression, gc_exception_msg); + end if; + while l_operator_stack.peek <> '(' loop + l_rnp_tokens.extend; + l_rnp_tokens(l_rnp_tokens.last) := l_operator_stack.pop; + end loop; + l_operator_stack.pop; --Pop the open bracket and discard it + l_expect_operand := false; + l_expect_operator:= true; + else + if not(l_expect_operand) then + raise_application_error(ut_utils.gc_invalid_tag_expression, gc_exception_msg); + end if; + l_rnp_tokens.extend; + l_rnp_tokens(l_rnp_tokens.last) :=l_token; + l_expect_operator := true; + l_expect_operand := false; + end if; + + l_idx := a_tags.next(l_idx); + end loop; + + while l_operator_stack.peek is not null loop + if l_operator_stack.peek in ('(',')') then + raise_application_error(ut_utils.gc_invalid_tag_expression, gc_exception_msg); + end if; + l_rnp_tokens.extend; + l_rnp_tokens(l_rnp_tokens.last):=l_operator_stack.pop; + end loop; + + return l_rnp_tokens; + end shunt_logical_expression; + + function conv_postfix_to_infix_sql(a_postfix_exp in ut_varchar2_list,a_tags_column_name in varchar2) + return varchar2 is + l_infix_stack ut_stack := ut_stack(); + l_right_side varchar2(32767); + l_left_side varchar2(32767); + l_infix_exp varchar2(32767); + l_member_token varchar2(20) := ' member of '||a_tags_column_name; + l_idx pls_integer; + begin + l_idx := a_postfix_exp.first; + while ( l_idx is not null) loop + --If the token we got is a none or any keyword + if a_postfix_exp(l_idx) member of gc_reserved_tag_words then + + l_infix_stack.push( + case + when a_postfix_exp(l_idx) = 'none' then '('||a_tags_column_name||' is empty or '||a_tags_column_name||' is null)' + else a_tags_column_name||' is not empty' + end + ); + --If token is operand but also single tag + elsif regexp_count(a_postfix_exp(l_idx),'[!()|&]') = 0 then + l_infix_stack.push(q'[']'||a_postfix_exp(l_idx)||q'[']'||l_member_token); + --If token is unary operator not + elsif a_postfix_exp(l_idx) member of gc_unary_operators then + l_right_side := l_infix_stack.pop; + l_infix_exp := a_postfix_exp(l_idx)||'('||l_right_side||')'; + l_infix_stack.push(l_infix_exp); + --If token is binary operator + elsif a_postfix_exp(l_idx) member of gc_binary_operators then + l_right_side := l_infix_stack.pop; + l_left_side := l_infix_stack.pop; + l_infix_exp := '('||l_left_side||a_postfix_exp(l_idx)||l_right_side||')'; + l_infix_stack.push(l_infix_exp); + end if; + l_idx := a_postfix_exp.next(l_idx); + end loop; + + return l_infix_stack.pop; + end conv_postfix_to_infix_sql; + + function create_where_filter(a_tags varchar2 + ) return varchar2 is + l_tags varchar2(4000); + begin + l_tags := replace(replace_legacy_tag_notation(a_tags),' '); + l_tags := conv_postfix_to_infix_sql(shunt_logical_expression(tokenize_tags_string(l_tags)),gc_tags_column_name); + l_tags := replace(l_tags, '|',' or '); + l_tags := replace(l_tags ,'&',' and '); + l_tags := replace(l_tags ,'!','not'); + return l_tags; + end; + + + /* + Having a base set of suites we will do a further filter down if there are + any tags defined. + */ + function get_tags_suites ( + a_suite_items ut_suite_cache_rows, + a_tags varchar2 + ) return ut_suite_cache_rows is + l_suite_tags ut_suite_cache_rows := ut_suite_cache_rows(); + l_sql varchar2(32000); + l_tags varchar2(4000):= create_where_filter(a_tags); + begin + l_sql := + q'[ +with + suites_mv as ( + select c.id,value(c) as obj,c.path as path,c.self_type,c.object_owner,c.tags as ]'||gc_tags_column_name||q'[ + from table(:suite_items) c + ), + suites_matching_expr as ( + select c.id,c.path as path,c.self_type,c.object_owner,c.tags + from suites_mv c + where c.self_type in ('UT_SUITE','UT_CONTEXT') + and ]'||l_tags||q'[ + ), + tests_matching_expr as ( + select c.id,c.path as path,c.self_type,c.object_owner,c.tags as ]'||gc_tags_column_name||q'[ + from suites_mv c where c.self_type in ('UT_TEST') + and ]'||l_tags||q'[ + ), + tests_with_tags_inh_from_suite as ( + select c.id,c.self_type,c.path,c.tags multiset union distinct t.tags as ]'||gc_tags_column_name||q'[ ,c.object_owner + from suites_mv c join suites_matching_expr t + on (c.path||'.' like t.path || '.%' /*all descendants and self*/ and c.object_owner = t.object_owner) + ), + tests_with_tags_prom_to_suite as ( + select c.id,c.self_type,c.path,c.tags multiset union distinct t.tags as ]'||gc_tags_column_name||q'[ ,c.object_owner + from suites_mv c join tests_matching_expr t + on (t.path||'.' like c.path || '.%' /*all ancestors and self*/ and c.object_owner = t.object_owner) + ) + select obj from suites_mv c, + (select id,row_number() over (partition by id order by id) r_num from + (select id + from tests_with_tags_prom_to_suite tst + where ]'||l_tags||q'[ + union all + select id from tests_with_tags_inh_from_suite tst + where ]'||l_tags||q'[ + ) + ) t where c.id = t.id and r_num = 1 ]'; + execute immediate l_sql bulk collect into l_suite_tags using a_suite_items; + return l_suite_tags; + end; + + function apply( + a_unfiltered_rows ut_suite_cache_rows, + a_tags varchar2 := null + ) return ut_suite_cache_rows is + l_suite_items ut_suite_cache_rows := a_unfiltered_rows; + begin + if length(a_tags) > 0 then + l_suite_items := get_tags_suites(l_suite_items,a_tags); + end if; + + return l_suite_items; + end; + +begin + --Define operators precedence + g_precedence('!'):=4; + g_precedence('&'):=3; + g_precedence('|'):=2; + g_precedence(')'):=1; + g_precedence('('):=1; + +end ut_suite_tag_filter; +/ diff --git a/source/core/ut_suite_tag_filter.pks b/source/core/ut_suite_tag_filter.pks new file mode 100644 index 000000000..e824ae275 --- /dev/null +++ b/source/core/ut_suite_tag_filter.pks @@ -0,0 +1,55 @@ +create or replace package ut_suite_tag_filter authid definer is + /* + utPLSQL - Version 3 + Copyright 2016 - 2023 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. + */ + + /** + * Package that will filter suites by tags + * + */ + + /* + * Return table of tokens character by character + */ + function tokenize_tags_string(a_tags in varchar2) return ut_varchar2_list; + + /* + * Function that uses Dijkstra algorithm to parse mathematical and logical expression + * and return a list of elements in Reverse Polish Notation ( postfix ) + * As part of execution it will validate expression. + */ + function shunt_logical_expression(a_tags in ut_varchar2_list) return ut_varchar2_list; + + /* + * Function that converts postfix notation into infix and creating a string of sql filter + * that checking a tags collections for tags according to posted logic. + */ + function conv_postfix_to_infix_sql(a_postfix_exp in ut_varchar2_list,a_tags_column_name in varchar2) + return varchar2; + + /* + * Generates a part where clause sql + */ + function create_where_filter(a_tags varchar2) + return varchar2; + + function apply( + a_unfiltered_rows ut_suite_cache_rows, + a_tags varchar2 := null + ) return ut_suite_cache_rows; + +end ut_suite_tag_filter; +/ diff --git a/source/core/ut_utils.pkb b/source/core/ut_utils.pkb index 2528c04e7..81d47221b 100644 --- a/source/core/ut_utils.pkb +++ b/source/core/ut_utils.pkb @@ -1,7 +1,7 @@ create or replace package body ut_utils is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -16,6 +16,15 @@ create or replace package body ut_utils is limitations under the License. */ + /** + * Constants regex used to validate XML name + */ + gc_invalid_first_xml_char constant varchar2(50) := '[^_[:alpha:]]'; + gc_invalid_xml_char constant varchar2(50) := '[^_[:alnum:]\.-]'; + gc_full_valid_xml_name constant varchar2(50) := '^([[:alpha:]])([_[:alnum:]\.-])*$'; + gc_owner_hash constant integer(11) := dbms_utility.get_hash_value( ut_owner(), 0, power(2,31)-1); + + function surround_with(a_value varchar2, a_quote_char varchar2) return varchar2 is begin return case when a_quote_char is not null then a_quote_char||a_value||a_quote_char else a_value end; @@ -52,21 +61,9 @@ create or replace package body ut_utils is function gen_savepoint_name return varchar2 is begin - return '"'|| utl_raw.cast_to_varchar2(utl_encode.base64_encode(sys_guid()))||'"'; + return 's'||gc_owner_hash||trim(to_char(ut_savepoint_seq.nextval,'00000000000000000')); 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 @@ -89,48 +86,66 @@ create or replace package body ut_utils is $end end; - function to_string(a_value varchar2, a_qoute_char varchar2 := '''') return varchar2 is - l_len integer := coalesce(length(a_value),0); - l_result varchar2(32767); + function to_string( + a_value varchar2, + a_quote_char varchar2 := '''', + a_max_output_len in number := gc_max_output_string_length + ) return varchar2 is + l_result varchar2(32767); + c_length constant integer := coalesce( lengthb( a_value ), 0 ); + c_max_input_string_length constant integer := a_max_output_len - coalesce( lengthb( a_quote_char ) * 2, 0 ); + c_overflow_substr_len constant integer := c_max_input_string_length - gc_more_data_string_len; begin - if l_len = 0 then + if c_length = 0 then l_result := gc_null_string; - elsif l_len <= gc_max_input_string_length then - l_result := surround_with(a_value, a_qoute_char); + elsif c_length <= c_max_input_string_length then + l_result := surround_with(a_value, a_quote_char); else - l_result := surround_with(substr(a_value,1,gc_overflow_substr_len),a_qoute_char) || gc_more_data_string; + l_result := surround_with(substr(a_value, 1, c_overflow_substr_len ), a_quote_char) || gc_more_data_string; end if ; return l_result; end; - function to_string(a_value clob, a_qoute_char varchar2 := '''') return varchar2 is - l_len integer := coalesce(dbms_lob.getlength(a_value), 0); - l_result varchar2(32767); + function to_string( + a_value clob, + a_quote_char varchar2 := '''', + a_max_output_len in number := gc_max_output_string_length + ) return varchar2 is + l_result varchar2(32767); + c_length constant integer := coalesce(ut_utils.lengthb_clob(a_value), 0); + c_max_input_string_length constant integer := a_max_output_len - coalesce( lengthb( a_quote_char ) * 2, 0 ); + c_overflow_substr_len constant integer := c_max_input_string_length - gc_more_data_string_len; begin if a_value is null then l_result := gc_null_string; - elsif l_len = 0 then + elsif c_length = 0 then l_result := gc_empty_string; - elsif l_len <= gc_max_input_string_length then - l_result := surround_with(a_value,a_qoute_char); + elsif c_length <= c_max_input_string_length then + l_result := surround_with(a_value,a_quote_char); else - l_result := surround_with(dbms_lob.substr(a_value, gc_overflow_substr_len),a_qoute_char) || gc_more_data_string; + l_result := surround_with(dbms_lob.substr(a_value, c_overflow_substr_len), a_quote_char) || gc_more_data_string; end if; return l_result; end; - function to_string(a_value blob, a_qoute_char varchar2 := '''') return varchar2 is - l_len integer := coalesce(dbms_lob.getlength(a_value), 0); - l_result varchar2(32767); + function to_string( + a_value blob, + a_quote_char varchar2 := '''', + a_max_output_len in number := gc_max_output_string_length + ) return varchar2 is + l_result varchar2(32767); + c_length constant integer := coalesce(dbms_lob.getlength(a_value), 0); + c_max_input_string_length constant integer := a_max_output_len - coalesce( lengthb( a_quote_char ) * 2, 0 ); + c_overflow_substr_len constant integer := c_max_input_string_length - gc_more_data_string_len; begin if a_value is null then l_result := gc_null_string; - elsif l_len = 0 then + elsif c_length = 0 then l_result := gc_empty_string; - elsif l_len <= gc_max_input_string_length then - l_result := surround_with(rawtohex(a_value),a_qoute_char); + elsif c_length <= c_max_input_string_length then + l_result := surround_with(rawtohex(a_value),a_quote_char); else - l_result := to_string( rawtohex(dbms_lob.substr(a_value, gc_overflow_substr_len)) ); + l_result := to_string( rawtohex(dbms_lob.substr(a_value, c_overflow_substr_len)) ); end if ; return l_result; end; @@ -215,6 +230,19 @@ create or replace package body ut_utils is return l_result; end; + function string_table_to_table(a_list ut_varchar2_list, a_delimiter varchar2:= chr(10), a_skip_leading_delimiter varchar2 := 'N') return ut_varchar2_list is + l_result ut_varchar2_list; + begin + if a_delimiter is null then + l_result := a_list; + elsif a_list is not empty then + for i in 1 .. a_list.count loop + ut_utils.append_to_list(l_result, ut_utils.string_to_table(a_list(i), a_delimiter, a_skip_leading_delimiter) ); + end loop; + end if; + return l_result; + end; + function clob_to_table(a_clob clob, a_max_amount integer := 8191, a_delimiter varchar2:= chr(10)) return ut_varchar2_list is l_offset integer := 1; l_length integer := dbms_lob.getlength(a_clob); @@ -228,7 +256,9 @@ create or replace package body ut_utils is begin while l_offset <= l_length loop l_amount := a_max_amount - coalesce( length(l_last_line), 0 ); - dbms_lob.read(a_clob, l_amount, l_offset, l_buffer); +-- dbms_lob.read(a_clob, l_amount, l_offset, l_buffer); + l_buffer := substr(a_clob, l_offset, l_amount); + l_amount := length(l_buffer); l_offset := l_offset + l_amount; l_string_results := string_to_table( l_last_line || l_buffer, a_delimiter, l_skip_leading_delimiter ); @@ -272,6 +302,20 @@ create or replace package body ut_utils is return l_result; end; + function table_to_clob(a_text_table ut_varchar2_rows, a_delimiter varchar2:= chr(10)) return clob is + l_result clob; + l_table_rows integer := coalesce(cardinality(a_text_table),0); + begin + for i in 1 .. l_table_rows loop + if i < l_table_rows then + append_to_clob(l_result, a_text_table(i)||a_delimiter); + else + append_to_clob(l_result, a_text_table(i)); + end if; + end loop; + return l_result; + end; + function table_to_clob(a_integer_table ut_integer_list, a_delimiter varchar2:= chr(10)) return clob is l_result clob; l_table_rows integer := coalesce(cardinality(a_integer_table),0); @@ -307,7 +351,7 @@ create or replace package body ut_utils is function get_utplsql_objects_list return ut_object_names is l_result ut_object_names; begin - select distinct ut_object_name(sys_context('userenv','current_user'), o.object_name) + select /*+ no_parallel */ distinct ut_object_name(sys_context('userenv','current_user'), o.object_name) bulk collect into l_result from user_objects o where o.object_name = 'UT' or object_name like 'UT\_%' escape '\' @@ -326,7 +370,63 @@ 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_list, a_items ut_varchar2_list) is + begin + if a_items is not null then + if a_list is null then + a_list := ut_varchar2_list(); + 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 lengthb(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 @@ -368,22 +468,12 @@ procedure append_to_clob(a_src_clob in out nocopy clob, a_clob_table t_clob_tab, l_result := ut_varchar2_rows(); for i in 1 .. a_collection.count loop l_result.extend(); - l_result(i) := substr(a_collection(i),1,gc_max_storage_varchar2_len); + l_result(i) := substrb(a_collection(i),1,gc_max_storage_varchar2_len); end loop; end if; return l_result; end; - procedure set_action(a_text in varchar2) is - begin - dbms_application_info.set_module('utPLSQL', a_text); - end; - - procedure set_client_info(a_text in varchar2) is - begin - dbms_application_info.set_client_info(a_text); - end; - function to_xpath(a_list varchar2, a_ancestors varchar2 := '/*/') return varchar2 is l_xpath varchar2(32767) := a_list; begin @@ -416,12 +506,6 @@ procedure append_to_clob(a_src_clob in out nocopy clob, a_clob_table t_clob_tab, return l_xpath; end; - procedure cleanup_temp_tables is - begin - execute immediate 'delete from ut_compound_data_tmp'; - execute immediate 'delete from ut_compound_data_diff_tmp'; - end; - function to_version(a_version_no varchar2) return t_version is l_result t_version; c_version_part_regex constant varchar2(20) := '[0-9]+'; @@ -448,9 +532,11 @@ procedure append_to_clob(a_src_clob in out nocopy clob, a_clob_table t_clob_tab, procedure flush_lines(a_lines ut_varchar2_rows, a_offset integer) is begin - insert into ut_dbms_output_cache (seq_no,text) - select rownum+a_offset, column_value - from table(a_lines); + if a_lines is not empty then + insert /*+ no_parallel */ into ut_dbms_output_cache (seq_no,text) + select /*+ no_parallel */ rownum+a_offset, column_value + from table(a_lines); + end if; end; begin loop @@ -470,10 +556,10 @@ procedure append_to_clob(a_src_clob in out nocopy clob, a_clob_table t_clob_tab, procedure read_cache_to_dbms_output is l_lines_data sys_refcursor; l_lines ut_varchar2_rows; - c_lines_limit constant integer := 100; + c_lines_limit constant integer := 10000; pragma autonomous_transaction; begin - open l_lines_data for select text from ut_dbms_output_cache order by seq_no; + open l_lines_data for select /*+ no_parallel */ text from ut_dbms_output_cache order by seq_no; loop fetch l_lines_data bulk collect into l_lines limit c_lines_limit; for i in 1 .. l_lines.count loop @@ -485,18 +571,19 @@ procedure append_to_clob(a_src_clob in out nocopy clob, a_clob_table t_clob_tab, end loop; exit when l_lines_data%notfound; end loop; - delete from ut_dbms_output_cache; + close l_lines_data; + execute immediate 'truncate table ut_dbms_output_cache'; commit; end; function ut_owner return varchar2 is begin - return sys_context('userenv','current_schema'); + return qualified_sql_name( sys_context('userenv','current_schema') ); end; function scale_cardinality(a_cardinality natural) return natural is begin - return nvl(trunc(power(10,(floor(log(10,a_cardinality))+1))/3),0); + return case when a_cardinality > 0 then trunc(power(10,(floor(log(10,a_cardinality))+1))/3) else 1 end; end; function build_depreciation_warning(a_old_syntax varchar2, a_new_syntax varchar2) return varchar2 is @@ -522,7 +609,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 @@ -547,7 +634,6 @@ procedure append_to_clob(a_src_clob in out nocopy clob, a_clob_table t_clob_tab, if a_list is not null then l_filtered_list := ut_varchar2_list(); l_index := a_list.first; - while (l_index is not null) loop if regexp_like(a_list(l_index), a_regexp_filter) then l_filtered_list.extend; @@ -561,15 +647,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_sql varchar2(32767) := q'!select q'[!'||a_string||q'!]' as "!'||a_string||'" from dual'; + l_result varchar2(4000) := a_string; + l_sql varchar2(32767) := q'!select /*+ no_parallel */ 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() + select /*+ no_parallel */ extract(dbms_xmlgen.getxmltype(l_sql),'/*/*/*').getRootElement() into l_result from dual; - else - l_result := a_string; end if; return l_result; end; @@ -663,5 +747,282 @@ procedure append_to_clob(a_src_clob in out nocopy clob, a_clob_table t_clob_tab, return l_result; end; + function get_child_reporters(a_for_reporters ut_reporters_info := null) return ut_reporters_info is + l_for_reporters ut_reporters_info := a_for_reporters; + l_results ut_reporters_info; + begin + if l_for_reporters is null then + l_for_reporters := ut_reporters_info(ut_reporter_info('UT_REPORTER_BASE','N','N','N')); + end if; + + select /*+ no_parallel cardinality(f 10) */ + ut_reporter_info( + object_name => t.type_name, + is_output_reporter => + case + when f.is_output_reporter = 'Y' or t.type_name = 'UT_OUTPUT_REPORTER_BASE' + then 'Y' else 'N' + end, + is_instantiable => case when t.instantiable = 'YES' then 'Y' else 'N' end, + is_final => case when t.final = 'YES' then 'Y' else 'N' end + ) + bulk collect into l_results + from user_types t + join (select * from table(l_for_reporters) where is_final = 'N' ) f + on f.object_name = supertype_name; + + return l_results; + end; + + function remove_error_from_stack(a_error_stack varchar2, a_ora_code number) return varchar2 is + l_caller_stack_line varchar2(4000); + l_ora_search_pattern varchar2(500) := '^ORA'||a_ora_code||': (.*)$'; + begin + l_caller_stack_line := regexp_replace(srcstr => a_error_stack + ,pattern => l_ora_search_pattern + ,replacestr => null + ,position => 1 + ,occurrence => 1 + ,modifier => 'm'); + return l_caller_stack_line; + end; + + /** + * Change string into unicode to match xmlgen format _00_ + * See the section of Oracle documentation called: Escape of Characters in Generated XML Data + * https://docs.oracle.com/en/database/oracle/oracle-database/12.2/adxdb/generation-of-XML-data-from-relational-data.html#GUID-5BE09A7D-80D8-4734-B9AF-4A61F27FA9B2 + */ + function char_to_xmlgen_unicode(a_character varchar2) return varchar2 is + begin + return '_x00'||rawtohex(utl_raw.cast_to_raw(a_character))||'_'; + end; + + /** + * Build valid XML column name as element names can contain letters, digits, hyphens, underscores, and periods + */ + function build_valid_xml_name(a_preprocessed_name varchar2) return varchar2 is + l_post_processed varchar2(4000); + begin + for i in (select /*+ no_parallel */ regexp_substr( a_preprocessed_name ,'(.{1})', 1, level, null, 1 ) AS string_char,level level_no + from dual connect by level <= regexp_count(a_preprocessed_name, '(.{1})')) + loop + if i.level_no = 1 and regexp_like(i.string_char,gc_invalid_first_xml_char) then + l_post_processed := l_post_processed || char_to_xmlgen_unicode(i.string_char); + elsif regexp_like(i.string_char,gc_invalid_xml_char) then + l_post_processed := l_post_processed || char_to_xmlgen_unicode(i.string_char); + else + l_post_processed := l_post_processed || i.string_char; + end if; + end loop; + return l_post_processed; + end; + + function get_valid_xml_name(a_name varchar2) return varchar2 is + l_valid_name varchar2(4000); + begin + if regexp_like(a_name,gc_full_valid_xml_name) then + l_valid_name := a_name; + else + l_valid_name := build_valid_xml_name(a_name); + end if; + return l_valid_name; + end; + + function to_cdata(a_lines ut_varchar2_rows) return ut_varchar2_rows is + l_results ut_varchar2_rows; + begin + if a_lines is not empty then + ut_utils.append_to_list( l_results, gc_cdata_start_tag); + for i in 1 .. a_lines.count loop + ut_utils.append_to_list( l_results, replace( a_lines(i), gc_cdata_end_tag, gc_cdata_end_tag_wrap ) ); + end loop; + ut_utils.append_to_list( l_results, gc_cdata_end_tag); + else + l_results := a_lines; + end if; + return l_results; + end; + + function to_cdata(a_clob clob) return clob is + l_result clob; + begin + if a_clob is not null and a_clob != empty_clob() then + l_result := replace( a_clob, gc_cdata_end_tag, gc_cdata_end_tag_wrap ); + l_result := to_clob(gc_cdata_start_tag) + || replace( a_clob, gc_cdata_end_tag, gc_cdata_end_tag_wrap ) + || to_clob(gc_cdata_end_tag); + else + l_result := a_clob; + end if; + return l_result; + end; + + function add_prefix(a_list ut_varchar2_list, a_prefix varchar2, a_connector varchar2 := '/') return ut_varchar2_list is + l_result ut_varchar2_list := ut_varchar2_list(); + l_idx binary_integer; + begin + if a_prefix is not null then + l_idx := a_list.first; + while l_idx is not null loop + l_result.extend; + l_result(l_idx) := add_prefix(a_list(l_idx), a_prefix, a_connector); + l_idx := a_list.next(l_idx); + end loop; + end if; + return l_result; + end; + + function add_prefix(a_item varchar2, a_prefix varchar2, a_connector varchar2 := '/') return varchar2 is + begin + return a_prefix||a_connector||trim(leading a_connector from a_item); + end; + + function strip_prefix(a_item varchar2, a_prefix varchar2, a_connector varchar2 := '/') return varchar2 is + begin + return regexp_replace(a_item,a_prefix||a_connector); + end; + + function get_hash(a_data raw, a_hash_type binary_integer := dbms_crypto.hash_sh1) return t_hash is + begin + --We cannot run hash on null + return case when a_data is null then null else dbms_crypto.hash(a_data, a_hash_type) end; + end; + + function get_hash(a_data clob, a_hash_type binary_integer := dbms_crypto.hash_sh1) return t_hash is + begin + --We cannot run hash on null + return case when a_data is null then null else dbms_crypto.hash(a_data, a_hash_type) end; + end; + + function hash_suite_path(a_path varchar2, a_random_seed positiven) return varchar2 is + l_start_pos pls_integer := 1; + l_end_pos pls_integer := 1; + l_result varchar2(4000); + l_item varchar2(4000); + l_at_end boolean := false; + begin + if a_random_seed is null then + l_result := a_path; + end if; + if a_path is not null then + loop + l_end_pos := instr(a_path,'.',l_start_pos); + if l_end_pos = 0 then + l_end_pos := length(a_path)+1; + l_at_end := true; + end if; + l_item := substr(a_path,l_start_pos,l_end_pos-l_start_pos); + if l_item is not null then + l_result := + l_result || + ut_utils.get_hash( to_char( dbms_utility.get_hash_value( l_item, 1, a_random_seed ) ) ); + end if; + exit when l_at_end; + l_result := l_result || chr(0); + l_start_pos := l_end_pos + 1; + end loop; + end if; + return l_result; + end; + + function qualified_sql_name(a_name varchar2) return varchar2 is + begin + return + case + when a_name is not null + then sys.dbms_assert.qualified_sql_name(a_name) + end; + end; + + function interval_to_text(a_interval dsinterval_unconstrained) return varchar2 is + l_day varchar2(100) := extract(day from a_interval); + l_hour varchar2(100) := extract(hour from a_interval); + l_minute varchar2(100) := extract(minute from a_interval); + l_second varchar2(100) := extract(second from a_interval); + l_result varchar2(32767); + begin + l_result := case + when l_day = 1 then l_day ||' day' + when l_day > 1 then l_day ||' days' + end || + case + when l_hour = 1 then ' '|| l_hour ||' hour' + when l_hour > 1 then ' '|| l_hour ||' hours' + end || + case + when l_minute = 1 then ' '||l_minute ||' minute' + when l_minute > 1 then ' '||l_minute ||' minutes' + end || + case + when l_second > 1 then ' '||l_second ||' seconds' + when l_second = 1 then ' '||l_second ||' second' + when l_second > 0 then ' '||l_second ||' seconds' + end; + l_result := + case + when a_interval is null then 'NULL' + when l_result is null then '0 seconds' + else ltrim(l_result,' ') + end; + + return l_result; + end; + + function interval_to_text(a_interval yminterval_unconstrained) return varchar2 is + l_year varchar2(4) := extract(year from a_interval); + l_month varchar2(20) := extract(month from a_interval); + l_result varchar2(32767); + begin + l_result := case + when l_year = 1 then l_year ||' year' + when l_year > 1 then l_year ||' years' + end || + case + when l_month > 1 then ' '||l_month ||' months' + when l_month = 1 then ' '||l_month ||' month' + end; + l_result := + case + when a_interval is null then 'NULL' + when l_result is null then '0 months' + else ltrim(l_result,' ') + end; + + return l_result; + end; + + + /* + * Inspired by + * https://stackoverflow.com/a/48782891 + */ + function lengthb_clob( a_clob clob) return integer is + l_blob blob; + l_desc_offset PLS_INTEGER := 1; + l_src_offset PLS_INTEGER := 1; + l_lang PLS_INTEGER := 0; + l_warning PLS_INTEGER := 0; + l_result integer; + begin + if a_clob = empty_clob() then + l_result := 0; + elsif a_clob is not null then + dbms_lob.createtemporary(l_blob,true); + dbms_lob.converttoblob + ( l_blob + , a_clob + , dbms_lob.getlength(a_clob) + , l_desc_offset + , l_src_offset + , dbms_lob.default_csid + , l_lang + , l_warning + ); + l_result := length(l_blob); + dbms_lob.freetemporary(l_blob); + end if; + return l_result; + end; + end ut_utils; / diff --git a/source/core/ut_utils.pks b/source/core/ut_utils.pks index ae2f6710f..0e1e0a851 100644 --- a/source/core/ut_utils.pks +++ b/source/core/ut_utils.pks @@ -1,7 +1,7 @@ create or replace package ut_utils authid definer is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -21,30 +21,8 @@ create or replace package ut_utils authid definer is * */ - gc_version constant varchar2(50) := 'v3.1.3.2245-develop'; - - /* Constants: Event names */ - subtype t_event_name is varchar2(30); - gc_before_run constant t_event_name := 'before_run'; - gc_before_suite constant t_event_name := 'before_suite'; - gc_before_before_all constant t_event_name := 'before_beforeall'; - gc_before_before_each constant t_event_name := 'before_beforeeach'; - gc_before_before_test constant t_event_name := 'before_beforetest'; - gc_before_test_execute constant t_event_name := 'before_test'; - gc_before_after_test constant t_event_name := 'before_aftertest'; - gc_before_after_each constant t_event_name := 'before_aftereach'; - gc_before_after_all constant t_event_name := 'before_afterall'; - gc_after_run constant t_event_name := 'after_run'; - gc_after_suite constant t_event_name := 'after_suite'; - gc_after_before_all constant t_event_name := 'after_beforeall'; - gc_after_before_each constant t_event_name := 'after_beforeeach'; - gc_after_before_test constant t_event_name := 'after_beforetest'; - gc_after_test_execute constant t_event_name := 'after_test'; - gc_after_after_test constant t_event_name := 'after_aftertest'; - gc_after_after_each constant t_event_name := 'after_aftereach'; - gc_after_after_all constant t_event_name := 'after_afterall'; - gc_finalize constant t_event_name := 'finalize'; - + gc_version constant varchar2(50) := 'v3.1.14.4206-develop'; + subtype t_executable_type is varchar2(30); gc_before_all constant t_executable_type := 'beforeall'; gc_before_each constant t_executable_type := 'beforeeach'; @@ -66,6 +44,11 @@ create or replace package ut_utils authid definer is gc_failure_char constant varchar2(7) := 'Failure'; -- one or more expectations failed gc_error_char constant varchar2(5) := 'Error'; -- exception was raised + gc_cdata_start_tag constant varchar2(10) := ''; + gc_cdata_end_tag_wrap constant varchar2(30) := ']]'||gc_cdata_end_tag||gc_cdata_start_tag||'>'; + + /* Constants: Rollback type for ut_test_object */ @@ -105,27 +88,65 @@ create or replace package ut_utils authid definer is gc_some_tests_failed constant pls_integer := -20213; pragma exception_init(ex_some_tests_failed, -20213); - -- Any of tests failed + -- Version number provided is not in valid format ex_invalid_version_no exception; gc_invalid_version_no constant pls_integer := -20214; pragma exception_init(ex_invalid_version_no, -20214); + -- Version number provided is not in valid format + ex_out_buffer_timeout exception; + gc_out_buffer_timeout constant pls_integer := -20215; + pragma exception_init(ex_out_buffer_timeout, -20215); + ex_invalid_package exception; gc_invalid_package constant pls_integer := -6550; pragma exception_init(ex_invalid_package, -6550); + ex_failure_for_all exception; + gc_failure_for_all constant pls_integer := -24381; + pragma exception_init (ex_failure_for_all, -24381); + + ex_dml_for_all exception; + gc_dml_for_all constant pls_integer := -20216; + pragma exception_init (ex_dml_for_all, -20216); + + ex_value_too_large exception; + gc_value_too_large constant pls_integer := -20217; + pragma exception_init (ex_value_too_large, -20217); + + ex_xml_processing exception; + gc_xml_processing constant pls_integer := -19202; + pragma exception_init (ex_xml_processing, -19202); + + ex_failed_open_cur exception; + gc_failed_open_cur constant pls_integer := -20218; + pragma exception_init (ex_failed_open_cur, -20218); + + ex_invalid_tag_expression exception; + gc_invalid_tag_expression constant pls_integer := -20219; + pragma exception_init (ex_invalid_tag_expression, -20219); + gc_max_storage_varchar2_len constant integer := 4000; gc_max_output_string_length constant integer := 4000; - gc_max_input_string_length constant integer := gc_max_output_string_length - 2; --we need to remove 2 chars for quotes around string gc_more_data_string constant varchar2(5) := '[...]'; - gc_overflow_substr_len constant integer := gc_max_input_string_length - length(gc_more_data_string); + gc_more_data_string_len constant integer := length( gc_more_data_string ); gc_number_format constant varchar2(100) := 'TM9'; - gc_date_format constant varchar2(100) := 'yyyy-mm-dd"T"hh24:mi:ss'; - gc_timestamp_format constant varchar2(100) := 'yyyy-mm-dd"T"hh24:mi:ssxff'; - gc_timestamp_tz_format constant varchar2(100) := 'yyyy-mm-dd"T"hh24:mi:ssxff tzh:tzm'; + gc_date_format constant varchar2(100) := 'syyyy-mm-dd"T"hh24:mi:ss'; + gc_timestamp_format constant varchar2(100) := 'syyyy-mm-dd"T"hh24:mi:ssxff'; + gc_timestamp_tz_format constant varchar2(100) := 'syyyy-mm-dd"T"hh24:mi:ssxff tzh:tzm'; gc_null_string constant varchar2(4) := 'NULL'; gc_empty_string constant varchar2(5) := 'EMPTY'; + gc_bc_fetch_limit constant integer := 1000; + gc_diff_max_rows constant integer := 20; + + gc_max_objects_fetch_limit constant integer := 1000000; + + /** + * Regexp to validate tag + */ + gc_word_no_space constant varchar2(50) := '^(\w|\S)+$'; + type t_version is record( major natural, minor natural, @@ -157,11 +178,23 @@ create or replace package ut_utils authid definer is procedure debug_log(a_message clob); - function to_string(a_value varchar2, a_qoute_char varchar2 := '''') return varchar2; + function to_string( + a_value varchar2, + a_quote_char varchar2 := '''', + a_max_output_len in number := gc_max_output_string_length + ) return varchar2; - function to_string(a_value clob, a_qoute_char varchar2 := '''') return varchar2; + function to_string( + a_value clob, + a_quote_char varchar2 := '''', + a_max_output_len in number := gc_max_output_string_length + ) return varchar2; - function to_string(a_value blob, a_qoute_char varchar2 := '''') return varchar2; + function to_string( + a_value blob, + a_quote_char varchar2 := '''', + a_max_output_len in number := gc_max_output_string_length + ) return varchar2; function to_string(a_value boolean) return varchar2; @@ -183,18 +216,14 @@ 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. * The delimiter gets removed. - * If null passed as any of the parameters, empty table is returned. - * If no occurence of a_delimiter found in a_text then text is returned as a single row of the table. + * If null a_string passed, empty table is returned. + * If null a_delimiter passed, a_string is returned as element of result table. + * If null a_skip_leading_delimiter, it defaults to 'N' + * If no occurrence of a_delimiter found in a_text then text is returned as a single row of the table. * If no text between delimiters found then an empty row is returned, example: * string_to_table( 'a,,b', ',' ) gives table ut_varchar2_list( 'a', null, 'b' ); * @@ -206,14 +235,36 @@ create or replace package ut_utils authid definer is */ function string_to_table(a_string varchar2, a_delimiter varchar2:= chr(10), a_skip_leading_delimiter varchar2 := 'N') return ut_varchar2_list; + /** + * + * Splits each string in table of string into a table of string using specified delimiter. + * The delimiter gets removed. + * If null a_delimiter passed, a_list is returned as-is. + * If null a_list passed, empty table is returned. + * If null a_skip_leading_delimiter, it defaults to 'N' + * If no occurrence of a_delimiter found in a_text then text is returned as a single row of the table. + * If no text between delimiters found then an empty row is returned, example: + * string_table_to_table( a_list => ut_varchar2_list('x','y',null,'a,,b'), a_delimiter=>',' ) gives table ut_varchar2_list( 'x', 'y', null, 'a', null, 'b' ); + * + * @param a_list the table of texts to be split. + * @param a_delimiter the delimiter character or string + * @param a_skip_leading_delimiter determines if the leading delimiter should be ignored, used by clob_to_table + * + * @return table of varchar2 values + */ + function string_table_to_table(a_list ut_varchar2_list, a_delimiter varchar2:= chr(10), a_skip_leading_delimiter varchar2 := 'N') return ut_varchar2_list; + /** * Splits a given string into table of string by delimiter. * Default value of a_max_amount is 8191 because of code can contains multibyte character. * The delimiter gets removed. - * If null passed as any of the parameters, empty table is returned. + * If null a_clob passed, empty table is returned. + * If null a_delimiter passed, a_string is returned as element of result table. + * If null a_skip_leading_delimiter, it defaults to 'N' + * If no occurrence of a_delimiter found in a_text then text is returned as a single row of the table. * If split text is longer than a_max_amount it gets split into pieces of a_max_amount. * If no text between delimiters found then an empty row is returned, example: - * string_to_table( 'a,,b', ',' ) gives table ut_varchar2_list( 'a', null, 'b' ); + * clob_to_table( 'a,,b', ',' ) gives table ut_varchar2_list( 'a', null, 'b' ); * * @param a_clob the text to be split. * @param a_delimiter the delimiter character or string (default chr(10) ) @@ -223,7 +274,9 @@ create or replace package ut_utils authid definer is function clob_to_table(a_clob clob, a_max_amount integer := 8191, a_delimiter varchar2:= chr(10)) return ut_varchar2_list; function table_to_clob(a_text_table ut_varchar2_list, a_delimiter varchar2:= chr(10)) return clob; - + + function table_to_clob(a_text_table ut_varchar2_rows, a_delimiter varchar2:= chr(10)) return clob; + function table_to_clob(a_integer_table ut_integer_list, a_delimiter varchar2:= chr(10)) return clob; /** @@ -247,30 +300,38 @@ create or replace package ut_utils authid definer is */ procedure append_to_list(a_list in out nocopy ut_varchar2_list, a_item varchar2); - 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); - - procedure append_to_clob(a_src_clob in out nocopy clob, a_new_data 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); - function convert_collection(a_collection ut_varchar2_list) return ut_varchar2_rows; + /** + * 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); /** - * Set session's action and module using dbms_application_info + * Append a list of items to the end of ut_varchar2_rows */ - procedure set_action(a_text in varchar2); + procedure append_to_list(a_list in out nocopy ut_varchar2_rows, a_items ut_varchar2_rows); /** - * Set session's client info using dbms_application_info + * Append a list of items to the end of ut_varchar2_list */ - procedure set_client_info(a_text in varchar2); + procedure append_to_list(a_list in out nocopy ut_varchar2_list, a_items ut_varchar2_list); + + 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); + + procedure append_to_clob(a_src_clob in out nocopy clob, a_new_data varchar2); + + function convert_collection(a_collection ut_varchar2_list) return ut_varchar2_rows; function to_xpath(a_list varchar2, a_ancestors varchar2 := '/*/') return varchar2; function to_xpath(a_list ut_varchar2_list, a_ancestors varchar2 := '/*/') return varchar2; - procedure cleanup_temp_tables; - /** * Converts version string into version record * @@ -328,10 +389,14 @@ create or replace package ut_utils authid definer is function get_xml_header(a_encoding varchar2) return varchar2; - /*It takes a collection of type ut_varchar2_list and it trims the characters passed as arguments for every element*/ + /** + * Takes a collection of type ut_varchar2_list and it trims the characters passed as arguments for every element + */ function trim_list_elements(a_list IN ut_varchar2_list, a_regexp_to_trim in varchar2 default '[:space:]') return ut_varchar2_list; - /*It takes a collection of type ut_varchar2_list and it only returns the elements which meets the regular expression*/ + /** + * Takes a collection of type ut_varchar2_list and it only returns the elements which meets the regular expression + */ function filter_list(a_list IN ut_varchar2_list, a_regexp_filter in varchar2) return ut_varchar2_list; -- Generates XMLGEN escaped string @@ -342,5 +407,80 @@ create or replace package ut_utils authid definer is */ function replace_multiline_comments(a_source clob) return clob; + /** + * Returns list of sub-type reporters for given list of super-type reporters + */ + function get_child_reporters(a_for_reporters ut_reporters_info := null) return ut_reporters_info; + + /** + * Remove given ORA error from stack + */ + function remove_error_from_stack(a_error_stack varchar2, a_ora_code number) return varchar2; + + /** + * Check if xml name is valid if not build a valid name + */ + function get_valid_xml_name(a_name varchar2) return varchar2; + + /** + * Converts input list into a list surrounded by CDATA tags + * All CDATA end tags get escaped using recommended method from https://en.wikipedia.org/wiki/CDATA#Nesting + */ + function to_cdata(a_lines ut_varchar2_rows) return ut_varchar2_rows; + + /** + * Converts input CLOB into a CLOB surrounded by CDATA tags + * All CDATA end tags get escaped using recommended method from https://en.wikipedia.org/wiki/CDATA#Nesting + */ + function to_cdata(a_clob clob) return clob; + + /** + * Add prefix word to elements of list + */ + function add_prefix(a_list ut_varchar2_list, a_prefix varchar2, a_connector varchar2 := '/') return ut_varchar2_list; + + function add_prefix(a_item varchar2, a_prefix varchar2, a_connector varchar2 := '/') return varchar2; + + function strip_prefix(a_item varchar2, a_prefix varchar2, a_connector varchar2 := '/') return varchar2; + + + subtype t_hash is raw(128); + + /* + * Wrapper function for calling dbms_crypto.hash + */ + function get_hash(a_data raw, a_hash_type binary_integer := dbms_crypto.hash_sh1) return t_hash; + + /* + * Wrapper function for calling dbms_crypto.hash + */ + function get_hash(a_data clob, a_hash_type binary_integer := dbms_crypto.hash_sh1) return t_hash; + + /* + * Returns a hash value of suitepath based on input path and random seed + */ + function hash_suite_path(a_path varchar2, a_random_seed positiven) return varchar2; + + /* + * Verifies that the input string is a qualified SQL name using sys.dbms_assert.qualified_sql_name + * If null value passed returns null + */ + function qualified_sql_name(a_name varchar2) return varchar2; + + /* + * Return value of interval in plain english + */ + function interval_to_text(a_interval dsinterval_unconstrained) return varchar2; + + /* + * Return value of interval in plain english + */ + function interval_to_text(a_interval yminterval_unconstrained) return varchar2; + + /* + * Return length of CLOB in bytes. Null for NULL + */ + function lengthb_clob( a_clob clob) return integer; + end ut_utils; / diff --git a/source/create_grants.sql b/source/create_grants.sql new file mode 100644 index 000000000..0e9f46cc5 --- /dev/null +++ b/source/create_grants.sql @@ -0,0 +1,144 @@ +/* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + +Create all necessary grant for the user who owns test packages and want to execute utPLSQL framework +*/ + +@@define_ut3_owner_param.sql + +column 2 new_value 2 noprint +select null as "2" from dual where 1=0; +spool params.sql.tmp +select + case + when '&&2' is null then q'[ACCEPT ut3_user CHAR DEFAULT 'PUBLIC' PROMPT 'Provide schema which should be granted access to the utPLSQL v3 framework (PUBLIC): ']' + else 'define ut3_user=&&2' + end +from dual; + +spool off +set termout on +@params.sql.tmp +set termout off +/* cleanup temporary sql files */ +--try running on windows +$ del params.sql.tmp +--try running on linux/unix +! rm params.sql.tmp +set termout on + +set echo off +set feedback on +set heading off +set verify off + +prompt Granting privileges on UTPLSQL objects in &&ut3_owner schema to user &&ut3_user + +whenever sqlerror exit failure rollback +whenever oserror exit failure rollback + +alter session set current_schema = &&ut3_owner; + +--public API +grant execute on &&ut3_owner..ut to &ut3_user; +grant execute on &&ut3_owner..ut_runner to &ut3_user; +grant execute on &&ut3_owner..ut_file_mappings to &ut3_user; +grant execute on &&ut3_owner..ut_file_mapping to &ut3_user; +grant execute on &&ut3_owner..ut_file_mapper to &ut3_user; +grant execute on &&ut3_owner..ut_suite_items_info to &ut3_user; +grant execute on &&ut3_owner..ut_suite_item_info to &ut3_user; +grant execute on &&ut3_owner..ut_suite_cache_rows to &ut3_user; +grant execute on &&ut3_owner..ut_run_info to &ut3_user; +grant execute on &&ut3_owner..ut_coverage_options to &ut3_user; + +--generic types +grant execute on &&ut3_owner..ut_varchar2_list to &ut3_user; +grant execute on &&ut3_owner..ut_varchar2_rows to &ut3_user; +grant execute on &&ut3_owner..ut_integer_list to &ut3_user; +grant execute on &&ut3_owner..ut_key_value_pairs to &ut3_user; +grant execute on &&ut3_owner..ut_key_value_pair to &ut3_user; + +--expectations +grant execute on &&ut3_owner..ut_expectation to &ut3_user; +grant execute on &&ut3_owner..ut_expectation_compound to &ut3_user; +grant execute on &&ut3_owner..ut_expectation_json to &ut3_user; + +--matchers +grant execute on &&ut3_owner..ut_matcher to &ut3_user; +grant execute on &&ut3_owner..ut_be_between to &ut3_user; +grant execute on &&ut3_owner..ut_be_empty to &ut3_user; +grant execute on &&ut3_owner..ut_be_false to &ut3_user; +grant execute on &&ut3_owner..ut_be_greater_or_equal to &ut3_user; +grant execute on &&ut3_owner..ut_be_greater_than to &ut3_user; +grant execute on &&ut3_owner..ut_be_less_or_equal to &ut3_user; +grant execute on &&ut3_owner..ut_be_less_than to &ut3_user; +grant execute on &&ut3_owner..ut_be_like to &ut3_user; +grant execute on &&ut3_owner..ut_be_not_null to &ut3_user; +grant execute on &&ut3_owner..ut_be_null to &ut3_user; +grant execute on &&ut3_owner..ut_be_true to &ut3_user; +grant execute on &&ut3_owner..ut_be_within to &ut3_user; +grant execute on &&ut3_owner..ut_be_within_pct to &ut3_user; +grant execute on &&ut3_owner..ut_contain to &ut3_user; +grant execute on &&ut3_owner..ut_equal to &ut3_user; +grant execute on &&ut3_owner..ut_have_count to &ut3_user; +grant execute on &&ut3_owner..ut_match to &ut3_user; + +--reporters - test results +grant execute on &&ut3_owner..ut_teamcity_reporter to &ut3_user; +grant execute on &&ut3_owner..ut_xunit_reporter to &ut3_user; +grant execute on &&ut3_owner..ut_junit_reporter to &ut3_user; +grant execute on &&ut3_owner..ut_tfs_junit_reporter to &ut3_user; +grant execute on &&ut3_owner..ut_documentation_reporter to &ut3_user; +grant execute on &&ut3_owner..ut_sonar_test_reporter to &ut3_user; +grant execute on &&ut3_owner..ut_realtime_reporter to &ut3_user; +--reporters - coverage +grant execute on &&ut3_owner..ut_coverage_html_reporter to &ut3_user; +grant execute on &&ut3_owner..ut_coverage_sonar_reporter to &ut3_user; +grant execute on &&ut3_owner..ut_coveralls_reporter to &ut3_user; +grant execute on &&ut3_owner..ut_coverage_cobertura_reporter to &ut3_user; +--reporters - debug +grant execute on &&ut3_owner..ut_debug_reporter to &ut3_user; + +--reporters - base types +grant execute on &&ut3_owner..ut_reporters to &ut3_user; +grant execute on &&ut3_owner..ut_reporter_base to &ut3_user; +grant execute on &&ut3_owner..ut_output_reporter_base to &ut3_user; +grant execute on &&ut3_owner..ut_coverage_reporter_base to &ut3_user; +grant execute on &&ut3_owner..ut_console_reporter_base to &ut3_user; + +--outputs +grant execute on &&ut3_owner..ut_output_buffer_base to &ut3_user; +grant execute on &&ut3_owner..ut_output_table_buffer to &ut3_user; +grant execute on &&ut3_owner..ut_output_clob_table_buffer to &ut3_user; +grant execute on &&ut3_owner..ut_output_bulk_buffer to &ut3_user; + +--needed internally for selecting from annotation objects within packages that use invoker rights +grant execute on &&ut3_owner..ut_annotation_objs_cache_info to &ut3_user; +grant execute on &&ut3_owner..ut_annotation_obj_cache_info to &ut3_user; + +--other grants +grant execute on &&ut3_owner..ut_executables to &ut3_user; +grant execute on &&ut3_owner..ut_executable_test to &ut3_user; +grant execute on &&ut3_owner..ut_suite_cache_row to &ut3_user; +grant execute on &&ut3_owner..ut_suite_cache_rows to &ut3_user; + +grant select, insert, delete, update on &&ut3_owner..dbmspcc_blocks to &ut3_user; +grant select, insert, delete, update on &&ut3_owner..dbmspcc_runs to &ut3_user; +grant select, insert, delete, update on &&ut3_owner..dbmspcc_units to &ut3_user; +grant select on &&ut3_owner..ut_coverage_runs to &ut3_user; +grant execute on &&ut3_owner..ut_matcher_options to &ut3_user; +grant execute on &&ut3_owner..ut_matcher_options_items to &ut3_user; + diff --git a/source/create_synonyms.sql b/source/create_synonyms.sql new file mode 100644 index 000000000..fa1c1dc45 --- /dev/null +++ b/source/create_synonyms.sql @@ -0,0 +1,137 @@ +/* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + +Create all necessary grant for the user who owns test packages and want to execute utPLSQL framework +*/ + +@@define_ut3_owner_param.sql + +column 2 new_value 2 noprint +select null as "2" from dual where 1=0; +spool params.sql.tmp +select + case + when '&&2' is null then q'[ACCEPT ut3_user CHAR DEFAULT 'PUBLIC' PROMPT 'Provide schema which should own synonyms for the utPLSQL v3 framework (PUBLIC): ']' + else 'define ut3_user=&&2.' + end +from dual; +spool off +set termout on +@params.sql.tmp +set termout off + +spool params.sql.tmp +select + case + when upper('&&ut3_user') = 'PUBLIC' then q'[define action_type='or replace public' + ]'||q'[define ut3_user='' + ]'||q'[define grantee='PUBLIC']' + else q'[define action_type='or replace' + ]'||q'[define grantee='&&ut3_user'] + ]'||q'[define ut3_user='&&ut3_user..']' + end +from dual; + +spool off +set termout on +@params.sql.tmp +set termout off +/* cleanup temporary sql files */ +--try running on windows +$ del params.sql.tmp +--try running on linux/unix +! rm params.sql.tmp +set termout on + +set echo off +set feedback on +set heading off +set verify off + +whenever sqlerror exit failure rollback +whenever oserror exit failure rollback + +alter session set current_schema = &&ut3_owner; + +prompt Creating synonyms for UTPLSQL objects in &&ut3_owner schema to user &&grantee + +--public API +create &action_type. synonym &ut3_user.ut for &&ut3_owner..ut; +create &action_type. synonym &ut3_user.ut_runner for &&ut3_owner..ut_runner; +create &action_type. synonym &ut3_user.ut_file_mappings for &&ut3_owner..ut_file_mappings; +create &action_type. synonym &ut3_user.ut_file_mapping for &&ut3_owner..ut_file_mapping; +create &action_type. synonym &ut3_user.ut_file_mapper for &&ut3_owner..ut_file_mapper; +create &action_type. synonym &ut3_user.ut_suite_items_info for &&ut3_owner..ut_suite_items_info; +create &action_type. synonym &ut3_user.ut_suite_item_info for &&ut3_owner..ut_suite_item_info; +create &action_type. synonym &ut3_user.ut_run_info for &&ut3_owner..ut_run_info; +create &action_type. synonym &ut3_user.ut_coverage_options for &&ut3_owner..ut_coverage_options; + +--generic types +create &action_type. synonym &ut3_user.ut_varchar2_list for &&ut3_owner..ut_varchar2_list; +create &action_type. synonym &ut3_user.ut_varchar2_rows for &&ut3_owner..ut_varchar2_rows; +create &action_type. synonym &ut3_user.ut_integer_list for &&ut3_owner..ut_integer_list; +create &action_type. synonym &ut3_user.ut_key_value_pairs for &&ut3_owner..ut_key_value_pairs; +create &action_type. synonym &ut3_user.ut_key_value_pair for &&ut3_owner..ut_key_value_pair; + +--expectations +create &action_type. synonym &ut3_user.ut_expectation for &&ut3_owner..ut_expectation; +create &action_type. synonym &ut3_user.ut_expectation_compound for &&ut3_owner..ut_expectation_compound; +create &action_type. synonym &ut3_user.ut_expectation_json for &&ut3_owner..ut_expectation_json; + +--matchers +create &action_type. synonym &ut3_user.ut_matcher for &&ut3_owner..ut_matcher; +create &action_type. synonym &ut3_user.be_between for &&ut3_owner..be_between; +create &action_type. synonym &ut3_user.be_empty for &&ut3_owner..be_empty; +create &action_type. synonym &ut3_user.be_false for &&ut3_owner..be_false; +create &action_type. synonym &ut3_user.be_greater_or_equal for &&ut3_owner..be_greater_or_equal; +create &action_type. synonym &ut3_user.be_greater_than for &&ut3_owner..be_greater_than; +create &action_type. synonym &ut3_user.be_less_or_equal for &&ut3_owner..be_less_or_equal; +create &action_type. synonym &ut3_user.be_less_than for &&ut3_owner..be_less_than; +create &action_type. synonym &ut3_user.be_like for &&ut3_owner..be_like; +create &action_type. synonym &ut3_user.be_not_null for &&ut3_owner..be_not_null; +create &action_type. synonym &ut3_user.be_null for &&ut3_owner..be_null; +create &action_type. synonym &ut3_user.be_true for &&ut3_owner..be_true; +create &action_type. synonym &ut3_user.be_within for &&ut3_owner..be_within; +create &action_type. synonym &ut3_user.be_within_pct for &&ut3_owner..be_within_pct; +create &action_type. synonym &ut3_user.contain for &&ut3_owner..contain; +create &action_type. synonym &ut3_user.equal for &&ut3_owner..equal; +create &action_type. synonym &ut3_user.have_count for &&ut3_owner..have_count; +create &action_type. synonym &ut3_user.match for &&ut3_owner..match; + +--reporters - test results +create &action_type. synonym &ut3_user.ut_teamcity_reporter for &&ut3_owner..ut_teamcity_reporter; +create &action_type. synonym &ut3_user.ut_xunit_reporter for &&ut3_owner..ut_xunit_reporter; +create &action_type. synonym &ut3_user.ut_junit_reporter for &&ut3_owner..ut_junit_reporter; +create &action_type. synonym &ut3_user.ut_tfs_junit_reporter for &&ut3_owner..ut_tfs_junit_reporter; +create &action_type. synonym &ut3_user.ut_documentation_reporter for &&ut3_owner..ut_documentation_reporter; +create &action_type. synonym &ut3_user.ut_sonar_test_reporter for &&ut3_owner..ut_sonar_test_reporter; +create &action_type. synonym &ut3_user.ut_realtime_reporter for &&ut3_owner..ut_realtime_reporter; +--reporters - coverage +create &action_type. synonym &ut3_user.ut_coverage_html_reporter for &&ut3_owner..ut_coverage_html_reporter; +create &action_type. synonym &ut3_user.ut_coverage_sonar_reporter for &&ut3_owner..ut_coverage_sonar_reporter; +create &action_type. synonym &ut3_user.ut_coveralls_reporter for &&ut3_owner..ut_coveralls_reporter; +create &action_type. synonym &ut3_user.ut_coverage_cobertura_reporter for &&ut3_owner..ut_coverage_cobertura_reporter; +--reporters - debug +create &action_type. synonym &ut3_user.ut_debug_reporter for &&ut3_owner..ut_debug_reporter; +--reporters - base types +create &action_type. synonym &ut3_user.ut_reporters for &&ut3_owner..ut_reporters; +create &action_type. synonym &ut3_user.ut_reporter_base for &&ut3_owner..ut_reporter_base; +create &action_type. synonym &ut3_user.ut_output_reporter_base for &&ut3_owner..ut_output_reporter_base; + +--other synonyms +create &action_type. synonym &ut3_user.dbmspcc_blocks for &&ut3_owner..dbmspcc_blocks; +create &action_type. synonym &ut3_user.dbmspcc_runs for &&ut3_owner..dbmspcc_runs; +create &action_type. synonym &ut3_user.dbmspcc_units for &&ut3_owner..dbmspcc_units; diff --git a/source/create_synonyms_and_grants_for_public.sql b/source/create_synonyms_and_grants_for_public.sql index 17452ec0c..050162d72 100644 --- a/source/create_synonyms_and_grants_for_public.sql +++ b/source/create_synonyms_and_grants_for_public.sql @@ -1,6 +1,6 @@ /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -19,141 +19,5 @@ Create all necessary grant for the user who owns test packages and want to execu @@define_ut3_owner_param.sql -set echo off -set feedback on -set heading off -set verify off - -prompt Granting privileges on UTPLSQL objects in &&ut3_owner schema to PUBLIC - -whenever sqlerror exit failure rollback -whenever oserror exit failure rollback - -alter session set current_schema = &&ut3_owner; - -grant execute on &&ut3_owner..ut_expectation to public; -grant execute on &&ut3_owner..ut_expectation_compound to public; -grant execute on &&ut3_owner..ut_be_between to public; -grant execute on &&ut3_owner..ut_be_empty to public; -grant execute on &&ut3_owner..ut_be_false to public; -grant execute on &&ut3_owner..ut_be_greater_or_equal to public; -grant execute on &&ut3_owner..ut_be_greater_than to public; -grant execute on &&ut3_owner..ut_be_less_or_equal to public; -grant execute on &&ut3_owner..ut_be_less_than to public; -grant execute on &&ut3_owner..ut_be_like to public; -grant execute on &&ut3_owner..ut_be_not_null to public; -grant execute on &&ut3_owner..ut_be_null to public; -grant execute on &&ut3_owner..ut_be_true to public; -grant execute on &&ut3_owner..ut_equal to public; -grant execute on &&ut3_owner..ut_have_count to public; -grant execute on &&ut3_owner..ut_match to public; -grant execute on &&ut3_owner..ut to public; -grant execute on &&ut3_owner..ut_runner to public; -grant execute on &&ut3_owner..ut_teamcity_reporter to public; -grant execute on &&ut3_owner..ut_xunit_reporter to public; -grant execute on &&ut3_owner..ut_junit_reporter to public; -grant execute on &&ut3_owner..ut_tfs_junit_reporter to public; -grant execute on &&ut3_owner..ut_documentation_reporter to public; -grant execute on &&ut3_owner..ut_coverage_html_reporter to public; -grant execute on &&ut3_owner..ut_coverage_sonar_reporter to public; -grant execute on &&ut3_owner..ut_coveralls_reporter to public; -grant execute on &&ut3_owner..ut_coverage_cobertura_reporter to public; -grant execute on &&ut3_owner..ut_reporters to public; -grant execute on &&ut3_owner..ut_varchar2_list to public; -grant execute on &&ut3_owner..ut_varchar2_rows to public; -grant execute on &&ut3_owner..ut_integer_list to public; -grant execute on &&ut3_owner..ut_reporter_base to public; -grant execute on &&ut3_owner..ut_output_reporter_base to public; -grant execute on &&ut3_owner..ut_coverage_reporter_base to public; -grant execute on &&ut3_owner..ut_console_reporter_base to public; -grant execute on &&ut3_owner..ut_coverage to public; -grant execute on &&ut3_owner..ut_coverage_options to public; -grant execute on &&ut3_owner..ut_coverage_helper to public; -grant execute on &&ut3_owner..ut_output_buffer_base to public; -grant execute on &&ut3_owner..ut_output_table_buffer to public; -grant execute on &&ut3_owner..ut_file_mappings to public; -grant execute on &&ut3_owner..ut_file_mapping to public; -grant execute on &&ut3_owner..ut_file_mapper to public; -grant execute on &&ut3_owner..ut_key_value_pairs to public; -grant execute on &&ut3_owner..ut_key_value_pair to public; -grant select, insert, delete on &&ut3_owner..ut_compound_data_tmp to public; -grant select, insert, delete on &&ut3_owner..ut_compound_data_diff_tmp to public; -grant execute on &&ut3_owner..ut_sonar_test_reporter to public; -grant execute on &&ut3_owner..ut_annotations to public; -grant execute on &&ut3_owner..ut_annotation to public; -grant execute on &&ut3_owner..ut_annotation_manager to public; -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_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; -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'; - execute immediate 'grant select, insert, delete, update on &&ut3_owner..dbmspcc_runs to public'; - execute immediate 'grant select, insert, delete, update on &&ut3_owner..dbmspcc_units to public'; - $else - null; - $end -end; -/ - -prompt Creating synonyms for UTPLSQL objects in &&ut3_owner schema to PUBLIC - -create public synonym ut_expectation for &&ut3_owner..ut_expectation; -create public synonym ut_expectation_compound for &&ut3_owner..ut_expectation_compound; -create public synonym be_between for &&ut3_owner..ut_be_between; -create public synonym be_empty for &&ut3_owner..ut_be_empty; -create public synonym be_false for &&ut3_owner..ut_be_false; -create public synonym be_greater_or_equal for &&ut3_owner..ut_be_greater_or_equal; -create public synonym be_greater_than for &&ut3_owner..ut_be_greater_than; -create public synonym be_less_or_equal for &&ut3_owner..ut_be_less_or_equal; -create public synonym be_less_than for &&ut3_owner..ut_be_less_than; -create public synonym be_like for &&ut3_owner..ut_be_like; -create public synonym be_not_null for &&ut3_owner..ut_be_not_null; -create public synonym be_null for &&ut3_owner..ut_be_null; -create public synonym be_true for &&ut3_owner..ut_be_true; -create public synonym equal for &&ut3_owner..ut_equal; -create public synonym have_count for &&ut3_owner..have_count; -create public synonym match for &&ut3_owner..ut_match; -create public synonym ut for &&ut3_owner..ut; -create public synonym ut_runner for &&ut3_owner..ut_runner; -create public synonym ut_teamcity_reporter for &&ut3_owner..ut_teamcity_reporter; -create public synonym ut_xunit_reporter for &&ut3_owner..ut_xunit_reporter; -create public synonym ut_junit_reporter for &&ut3_owner..ut_junit_reporter; -create public synonym ut_tfs_junit_reporter for &&ut3_owner..ut_tfs_junit_reporter; -create public synonym ut_documentation_reporter for &&ut3_owner..ut_documentation_reporter; -create public synonym ut_coverage_html_reporter for &&ut3_owner..ut_coverage_html_reporter; -create public synonym ut_coverage_sonar_reporter for &&ut3_owner..ut_coverage_sonar_reporter; -create public synonym ut_coveralls_reporter for &&ut3_owner..ut_coveralls_reporter; -create public synonym ut_coverage_cobertura_reporter for &&ut3_owner..ut_coverage_cobertura_reporter; -create public synonym ut_reporters for &&ut3_owner..ut_reporters; -create public synonym ut_varchar2_list for &&ut3_owner..ut_varchar2_list; -create public synonym ut_varchar2_rows for &&ut3_owner..ut_varchar2_rows; -create public synonym ut_integer_list for &&ut3_owner..ut_integer_list; -create public synonym ut_reporter_base for &&ut3_owner..ut_reporter_base; -create public synonym ut_output_reporter_base for &&ut3_owner..ut_output_reporter_base; -create public synonym ut_coverage for &&ut3_owner..ut_coverage; -create public synonym ut_coverage_options for &&ut3_owner..ut_coverage_options; -create public synonym ut_coverage_helper for &&ut3_owner..ut_coverage_helper; -create public synonym ut_output_buffer_base for &&ut3_owner..ut_output_buffer_base; -create public synonym ut_output_table_buffer for &&ut3_owner..ut_output_table_buffer; -create public synonym ut_file_mappings for &&ut3_owner..ut_file_mappings; -create public synonym ut_file_mapping for &&ut3_owner..ut_file_mapping; -create public synonym ut_file_mapper for &&ut3_owner..ut_file_mapper; -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; -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'; - execute immediate 'create public synonym dbmspcc_runs for &&ut3_owner..dbmspcc_runs'; - execute immediate 'create public synonym dbmspcc_units for &&ut3_owner..dbmspcc_units'; - $else - null; - $end -end; -/ +@@create_grants.sql '&&ut3_owner' 'PUBLIC' +@@create_synonyms.sql '&&ut3_owner' 'PUBLIC' diff --git a/source/create_user_grants.sql b/source/create_user_grants.sql index bae0364be..83e594884 100644 --- a/source/create_user_grants.sql +++ b/source/create_user_grants.sql @@ -1,6 +1,6 @@ /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -17,106 +17,4 @@ Create all necessary grant for the user who owns test packages and want to execute utPLSQL framework */ -@@define_ut3_owner_param.sql - -column 2 new_value 2 noprint -select null as "2" from dual where 1=0; -spool params.sql.tmp -select - case - when '&&2' is null then q'[ACCEPT ut3_user CHAR PROMPT 'Provide schema to which should be granted the utPLSQL v3 ']' - else 'define ut3_user=&&2' - end -from dual; -spool off -set termout on -@params.sql.tmp -set termout off -/* cleanup temporary sql files */ ---try running on windows -$ del params.sql.tmp ---try running on linux/unix -! rm params.sql.tmp -set termout on - -set echo off -set feedback on -set heading off -set verify off - -prompt Granting privileges on UTPLSQL objects in &&ut3_owner schema to user &&ut3_user - -whenever sqlerror exit failure rollback -whenever oserror exit failure rollback - -alter session set current_schema = &&ut3_owner; - -grant execute on &&ut3_owner..ut_expectation to &ut3_user; -grant execute on &&ut3_owner..ut_expectation_compound to &ut3_user; -grant execute on &&ut3_owner..ut_be_between to &ut3_user; -grant execute on &&ut3_owner..ut_be_empty to &ut3_user; -grant execute on &&ut3_owner..ut_be_false to &ut3_user; -grant execute on &&ut3_owner..ut_be_greater_or_equal to &ut3_user; -grant execute on &&ut3_owner..ut_be_greater_than to &ut3_user; -grant execute on &&ut3_owner..ut_be_less_or_equal to &ut3_user; -grant execute on &&ut3_owner..ut_be_less_than to &ut3_user; -grant execute on &&ut3_owner..ut_be_like to &ut3_user; -grant execute on &&ut3_owner..ut_be_not_null to &ut3_user; -grant execute on &&ut3_owner..ut_be_null to &ut3_user; -grant execute on &&ut3_owner..ut_be_true to &ut3_user; -grant execute on &&ut3_owner..ut_equal to &ut3_user; -grant execute on &&ut3_owner..ut_have_count to &ut3_user; -grant execute on &&ut3_owner..ut_match to &ut3_user; -grant execute on &&ut3_owner..ut to &ut3_user; -grant execute on &&ut3_owner..ut_runner to &ut3_user; -grant execute on &&ut3_owner..ut_teamcity_reporter to &ut3_user; -grant execute on &&ut3_owner..ut_xunit_reporter to &ut3_user; -grant execute on &&ut3_owner..ut_junit_reporter to &ut3_user; -grant execute on &&ut3_owner..ut_tfs_junit_reporter to &ut3_user; -grant execute on &&ut3_owner..ut_documentation_reporter to &ut3_user; -grant execute on &&ut3_owner..ut_coverage_html_reporter to &ut3_user; -grant execute on &&ut3_owner..ut_coverage_sonar_reporter to &ut3_user; -grant execute on &&ut3_owner..ut_coveralls_reporter to &ut3_user; -grant execute on &&ut3_owner..ut_coverage_cobertura_reporter to &ut3_user; -grant execute on &&ut3_owner..ut_reporters to &ut3_user; -grant execute on &&ut3_owner..ut_varchar2_list to &ut3_user; -grant execute on &&ut3_owner..ut_varchar2_rows to &ut3_user; -grant execute on &&ut3_owner..ut_integer_list to &ut3_user; -grant execute on &&ut3_owner..ut_reporter_base to &ut3_user; -grant execute on &&ut3_owner..ut_output_reporter_base to &ut3_user; -grant execute on &&ut3_owner..ut_coverage_reporter_base to &ut3_user; -grant execute on &&ut3_owner..ut_console_reporter_base to &ut3_user; -grant execute on &&ut3_owner..ut_coverage to &ut3_user; -grant execute on &&ut3_owner..ut_coverage_options to &ut3_user; -grant execute on &&ut3_owner..ut_coverage_helper to &ut3_user; -grant execute on &&ut3_owner..ut_output_buffer_base to &ut3_user; -grant execute on &&ut3_owner..ut_output_table_buffer to &ut3_user; -grant execute on &&ut3_owner..ut_file_mappings to &ut3_user; -grant execute on &&ut3_owner..ut_file_mapping to &ut3_user; -grant execute on &&ut3_owner..ut_file_mapper to &ut3_user; -grant execute on &&ut3_owner..ut_key_value_pairs to &ut3_user; -grant execute on &&ut3_owner..ut_key_value_pair to &ut3_user; -grant select, insert, delete on &&ut3_owner..ut_compound_data_tmp to &ut3_user; -grant select, insert, delete on &&ut3_owner..ut_compound_data_diff_tmp to &ut3_user; -grant execute on &&ut3_owner..ut_sonar_test_reporter to &ut3_user; -grant execute on &&ut3_owner..ut_annotations to &ut3_user; -grant execute on &&ut3_owner..ut_annotation to &ut3_user; -grant execute on &&ut3_owner..ut_annotation_manager to &ut3_user; -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_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; -grant execute on &&ut3_owner..ut_annotation_obj_cache_info to &ut3_user; -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 &ut3_user'; - execute immediate 'grant select, insert, delete, update on &&ut3_owner..dbmspcc_runs to &ut3_user'; - execute immediate 'grant select, insert, delete, update on &&ut3_owner..dbmspcc_units to &ut3_user'; - $else - null; - $end -end; -/ +@@create_grants.sql diff --git a/source/create_user_synonyms.sql b/source/create_user_synonyms.sql index 9a087f61a..a1e7a6acc 100644 --- a/source/create_user_synonyms.sql +++ b/source/create_user_synonyms.sql @@ -1,6 +1,6 @@ /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -17,94 +17,4 @@ Create all necessary grant for the user who owns test packages and want to execute utPLSQL framework */ -@@define_ut3_owner_param.sql - -column 2 new_value 2 noprint -select null as "2" from dual where 1=0; -spool params.sql.tmp -select - case - when '&&2' is null then q'[ACCEPT ut3_user CHAR PROMPT 'Provide schema name where synonyms for the utPLSQL v3 should be created ']' - else 'define ut3_user=&&2' - end -from dual; -spool off -set termout on -@params.sql.tmp -set termout off -/* cleanup temporary sql files */ ---try running on windows -$ del params.sql.tmp ---try running on linux/unix -! rm params.sql.tmp -set termout on - -set echo off -set feedback on -set heading off -set verify off - -prompt Granting privileges on UTPLSQL objects in &&ut3_owner schema to user &&ut3_user - -whenever sqlerror exit failure rollback -whenever oserror exit failure rollback - -alter session set current_schema = &&ut3_owner; - -prompt Creating synonyms for UTPLSQL objects in &&ut3_owner schema to user &&ut3_user - -create or replace synonym &ut3_user..ut_expectation for &&ut3_owner..ut_expectation; -create or replace synonym &ut3_user..ut_expectation_compound for &&ut3_owner..ut_expectation_compound; -create or replace synonym &ut3_user..be_between for &&ut3_owner..be_between; -create or replace synonym &ut3_user..be_empty for &&ut3_owner..be_empty; -create or replace synonym &ut3_user..be_false for &&ut3_owner..be_false; -create or replace synonym &ut3_user..be_greater_or_equal for &&ut3_owner..be_greater_or_equal; -create or replace synonym &ut3_user..be_greater_than for &&ut3_owner..be_greater_than; -create or replace synonym &ut3_user..be_less_or_equal for &&ut3_owner..be_less_or_equal; -create or replace synonym &ut3_user..be_less_than for &&ut3_owner..be_less_than; -create or replace synonym &ut3_user..be_like for &&ut3_owner..be_like; -create or replace synonym &ut3_user..be_not_null for &&ut3_owner..be_not_null; -create or replace synonym &ut3_user..be_null for &&ut3_owner..be_null; -create or replace synonym &ut3_user..be_true for &&ut3_owner..be_true; -create or replace synonym &ut3_user..equal for &&ut3_owner..equal; -create or replace synonym &ut3_user..have_count for &&ut3_owner..have_count; -create or replace synonym &ut3_user..match for &&ut3_owner..match; -create or replace synonym &ut3_user..ut for &&ut3_owner..ut; -create or replace synonym &ut3_user..ut_runner for &&ut3_owner..ut_runner; -create or replace synonym &ut3_user..ut_teamcity_reporter for &&ut3_owner..ut_teamcity_reporter; -create or replace synonym &ut3_user..ut_xunit_reporter for &&ut3_owner..ut_xunit_reporter; -create or replace synonym &ut3_user..ut_junit_reporter for &&ut3_owner..ut_junit_reporter; -create or replace synonym &ut3_user..ut_tfs_junit_reporter for &&ut3_owner..ut_tfs_junit_reporter; -create or replace synonym &ut3_user..ut_documentation_reporter for &&ut3_owner..ut_documentation_reporter; -create or replace synonym &ut3_user..ut_coverage_html_reporter for &&ut3_owner..ut_coverage_html_reporter; -create or replace synonym &ut3_user..ut_coverage_sonar_reporter for &&ut3_owner..ut_coverage_sonar_reporter; -create or replace synonym &ut3_user..ut_coveralls_reporter for &&ut3_owner..ut_coveralls_reporter; -create or replace synonym &ut3_user..ut_coverage_cobertura_reporter for &&ut3_owner..ut_coverage_cobertura_reporter; -create or replace synonym &ut3_user..ut_reporters for &&ut3_owner..ut_reporters; -create or replace synonym &ut3_user..ut_varchar2_list for &&ut3_owner..ut_varchar2_list; -create or replace synonym &ut3_user..ut_varchar2_rows for &&ut3_owner..ut_varchar2_rows; -create or replace synonym &ut3_user..ut_integer_list for &&ut3_owner..ut_integer_list; -create or replace synonym &ut3_user..ut_reporter_base for &&ut3_owner..ut_reporter_base; -create or replace synonym &ut3_user..ut_output_reporter_base for &&ut3_owner..ut_output_reporter_base; -create or replace synonym &ut3_user..ut_coverage for &&ut3_owner..ut_coverage; -create or replace synonym &ut3_user..ut_coverage_options for &&ut3_owner..ut_coverage_options; -create or replace synonym &ut3_user..ut_coverage_helper for &&ut3_owner..ut_coverage_helper; -create or replace synonym &ut3_user..ut_output_buffer_base for &&ut3_owner..ut_output_buffer_base; -create or replace synonym &ut3_user..ut_output_table_buffer for &&ut3_owner..ut_output_table_buffer; -create or replace synonym &ut3_user..ut_file_mappings for &&ut3_owner..ut_file_mappings; -create or replace synonym &ut3_user..ut_file_mapping for &&ut3_owner..ut_file_mapping; -create or replace synonym &ut3_user..ut_file_mapper for &&ut3_owner..ut_file_mapper; -create or replace synonym &ut3_user..ut_key_value_pairs for &&ut3_owner..ut_key_value_pairs; -create or replace synonym &ut3_user..ut_key_value_pair for &&ut3_owner..ut_key_value_pair; -create or replace synonym &ut3_user..ut_compound_data_tmp for &&ut3_owner..ut_cursor_data; -create or replace synonym &ut3_user..ut_sonar_test_reporter for &&ut3_owner..ut_sonar_test_reporter; -begin - $if dbms_db_version.version = 12 and dbms_db_version.release >= 2 or dbms_db_version.version > 12 $then - execute immediate 'create or replace synonym &ut3_user..dbmspcc_blocks for &&ut3_owner..dbmspcc_blocks'; - execute immediate 'create or replace synonym &ut3_user..dbmspcc_runs for &&ut3_owner..dbmspcc_runs'; - execute immediate 'create or replace synonym &ut3_user..dbmspcc_units for &&ut3_owner..dbmspcc_units'; - $else - null; - $end -end; -/ +@@create_synonyms.sql diff --git a/source/create_utplsql_owner.sql b/source/create_utplsql_owner.sql index 6bdda5611..d7e4f3040 100644 --- a/source/create_utplsql_owner.sql +++ b/source/create_utplsql_owner.sql @@ -1,6 +1,6 @@ /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -21,19 +21,23 @@ set feedback off set heading off set verify off -define ut3_user = &1 -define ut3_password = &2 -define ut3_tablespace = &3 +define ut3_owner_schema = &1 +define ut3_password = &2 +define ut3_tablespace = &3 -prompt Creating utPLSQL user &&ut3_user +prompt Creating utPLSQL user &&ut3_owner_schema -create user &ut3_user identified by &ut3_password default tablespace &ut3_tablespace quota unlimited on &ut3_tablespace; +create user &ut3_owner_schema identified by "&ut3_password" default tablespace &ut3_tablespace quota unlimited on &ut3_tablespace; -grant create session, create sequence, create procedure, create type, create table, create view, create synonym to &ut3_user; +grant create session, create sequence, create procedure, create type, create table, create view, create synonym to &ut3_owner_schema; -grant execute on dbms_lock to &ut3_user; +grant execute on dbms_lock to &ut3_owner_schema; +grant execute on dbms_crypto to &ut3_owner_schema; +grant execute on dbms_lob to &ut3_owner_schema; +grant execute on dbms_xmlgen to &ut3_owner_schema; +grant execute on dbms_sql to &ut3_owner_schema; +grant execute on dbms_random to &ut3_owner_schema; -grant execute on dbms_crypto to &ut3_user; -grant alter session to &ut3_user; +grant alter session to &ut3_owner_schema; diff --git a/source/define_ut3_owner_param.sql b/source/define_ut3_owner_param.sql index a889ead05..259b49712 100644 --- a/source/define_ut3_owner_param.sql +++ b/source/define_ut3_owner_param.sql @@ -1,6 +1,6 @@ /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/data_values/ut_compound_data_diff_tmp.sql b/source/expectations/data_values/ut_compound_data_diff_tmp.sql index a7959d4aa..c10e8d2e8 100644 --- a/source/expectations/data_values/ut_compound_data_diff_tmp.sql +++ b/source/expectations/data_values/ut_compound_data_diff_tmp.sql @@ -1,7 +1,7 @@ create global temporary table ut_compound_data_diff_tmp( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 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 @@ -12,15 +12,15 @@ create global temporary table ut_compound_data_diff_tmp( See the License for the specific language governing permissions and limitations under the License. */ - diff_id raw(128), - item_no integer, - pk_hash raw(128), - item_hash raw(128), + diff_id raw(128), + act_data_id raw(32), + exp_data_id raw(32), + act_item_data xmltype, + exp_item_data xmltype, + item_no integer, duplicate_no integer, - constraint ut_compound_data_diff_tmp_uk1 unique (diff_id,duplicate_no,item_no,item_hash, pk_hash), + constraint ut_compound_data_diff_tmp_uk1 unique (diff_id,duplicate_no,item_no), constraint ut_compound_data_diff_tmp_chk check( - item_no is not null and pk_hash is null and duplicate_no is null - or item_no is null and item_hash is not null and duplicate_no is not null - or item_no is null and pk_hash is not null and duplicate_no is not null + item_no is not null ) -) on commit preserve rows; +) on commit delete rows; diff --git a/source/expectations/data_values/ut_compound_data_helper.pkb b/source/expectations/data_values/ut_compound_data_helper.pkb index ee01819d6..875ec760a 100644 --- a/source/expectations/data_values/ut_compound_data_helper.pkb +++ b/source/expectations/data_values/ut_compound_data_helper.pkb @@ -1,7 +1,7 @@ create or replace package body ut_compound_data_helper is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -16,526 +16,838 @@ create or replace package body ut_compound_data_helper is limitations under the License. */ - g_user_defined_type pls_integer := dbms_sql.user_defined_type; + g_diff_count integer; + type t_type_name_map is table of varchar2(128) index by binary_integer; + type t_types_no_length is table of varchar2(128) index by varchar2(128); + g_type_name_map t_type_name_map; + g_anytype_name_map t_type_name_map; + g_type_no_length_map t_types_no_length; + + g_compare_sql_template varchar2(4000) := + q'[ + with exp as ( + select + ucd.*, + {:duplicate_number:} "UT3$_Dup#No" + from ( + select + ucd."UT3$_Item#Data" + ,x.data_id "UT3$_Data#Id" + ,ucd."UT3$_Position#" + x.item_no "UT3$_Item#No" + {:columns:} + from ut_compound_data_tmp x, + xmltable('/ROWSET/ROW' passing x.item_data columns + "UT3$_Item#Data" xmltype path '*' + ,"UT3$_Position#" for ordinality + {:xml_to_columns:} ) ucd + where x.data_id = :exp_guid + ) ucd + ) + , act as ( + select + ucd.*, + {:duplicate_number:} "UT3$_Dup#No" + from ( + select + ucd."UT3$_Item#Data" + ,x.data_id "UT3$_Data#Id" + ,ucd."UT3$_Position#" + x.item_no "UT3$_Item#No" + {:columns:} + from ut_compound_data_tmp x, + xmltable('/ROWSET/ROW' passing x.item_data columns + "UT3$_Item#Data" xmltype path '*' + ,"UT3$_Position#" for ordinality + {:xml_to_columns:} ) ucd + where x.data_id = :act_guid + ) ucd + ) + select /*+ no_parallel */ + a."UT3$_Item#Data" as act_item_data, + a."UT3$_Data#Id" act_data_id, + e."UT3$_Item#Data" as exp_item_data, + e."UT3$_Data#Id" exp_data_id, + {:item_no:} as item_no, + nvl(e."UT3$_Dup#No",a."UT3$_Dup#No") dup_no + from act a {:join_type:} exp e on ( {:join_condition:} ) + where {:where_condition:}]'; + + function get_columns_diff( + a_expected ut_cursor_column_tab, + a_actual ut_cursor_column_tab, + a_order_enforced boolean := false + ) return tt_column_diffs is + l_results tt_column_diffs; + begin + execute immediate q'[with + expected_cols as ( + select display_path exp_column_name,column_position exp_col_pos, + replace(column_type_name,'VARCHAR2','CHAR') exp_col_type_compare, column_type_name exp_col_type + from table(:a_expected) + where parent_name is null and hierarchy_level = 1 and column_name is not null + ), + actual_cols as ( + select display_path act_column_name,column_position act_col_pos, + replace(column_type_name,'VARCHAR2','CHAR') act_col_type_compare, column_type_name act_col_type + from table(:a_actual) + where parent_name is null and hierarchy_level = 1 and column_name is not null + ), + joined_cols as ( + select e.*,a.*]' + || case when a_order_enforced then ', + row_number() over(partition by case when a.act_col_pos + e.exp_col_pos is not null then 1 end order by a.act_col_pos) a_pos_nn, + row_number() over(partition by case when a.act_col_pos + e.exp_col_pos is not null then 1 end order by e.exp_col_pos) e_pos_nn' + else + null + end ||q'[ + from expected_cols e + full outer join actual_cols a + on e.exp_column_name = a.act_column_name + ) + select /*+ no_parallel */ case + when exp_col_pos is null and act_col_pos is not null then '+' + when exp_col_pos is not null and act_col_pos is null then '-' + when exp_col_type_compare != act_col_type_compare then 't' + else 'p' + end as diff_type, + exp_column_name, exp_col_type, exp_col_pos, + act_column_name, act_col_type, act_col_pos + from joined_cols + --column is unexpected (extra) or missing + where act_col_pos is null or exp_col_pos is null + --column type is not matching (except CHAR/VARCHAR2) + or act_col_type_compare != exp_col_type_compare]' + || case when a_order_enforced then q'[ + --column position is not matching (both when excluded extra/missing columns as well as when they are included) + or (a_pos_nn != e_pos_nn and exp_col_pos != act_col_pos)]' + end ||q'[ + order by exp_col_pos, act_col_pos]' + bulk collect into l_results using a_expected, a_actual; + return l_results; + end; + + function generate_not_equal_stmt( + a_data_info ut_cursor_column, a_pk_table ut_varchar2_list + ) return varchar2 + is + l_pk_tab ut_varchar2_list := coalesce(a_pk_table,ut_varchar2_list()); + l_index integer; + l_sql_stmt varchar2(32767); + l_exists boolean := false; + begin + l_index := l_pk_tab.first; + if l_pk_tab.count > 0 then + loop + if a_data_info.access_path = l_pk_tab(l_index) then + l_exists := true; + end if; + exit when l_index = l_pk_tab.count or (a_data_info.access_path = l_pk_tab(l_index)); + l_index := a_pk_table.next(l_index); + end loop; + end if; + if not(l_exists) then + l_sql_stmt := ' (decode(a.'||a_data_info.transformed_name||','||' e.'||a_data_info.transformed_name||',1,0) = 0)'; + end if; + return l_sql_stmt; + end; + + function generate_join_by_stmt( + a_data_info ut_cursor_column, a_pk_table ut_varchar2_list + ) return varchar2 + is + l_pk_tab ut_varchar2_list := coalesce(a_pk_table,ut_varchar2_list()); + l_index integer; + l_sql_stmt varchar2(32767); + begin + if l_pk_tab.count <> 0 then + l_index:= l_pk_tab.first; + loop + if l_pk_tab(l_index) in (a_data_info.access_path, a_data_info.parent_name) then + --When then table is nested and join is on whole table + l_sql_stmt := l_sql_stmt ||' a.'||a_data_info.transformed_name||q'[ = ]'||' e.'||a_data_info.transformed_name; + end if; + exit when (a_data_info.access_path = l_pk_tab(l_index)) or l_index = l_pk_tab.count; + l_index := l_pk_tab.next(l_index); + end loop; + end if; + return l_sql_stmt; + end; - function get_column_info_xml(a_column_details ut_key_anyval_pair) return xmltype is - l_result varchar2(4000); - l_res xmltype; - l_data ut_data_value := a_column_details.value; - l_key varchar2(4000) := ut_utils.xmlgen_escaped_string(a_column_details.KEY); + function generate_equal_sql(a_col_name in varchar2) return varchar2 is begin - l_result := '<'||l_key||' xml_valid_name="'||l_key||'">'; - if l_data is of(ut_data_value_xmltype) then - l_result := l_result || (treat(l_data as ut_data_value_xmltype).to_string); + return ' decode(a.'||a_col_name||','||' e.'||a_col_name||',1,0) = 1 '; + end; + + function generate_partition_stmt( + a_data_info ut_cursor_column, a_pk_table in ut_varchar2_list, a_alias varchar2 := 'ucd.' + ) return varchar2 + is + l_index integer; + l_sql_stmt varchar2(32767); + begin + if a_pk_table is not empty then + l_index:= a_pk_table.first; + loop + if a_pk_table(l_index) in (a_data_info.access_path, a_data_info.parent_name) then + --When then table is nested and join is on whole table + l_sql_stmt := l_sql_stmt ||a_alias||a_data_info.transformed_name; + end if; + exit when (a_data_info.access_path = a_pk_table(l_index)) or l_index = a_pk_table.count; + l_index := a_pk_table.next(l_index); + end loop; else - l_result := l_result || ut_utils.xmlgen_escaped_string((treat(l_data as ut_data_value_varchar2).data_value)); + l_sql_stmt := a_alias||a_data_info.transformed_name; end if; - - l_result := l_result ||''; - return xmltype(l_result); - end; + return l_sql_stmt; + end; - function get_columns_filter( - a_exclude_xpath varchar2, a_include_xpath varchar2, - a_table_alias varchar2 := 'ucd', a_column_alias varchar2 := 'item_data' - ) return varchar2 is - l_filter varchar2(32767); - l_source_column varchar2(500) := a_table_alias||'.'||a_column_alias; + function generate_select_stmt(a_data_info ut_cursor_column, a_alias varchar2 := 'ucd.') + return varchar2 + is + l_alias varchar2(10) := a_alias; + l_col_syntax varchar2(4000); + begin + if a_data_info.is_sql_diffable = 0 then + l_col_syntax := 'ut_utils.get_hash('||l_alias||a_data_info.transformed_name||'.getClobVal()) as '||a_data_info.transformed_name ; + elsif a_data_info.is_sql_diffable = 1 and a_data_info.column_type = 'DATE' then + l_col_syntax := 'to_date('||l_alias||a_data_info.transformed_name||') as '|| a_data_info.transformed_name; + elsif a_data_info.is_sql_diffable = 1 and a_data_info.column_type in ('TIMESTAMP') then + l_col_syntax := 'to_timestamp('||l_alias||a_data_info.transformed_name||','''||ut_utils.gc_timestamp_format||''') as '|| a_data_info.transformed_name; + elsif a_data_info.is_sql_diffable = 1 and a_data_info.column_type in ('TIMESTAMP WITH TIME ZONE') then + l_col_syntax := 'to_timestamp_tz('||l_alias||a_data_info.transformed_name||','''||ut_utils.gc_timestamp_tz_format||''') as '|| a_data_info.transformed_name; + elsif a_data_info.is_sql_diffable = 1 and a_data_info.column_type in ('TIMESTAMP WITH LOCAL TIME ZONE') then + l_col_syntax := ' cast( to_timestamp_tz('||l_alias||a_data_info.transformed_name||','''||ut_utils.gc_timestamp_tz_format||''') AS TIMESTAMP WITH LOCAL TIME ZONE) as '|| a_data_info.transformed_name; + else + l_col_syntax := l_alias||a_data_info.transformed_name||' as '|| a_data_info.transformed_name; + end if; + return l_col_syntax; + end; + + function generate_xmltab_stmt(a_data_info ut_cursor_column) return varchar2 is + l_col_type varchar2(4000); begin - -- this SQL statement is constructed in a way that we always get the same number and ordering of substitution variables - -- That is, we always get: l_exclude_xpath, l_include_xpath - -- regardless if the variables are NULL (not to be used) or NOT NULL and will be used for filtering - if a_exclude_xpath is null and a_include_xpath is null then - l_filter := ':l_exclude_xpath, :l_include_xpath, '||l_source_column||' as '||a_column_alias; - elsif a_exclude_xpath is not null and a_include_xpath is null then - l_filter := 'deletexml( '||l_source_column||', :l_exclude_xpath ) as '||a_column_alias||', :l_include_xpath'; - elsif a_exclude_xpath is null and a_include_xpath is not null then - l_filter := ':l_exclude_xpath, extract( '||l_source_column||', :l_include_xpath ) as '||a_column_alias; - elsif a_exclude_xpath is not null and a_include_xpath is not null then - l_filter := 'extract( deletexml( '||l_source_column||', :l_exclude_xpath ), :l_include_xpath ) as '||a_column_alias; + if a_data_info.is_sql_diffable = 0 then + l_col_type := 'XMLTYPE'; + elsif a_data_info.is_sql_diffable = 1 and a_data_info.column_type in ('DATE','TIMESTAMP','TIMESTAMP WITH TIME ZONE', + 'TIMESTAMP WITH LOCAL TIME ZONE') then + l_col_type := 'VARCHAR2(50)'; + elsif a_data_info.is_sql_diffable = 1 and type_no_length(a_data_info.column_type) then + l_col_type := a_data_info.column_type; + elsif a_data_info.is_sql_diffable = 1 and a_data_info.column_type in ('VARCHAR2','CHAR') then + l_col_type := 'VARCHAR2('||greatest(a_data_info.column_len,4000)||')'; + elsif a_data_info.is_sql_diffable = 1 and a_data_info.column_type in ('NUMBER') then + --We cannot use a precision and scale as dbms_sql.describe_columns3 return precision 0 for dual table + -- there is also no need for that as we not process data but only read and compare as they are stored + l_col_type := a_data_info.column_type; + else + l_col_type := a_data_info.column_type + ||case when a_data_info.column_len is not null + then '('||a_data_info.column_len||')' + else null + end; end if; - return l_filter; + return a_data_info.transformed_name||' '||l_col_type||q'[ PATH ']'||a_data_info.access_path||q'[']'; end; - - /** - * Current get column filter shaving off ROW tag during extract, this not working well with include and XMLTABLE option - * so when there is extract we artificially inject removed tag - **/ - function get_columns_row_filter( - a_exclude_xpath varchar2, a_include_xpath varchar2, - a_table_alias varchar2 := 'ucd', a_column_alias varchar2 := 'item_data' - ) return varchar2 is - l_filter varchar2(32767); - l_source_column varchar2(500) := a_table_alias||'.'||a_column_alias; + + procedure gen_sql_pieces_out_of_cursor( + a_data_info ut_cursor_column_tab, + a_pk_table ut_varchar2_list, + a_unordered boolean, + a_xml_stmt out nocopy clob, + a_select_stmt out nocopy clob, + a_partition_stmt out nocopy clob, + a_join_by_stmt out nocopy clob, + a_not_equal_stmt out nocopy clob + ) is + l_partition_tmp clob; + l_xmltab_list ut_varchar2_list := ut_varchar2_list(); + l_select_list ut_varchar2_list := ut_varchar2_list(); + l_partition_list ut_varchar2_list := ut_varchar2_list(); + l_equal_list ut_varchar2_list := ut_varchar2_list(); + l_join_by_list ut_varchar2_list := ut_varchar2_list(); + l_not_equal_list ut_varchar2_list := ut_varchar2_list(); + + procedure add_element_to_list(a_list in out ut_varchar2_list, a_list_element in varchar2) + is + begin + if a_list_element is not null then + a_list.extend; + a_list(a_list.last) := a_list_element; + end if; + end; + begin - -- this SQL statement is constructed in a way that we always get the same number and ordering of substitution variables - -- That is, we always get: l_exclude_xpath, l_include_xpath - -- regardless if the variables are NULL (not to be used) or NOT NULL and will be used for filtering - if a_exclude_xpath is null and a_include_xpath is null then - l_filter := ':l_exclude_xpath, :l_include_xpath, '||l_source_column||' as '||a_column_alias; - elsif a_exclude_xpath is not null and a_include_xpath is null then - l_filter := 'deletexml( '||l_source_column||', :l_exclude_xpath ) as '||a_column_alias||', :l_include_xpath'; - elsif a_exclude_xpath is null and a_include_xpath is not null then - l_filter := ':l_exclude_xpath, xmlelement("ROW",extract( '||l_source_column||', :l_include_xpath )) as '||a_column_alias; - elsif a_exclude_xpath is not null and a_include_xpath is not null then - l_filter := 'xmlelement("ROW",extract( deletexml( '||l_source_column||', :l_exclude_xpath ), :l_include_xpath )) as '||a_column_alias; + if a_data_info is not empty then + for i in 1..a_data_info.count loop + if a_data_info(i).has_nested_col = 0 and a_data_info(i).column_type <> 'OBJECT' then + --Get XMLTABLE column list + add_element_to_list(l_xmltab_list,generate_xmltab_stmt(a_data_info(i))); + --Get Select statment list of columns + add_element_to_list(l_select_list, generate_select_stmt(a_data_info(i))); + --Get columns by which we partition + add_element_to_list(l_partition_list,generate_partition_stmt(a_data_info(i), a_pk_table)); + --Get equal statement + add_element_to_list(l_equal_list,generate_equal_sql(a_data_info(i).transformed_name)); + --Generate join by stmt + add_element_to_list(l_join_by_list,generate_join_by_stmt(a_data_info(i), a_pk_table)); + --Generate not equal stmt + add_element_to_list(l_not_equal_list,generate_not_equal_stmt(a_data_info(i), a_pk_table)); + end if; + end loop; + + a_xml_stmt := nullif(','||ut_utils.table_to_clob(l_xmltab_list, ' , '),','); + a_select_stmt := nullif(','||ut_utils.table_to_clob(l_select_list, ' , '),','); + l_partition_tmp := ut_utils.table_to_clob(l_partition_list, ' , '); + ut_utils.append_to_clob(a_partition_stmt,' row_number() over (partition by '||l_partition_tmp||' order by '||l_partition_tmp||' ) '); + + if a_pk_table.count > 0 then + -- If key defined do the join or these and where on diffrences as well as on duplicate number when rows are same. + a_join_by_stmt := ' e."UT3$_Dup#No" = a."UT3$_Dup#No" and '||ut_utils.table_to_clob(l_join_by_list, ' and '); + elsif a_unordered then + -- If no key defined do the join on all columns + a_join_by_stmt := ' e."UT3$_Dup#No" = a."UT3$_Dup#No" and '||ut_utils.table_to_clob(l_equal_list, ' and '); + else + -- Else join on rownumber + a_join_by_stmt := 'a."UT3$_Item#No" = e."UT3$_Item#No" '; + end if; + a_not_equal_stmt := ut_utils.table_to_clob(l_not_equal_list, ' or '); + else + --Partition by piece when no data + ut_utils.append_to_clob(a_partition_stmt,' 1 '); + a_join_by_stmt := 'a."UT3$_Item#No" = e."UT3$_Item#No" '; end if; - return l_filter; end; + + function gen_compare_sql( + a_other ut_data_value_refcursor, + a_join_by_list ut_varchar2_list, + a_unordered boolean, + a_inclusion_type boolean, + a_is_negated boolean + ) return clob is + l_compare_sql clob; + l_xmltable_stmt clob; + l_select_stmt clob; + l_partition_stmt clob; + l_join_on_stmt clob; + l_not_equal_stmt clob; + l_where_stmt clob; + l_join_by_list ut_varchar2_list; + + function get_join_type(a_inclusion_compare in boolean,a_negated in boolean) return varchar2 is + begin + return + case + when a_inclusion_compare and not(a_negated) then ' right outer join ' + when a_inclusion_compare and a_negated then ' inner join ' + else ' full outer join ' + end; + end; + + function get_item_no(a_unordered boolean) return varchar2 is + begin + return + case + when a_unordered then 'row_number() over ( order by nvl(e."UT3$_Item#No",a."UT3$_Item#No"))' + else 'nvl(e."UT3$_Item#No",a."UT3$_Item#No") ' + end; + end; - function get_columns_diff( - a_expected xmltype, a_actual xmltype, a_exclude_xpath varchar2, a_include_xpath varchar2 - ) return tt_column_diffs is - l_column_filter varchar2(32767); - l_sql varchar2(32767); - l_results tt_column_diffs; begin - l_column_filter := get_columns_row_filter(a_exclude_xpath, a_include_xpath); - l_sql := q'[ - with - expected_cols as ( select :a_expected as item_data from dual ), - actual_cols as ( select :a_actual as item_data from dual ), - expected_cols_info as ( - select e.*, - replace(expected_type,'VARCHAR2','CHAR') expected_type_compare - from ( - SELECT rownum expected_pos, - xt.name expected_name, - xt.type expected_type - FROM (select ]'||l_column_filter||q'[ from expected_cols ucd) x, - XMLTABLE('/ROW/*' - PASSING x.item_data - COLUMNS - name VARCHAR2(4000) PATH '@xml_valid_name', - type VARCHAR2(4000) PATH '/' - ) xt - ) e - ), - actual_cols_info as ( - select a.*, - replace(actual_type,'VARCHAR2','CHAR') actual_type_compare - from ( - SELECT rownum actual_pos, - xt.name actual_name, - xt.type actual_type - FROM (select ]'||l_column_filter||q'[ from actual_cols ucd) x, - XMLTABLE('/ROW/*' - PASSING x.item_data - COLUMNS - name VARCHAR2(4000) PATH '@xml_valid_name', - type VARCHAR2(4000) PATH '/' - ) xt - ) a - ), - joined_cols as ( - select e.*, a.*, - row_number() over(partition by case when actual_pos + expected_pos is not null then 1 end order by actual_pos) a_pos_nn, - row_number() over(partition by case when actual_pos + expected_pos is not null then 1 end order by expected_pos) e_pos_nn - from expected_cols_info e - full outer join actual_cols_info a on e.expected_name = a.actual_name - ) - select case - when expected_pos is null and actual_pos is not null then '+' - when expected_pos is not null and actual_pos is null then '-' - when expected_type_compare != actual_type_compare then 't' - else 'p' - end as diff_type, - expected_name, expected_type, expected_pos, - actual_name, actual_type, actual_pos - from joined_cols - --column is unexpected (extra) or missing - where actual_pos is null or expected_pos is null - --column type is not matching (except CHAR/VARCHAR2) - or actual_type_compare != expected_type_compare - --column position is not matching (both when excluded extra/missing columns as well as when they are included) - or (a_pos_nn != e_pos_nn and expected_pos != actual_pos) - order by expected_pos, actual_pos]'; - execute immediate l_sql - bulk collect into l_results - using a_expected, a_actual, a_exclude_xpath, a_include_xpath, a_exclude_xpath, a_include_xpath; + /** + * We already estabilished cursor equality so now we add anydata root if we compare anydata + * to join by. + */ + l_join_by_list := + case + when a_other is of (ut_data_value_anydata) then ut_utils.add_prefix(a_join_by_list, a_other.cursor_details.get_root) + else a_join_by_list + end; + + dbms_lob.createtemporary(l_compare_sql, true); + --Initiate a SQL template with placeholders + ut_utils.append_to_clob(l_compare_sql, g_compare_sql_template); + --Generate a pieceso of dynamic SQL that will substitute placeholders + gen_sql_pieces_out_of_cursor( + a_other.cursor_details.cursor_columns_info, l_join_by_list, a_unordered, + l_xmltable_stmt, l_select_stmt, l_partition_stmt, l_join_on_stmt, + l_not_equal_stmt + ); + + l_compare_sql := replace(l_compare_sql,'{:duplicate_number:}',l_partition_stmt); + l_compare_sql := replace(l_compare_sql,'{:columns:}',l_select_stmt); + l_compare_sql := replace(l_compare_sql,'{:xml_to_columns:}',l_xmltable_stmt); + l_compare_sql := replace(l_compare_sql,'{:item_no:}',get_item_no(a_unordered)); + l_compare_sql := replace(l_compare_sql,'{:join_type:}',get_join_type(a_inclusion_type,a_is_negated)); + l_compare_sql := replace(l_compare_sql,'{:join_condition:}',l_join_on_stmt); - return l_results; + if l_not_equal_stmt is not null and ((l_join_by_list.count > 0 and not a_is_negated) or (not a_unordered)) then + ut_utils.append_to_clob(l_where_stmt,' ( '||l_not_equal_stmt||' ) or '); + end if; + --If its inclusion we expect a actual set to fully match and have no extra elements over expected + if a_inclusion_type then + ut_utils.append_to_clob(l_where_stmt,case when a_is_negated then ' 1 = 1 ' else ' ( a."UT3$_Data#Id" is null ) ' end); + else + ut_utils.append_to_clob(l_where_stmt,' (a."UT3$_Data#Id" is null or e."UT3$_Data#Id" is null) '); + end if; + + l_compare_sql := replace(l_compare_sql,'{:where_condition:}',l_where_stmt); + return l_compare_sql; end; - - function get_pk_value (a_join_by_xpath varchar2,a_item_data xmltype) return clob is - l_pk_value clob; + + function get_column_extract_path(a_cursor_info ut_cursor_column_tab) return ut_varchar2_list is + l_column_list ut_varchar2_list := ut_varchar2_list(); begin - select replace((extract(a_item_data,a_join_by_xpath).getclobval()),chr(10)) into l_pk_value from dual; - return l_pk_value; + for i in 1..a_cursor_info.count loop + --This avoids extracting single columns from nested objects. + --as we can go down to any level but we will lose visibility of parent. + if a_cursor_info(i).hierarchy_level = 1 then + l_column_list.extend; + l_column_list(l_column_list.last) := a_cursor_info(i).access_path; + end if; + end loop; + return l_column_list; end; - - function get_rows_diff( + + function get_rows_diff_by_sql( + a_act_cursor_info ut_cursor_column_tab, a_exp_cursor_info ut_cursor_column_tab, a_expected_dataset_guid raw, a_actual_dataset_guid raw, a_diff_id raw, - a_max_rows integer, a_exclude_xpath varchar2, a_include_xpath varchar2, - a_join_by_xpath varchar2 + a_join_by_list ut_varchar2_list, a_unordered boolean, a_enforce_column_order boolean := false, + a_extract_path varchar2 ) return tt_row_diffs is - l_column_filter varchar2(32767); - l_results tt_row_diffs; + l_act_extract_xpath varchar2(32767):= ut_utils.to_xpath(get_column_extract_path(a_act_cursor_info)); + l_exp_extract_xpath varchar2(32767):= ut_utils.to_xpath(get_column_extract_path(a_exp_cursor_info)); + l_join_xpath varchar2(32767) := ut_utils.to_xpath(a_join_by_list); + l_results tt_row_diffs; + l_sql varchar2(32767); + l_column_order varchar2(100); begin - l_column_filter := get_columns_row_filter(a_exclude_xpath,a_include_xpath); - - /** - * Since its unordered search we cannot select max rows from diffs as we miss some comparision records - * We will restrict output on higher level of select - * NO_MERGE hint was introduced to prevent optimizer from merging views and rewriting query which in some cases - * lead to second value being null depend on execution plan that been chosen - **/ - execute immediate q'[ - with diff_info as (select item_hash,pk_hash,duplicate_no from ut_compound_data_diff_tmp ucdc where diff_id = :diff_guid) - select rn,diff_type,diffed_row,pk_value from - ( - select - diff_type, diffed_row, - dense_rank() over (order by case when diff_type in ('Extra','Missing') then diff_type end, - case when diff_type in ('Actual','Expected') then pk_hash end, - case when diff_type in ('Extra','Missing') then pk_hash end, - case when diff_type in ('Actual','Expected') then diff_type end) rn, - pk_value, pk_hash - from - ( - select diff_type,diffed_row,pk_hash,pk_value from - (select diff_type,data_item diffed_row,pk_hash,pk_value - from - (select /*+NO_MERGE*/ nvl(exp.pk_hash, act.pk_hash) pk_hash,nvl(exp.pk_value, act.pk_value) pk_value, - xmlserialize(content exp.row_data no indent) exp_item, - xmlserialize(content act.row_data no indent) act_item - from - (select ucd.* - from - (select ucd.column_value row_data, - r.item_hash row_hash, - r.pk_hash , - r.duplicate_no, - ucd.column_value.getclobval() col_val, - ucd.column_value.getRootElement() col_name, - ut_compound_data_helper.get_pk_value(:join_xpath,r.item_data) pk_value - from - (select ]'||l_column_filter||q'[, ucd.item_no, ucd.item_hash, i.pk_hash, i.duplicate_no - from ut_compound_data_tmp ucd, - diff_info i - where ucd.data_id = :self_guid - and ucd.item_hash = i.item_hash - ) r, - table( xmlsequence( extract(r.item_data,'/*/*') ) ) ucd - ) ucd - ) exp - join ( - select ucd.* - from - (select ucd.column_value row_data, - r.item_hash row_hash, - r.pk_hash , - r.duplicate_no, - ucd.column_value.getclobval() col_val, - ucd.column_value.getRootElement() col_name, - ut_compound_data_helper.get_pk_value(:join_xpath,r.item_data) pk_value - from - (select ]'||l_column_filter||q'[, ucd.item_no, ucd.item_hash, i.pk_hash, i.duplicate_no - from ut_compound_data_tmp ucd, - diff_info i - where ucd.data_id = :other_guid - and ucd.item_hash = i.item_hash - ) r, - table( xmlsequence( extract(r.item_data,'/*/*') ) ) ucd - ) ucd - ) act - on exp.pk_hash = act.pk_hash and exp.col_name = act.col_name - and exp.duplicate_no = act.duplicate_no - where dbms_lob.compare(exp.col_val, act.col_val) != 0 - ) - unpivot ( data_item for diff_type in (exp_item as 'Expected:', act_item as 'Actual:') ) - ) - union all - select case when exp.pk_hash is null then 'Extra' else 'Missing' end as diff_type, - xmlserialize(content nvl(exp.item_data, act.item_data) no indent) diffed_row, - coalesce(exp.pk_hash,act.pk_hash) pk_hash, - coalesce(exp.pk_value,act.pk_value) pk_value - from (select extract(deletexml(ucd.item_data, :join_by),'/*/*') item_data,i.pk_hash, - ut_compound_data_helper.get_pk_value(:join_by,item_data) pk_value - from ut_compound_data_tmp ucd, - diff_info i - where ucd.data_id = :self_guid - and ucd.item_hash = i.item_hash - ) exp - full outer join ( - select extract(deletexml(ucd.item_data, :join_by),'/*/*') item_data,i.pk_hash, - ut_compound_data_helper.get_pk_value(:join_by,item_data) pk_value - from ut_compound_data_tmp ucd, - diff_info i - where ucd.data_id = :other_guid - and ucd.item_hash = i.item_hash - )act - on exp.pk_hash = act.pk_hash - where exp.pk_hash is null or act.pk_hash is null - ) - ) where rn <= :max_rows - order by rn, pk_hash, diff_type - ]' - bulk collect into l_results - using a_diff_id, - a_join_by_xpath, - a_exclude_xpath, a_include_xpath, a_expected_dataset_guid, - a_join_by_xpath, - a_exclude_xpath, a_include_xpath, a_actual_dataset_guid, - a_join_by_xpath,a_join_by_xpath,a_expected_dataset_guid,a_join_by_xpath,a_join_by_xpath, a_actual_dataset_guid, - a_max_rows; - + if a_enforce_column_order then + l_column_order := 'col_no'; + else + l_column_order := 'col_name'; + end if; + l_sql := q'[ + with + exp_cols as ( + select + i.exp_item_data, i.exp_data_id, i.item_no rn, rownum col_no, i.diff_id, + s.column_value col, s.column_value.getRootElement() col_name, + nvl( s.column_value.getclobval(), empty_clob() ) col_val + from ( + select + ucd.exp_data_id, extract( ucd.exp_item_data, :column_path ) exp_item_data, + ucd.item_no, ucd.diff_id + from ut_compound_data_diff_tmp ucd + where ucd.diff_id = :diff_id + and ucd.exp_data_id = :self_guid + ) i, + table( xmlsequence( extract( i.exp_item_data, :extract_path ) ) ) s + ), + act_cols as ( + select + i.act_item_data, i.act_data_id, i.item_no rn, rownum col_no, i.diff_id, + s.column_value col, s.column_value.getRootElement() col_name, + nvl( s.column_value.getclobval(), empty_clob() ) col_val + from ( + select + ucd.act_data_id, extract( ucd.act_item_data, :column_path ) act_item_data, + ucd.item_no, ucd.diff_id + from ut_compound_data_diff_tmp ucd + where ucd.diff_id = :diff_id + and ucd.act_data_id = :other_guid + ) i, + table( xmlsequence( extract( i.act_item_data, :extract_path ) ) ) s + ), + data_diff as ( + select rn, diff_type, xmlserialize(content data_item no indent) diffed_row, null pk_value, col_name, diff_id + from ( + select nvl(exp.rn, act.rn) rn, + exp.diff_id diff_id, + xmlagg(exp.col order by exp.col_no) exp_item, + xmlagg(act.col order by nvl(exp.col_no, act.col_no)) act_item, + max(nvl(exp.col_name,act.col_name)) col_name + from exp_cols exp + join act_cols act + on exp.rn = act.rn and exp.col_name = act.col_name + where dbms_lob.compare(exp.col_val, act.col_val) != 0 + group by nvl(exp.rn, act.rn), exp.diff_id + ) + unpivot ( data_item for diff_type in (exp_item as 'Expected:', act_item as 'Actual:') ) + ), + unordered_diff as ( + select rn, diff_type, xmlserialize(content data_item no indent) diffed_row, null pk_value, col_name, diff_id + from ( + select nvl(exp.rn, act.rn) rn, + exp.diff_id diff_id, + xmlagg(exp.col order by exp.col_name) exp_item, + xmlagg(act.col order by act.col_name) act_item, + max(nvl(exp.col_name,act.col_name)) col_name + from exp_cols exp + join act_cols act + on exp.rn = act.rn and exp.col_name = act.col_name + where dbms_lob.compare(exp.col_val, act.col_val) != 0 + group by nvl(exp.rn, act.rn), exp.diff_id + ) + unpivot ( data_item for diff_type in (exp_item as 'Expected:', act_item as 'Actual:') ) + ) + select /*+ no_parallel */ rn, diff_type, diffed_row, pk_value + from ( + select rn, diff_type, diffed_row, pk_value, + case when diff_type = 'Actual:' then 1 else 2 end rnk, + 1 final_order, + col_name + from ( ]' + || case when a_unordered then q'[ + select /*+ no_unnest */ + u.rn, u.diff_type, u.diffed_row, + replace( + extract( case when i.exp_data_id is null then i.act_item_data else i.exp_item_data end, :join_by ).getclobval(), + chr(10) + ) pk_value, + u.col_name + from data_diff u + join ut_compound_data_diff_tmp i + on i.diff_id = u.diff_id + and i.item_no = u.rn]' + else q'[ + select rn, diff_type, diffed_row, pk_value, col_name + from data_diff + where :join_by is null ]' + end ||q'[ + ) + union all + select + item_no as rn, + case when exp_data_id is null then 'Extra:' else 'Missing:' end as diff_type, + xmlserialize( + content ( + extract( (case when exp_data_id is null then act_item_data else exp_item_data end),'/*/*') + ) no indent + ) diffed_row, + nvl2( + :join_by, + replace( + extract( case when exp_data_id is null then act_item_data else exp_item_data end, :join_by ).getclobval(), + chr(10) + ), + null + ) pk_value, + case when exp_data_id is null then 1 else 2 end rnk, + 2 final_order, + null col_name + from ut_compound_data_diff_tmp i + where diff_id = :diff_id + and act_data_id is null or exp_data_id is null + ) + order by final_order,]' + ||case when a_enforce_column_order or (not(a_enforce_column_order) and not(a_unordered)) then + q'[ + case when final_order = 1 then rn else rnk end, + case when final_order = 1 then rnk else rn end + ]' + when a_unordered then + q'[ + case when final_order = 1 then col_name else to_char(rnk) end, + case when final_order = 1 then to_char(rn) else col_name end, + case when final_order = 1 then to_char(rnk) else col_name end + ]' + end; + execute immediate l_sql + bulk collect into l_results + using l_exp_extract_xpath, a_diff_id, a_expected_dataset_guid, a_extract_path, + l_act_extract_xpath, a_diff_id, a_actual_dataset_guid, a_extract_path, + l_join_xpath, l_join_xpath, l_join_xpath, a_diff_id; return l_results; end; - - function get_rows_diff( - a_expected_dataset_guid raw, a_actual_dataset_guid raw, a_diff_id raw, - a_max_rows integer, a_exclude_xpath varchar2, a_include_xpath varchar2 - ) return tt_row_diffs is - l_column_filter varchar2(32767); - l_results tt_row_diffs; + + function get_fixed_size_hash(a_string varchar2, a_base integer :=0,a_size integer := 9999999) return number is begin - l_column_filter := get_columns_filter(a_exclude_xpath,a_include_xpath); - execute immediate q'[ - with - diff_info as ( select item_no - from - (select item_no from ut_compound_data_diff_tmp ucdc where diff_id = :diff_guid order by item_no asc) - where rownum <= :max_rows) - select * - from (select rn, diff_type, xmlserialize(content data_item no indent) diffed_row, null pk_value - from (select nvl(exp.rn, act.rn) rn, - xmlagg(exp.col order by exp.col_no) exp_item, - xmlagg(act.col order by act.col_no) act_item - from (select r.item_no as rn, rownum col_no, s.column_value col, - s.column_value.getRootElement() col_name, - s.column_value.getclobval() col_val - from (select ]'||l_column_filter||q'[, ucd.item_no, ucd.item_data item_data_no_filter - from ut_compound_data_tmp ucd, - diff_info i - where ucd.data_id = :self_guid - and ucd.item_no = i.item_no - ) r, - table( xmlsequence( extract(r.item_data,'/*/*') ) ) s - ) exp - join ( - select item_no as rn, rownum col_no, s.column_value col, - s.column_value.getRootElement() col_name, - s.column_value.getclobval() col_val - from (select ]'||l_column_filter||q'[, ucd.item_no, ucd.item_data item_data_no_filter - from ut_compound_data_tmp ucd, - diff_info i - where ucd.data_id = :other_guid - and ucd.item_no = i.item_no - ) r, - table( xmlsequence( extract(r.item_data,'/*/*') ) ) s - ) act - on exp.rn = act.rn and exp.col_name = act.col_name - where dbms_lob.compare(exp.col_val, act.col_val) != 0 - group by exp.rn, act.rn - ) - unpivot ( data_item for diff_type in (exp_item as 'Expected:', act_item as 'Actual:') ) - ) - union all - select nvl(exp.item_no, act.item_no) rn, - case when exp.item_no is null then 'Extra:' else 'Missing:' end as diff_type, - xmlserialize(content nvl(exp.item_data, act.item_data) no indent) diffed_row, - null pk_value - from (select ucd.item_no, extract(ucd.item_data,'/*/*') item_data - from ut_compound_data_tmp ucd - where ucd.data_id = :self_guid - and ucd.item_no in (select i.item_no from diff_info i) - ) exp - full outer join ( - select ucd.item_no, extract(ucd.item_data,'/*/*') item_data - from ut_compound_data_tmp ucd - where ucd.data_id = :other_guid - and ucd.item_no in (select i.item_no from diff_info i) - )act - on exp.item_no = act.item_no - where exp.item_no is null or act.item_no is null - order by 1, 2]' - bulk collect into l_results - using a_diff_id, a_max_rows, - a_exclude_xpath, a_include_xpath, a_expected_dataset_guid, - a_exclude_xpath, a_include_xpath, a_actual_dataset_guid, - a_expected_dataset_guid, a_actual_dataset_guid; - return l_results; + return dbms_utility.get_hash_value(a_string,a_base,a_size); end; - function get_rows_diff_unordered( - a_expected_dataset_guid raw, a_actual_dataset_guid raw, a_diff_id raw, - a_max_rows integer, a_exclude_xpath varchar2, a_include_xpath varchar2 - ) return tt_row_diffs is - l_column_filter varchar2(32767); - l_results tt_row_diffs; + procedure insert_diffs_result(a_diff_tab t_diff_tab, a_diff_id raw) is + begin + forall idx in 1..a_diff_tab.count save exceptions + insert /*+ no_parallel */ into ut_compound_data_diff_tmp + ( diff_id, act_item_data, act_data_id, exp_item_data, exp_data_id, item_no, duplicate_no ) + values + (a_diff_id, + xmlelement( name "ROW", a_diff_tab(idx).act_item_data), a_diff_tab(idx).act_data_id, + xmlelement( name "ROW", a_diff_tab(idx).exp_item_data), a_diff_tab(idx).exp_data_id, + a_diff_tab(idx).item_no, a_diff_tab(idx).dup_no); + exception + when ut_utils.ex_failure_for_all then + raise_application_error(ut_utils.gc_dml_for_all,'Failure to insert a diff tmp data.'); + end; + + procedure set_rows_diff(a_rows_diff integer) is begin - l_column_filter := get_columns_filter(a_exclude_xpath,a_include_xpath); - - /** - * Since its unordered search we cannot select max rows from diffs as we miss some comparision records - * We will restrict output on higher level of select - */ - - execute immediate q'[with - diff_info as (select item_hash,duplicate_no from ut_compound_data_diff_tmp ucdc where diff_id = :diff_guid) - select duplicate_no, - diffed_type, - diffed_row, - null pk_value - from - (select - coalesce(exp.duplicate_no,act.duplicate_no) duplicate_no, - case - when act.row_hash is null then - 'Missing:' - else 'Extra:' - end diffed_type, - case when exp.row_hash is null then - xmlserialize(content act.row_data no indent) - when act.row_hash is null then - xmlserialize(content exp.row_data no indent) - end diffed_row - from (select ucd.* - from (select ucd.column_value row_data, - r.item_hash row_hash, - r.duplicate_no - from (select ]'||l_column_filter||q'[, ucd.item_no, i.item_hash, i.duplicate_no - from ut_compound_data_tmp ucd, - diff_info i - where ucd.data_id = :self_guid - and ucd.item_hash = i.item_hash - ) r, - table( xmlsequence( extract(r.item_data,'/*') ) ) ucd - ) ucd - ) exp - full outer join - (select ucd.* - from (select ucd.column_value row_data, - r.item_hash row_hash, - r.duplicate_no - from (select ]'||l_column_filter||q'[, ucd.item_no, i.item_hash, i.duplicate_no - from ut_compound_data_tmp ucd, - diff_info i - where ucd.data_id = :other_guid - and ucd.item_hash = i.item_hash - ) r, - table( xmlsequence( extract(r.item_data,'/*') ) ) ucd - ) ucd - ) act - on exp.row_hash = act.row_hash - and exp.duplicate_no = act.duplicate_no - where exp.row_hash is null or act.row_hash is null - order by diffed_type, coalesce(exp.row_hash,act.row_hash), duplicate_no - ) - where rownum < :max_rows ]' - bulk collect into l_results - using a_diff_id, - a_exclude_xpath, a_include_xpath, a_expected_dataset_guid, - a_exclude_xpath, a_include_xpath, a_actual_dataset_guid, - a_max_rows; - - return l_results; - + g_diff_count := a_rows_diff; end; - function compare_type(a_join_by_xpath in varchar2,a_unordered boolean) return varchar2 is - begin - case - when a_join_by_xpath is not null then - return gc_compare_join_by; - when a_unordered then - return gc_compare_unordered; - else - return gc_compare_normal; - end case; - end; + procedure cleanup_diff is + begin + g_diff_count := 0; + delete from ut_compound_data_diff_tmp; + delete from ut_json_data_diff_tmp; + end; - function get_rows_diff( - a_expected_dataset_guid raw, a_actual_dataset_guid raw, a_diff_id raw, - a_max_rows integer, a_exclude_xpath varchar2, a_include_xpath varchar2, - a_join_by_xpath varchar2,a_unorderdered boolean - ) return tt_row_diffs is - l_results tt_row_diffs; - l_compare_type varchar2(10):= compare_type(a_join_by_xpath,a_unorderdered); + function get_rows_diff_count return integer is begin - case - when l_compare_type = gc_compare_join_by then - return get_rows_diff(a_expected_dataset_guid, a_actual_dataset_guid, a_diff_id, - a_max_rows, a_exclude_xpath, a_include_xpath ,a_join_by_xpath); - when l_compare_type = gc_compare_unordered then - return get_rows_diff_unordered(a_expected_dataset_guid, a_actual_dataset_guid, a_diff_id, - a_max_rows, a_exclude_xpath, a_include_xpath); - else - return get_rows_diff(a_expected_dataset_guid, a_actual_dataset_guid, a_diff_id, - a_max_rows, a_exclude_xpath, a_include_xpath); - end case; + return g_diff_count; + end; + function is_sql_compare_allowed(a_type_name varchar2) + return boolean is + l_assert boolean; + begin + --clob/blob/xmltype/object/nestedcursor/nestedtable + if a_type_name IN (g_type_name_map(dbms_sql.blob_type), + g_type_name_map(dbms_sql.clob_type), + g_type_name_map(dbms_sql.long_type), + g_type_name_map(dbms_sql.long_raw_type), + g_type_name_map(dbms_sql.bfile_type), + g_anytype_name_map(dbms_types.typecode_namedcollection)) + then + l_assert := false; + else + l_assert := true; + end if; + return l_assert; end; - function get_hash(a_data raw, a_hash_type binary_integer := dbms_crypto.hash_sh1) return t_hash is + function get_column_type_desc(a_type_code in integer, a_dbms_sql_desc in boolean) + return varchar2 is begin - return dbms_crypto.hash(a_data, a_hash_type); + return + case + when a_dbms_sql_desc then g_type_name_map(a_type_code) + else g_anytype_name_map(a_type_code) + end; end; - function get_hash(a_data clob, a_hash_type binary_integer := dbms_crypto.hash_sh1) return t_hash is + function get_compare_cursor(a_diff_cursor_text in clob,a_self_id raw, a_other_id raw) return sys_refcursor is + l_diff_cursor sys_refcursor; + begin + open l_diff_cursor for a_diff_cursor_text using a_self_id, a_other_id; + return l_diff_cursor; + end; + + function create_err_cursor_msg(a_error_stack varchar2) return varchar2 is begin - return dbms_crypto.hash(a_data, a_hash_type); + return 'SQL exception thrown when fetching data from cursor:'|| + ut_utils.remove_error_from_stack(sqlerrm,ut_utils.gc_xml_processing)||chr(10)|| + ut_expectation_processor.who_called_expectation(a_error_stack)||chr(10)|| + 'Check the query and data for errors.'; end; - function columns_hash( - a_data_value_cursor ut_data_value_refcursor, a_exclude_xpath varchar2, a_include_xpath varchar2, - a_hash_type binary_integer := dbms_crypto.hash_sh1 - ) return t_hash is - l_cols_hash t_hash; - begin - if not a_data_value_cursor.is_null then - execute immediate - q'[select dbms_crypto.hash(replace(x.item_data.getclobval(),'>CHAR<','>VARCHAR2<'),]'||a_hash_type||') ' || - ' from ( select '||get_columns_filter(a_exclude_xpath, a_include_xpath)|| - ' from (select :columns_info as item_data from dual ) ucd' || - ' ) x' - into l_cols_hash using a_exclude_xpath,a_include_xpath, a_data_value_cursor.columns_info; - end if; - return l_cols_hash; + procedure save_cursor_data_for_diff(a_data_id raw, a_set_id integer, a_xml xmltype) is + begin + insert /*+ no_parallel */ into ut_compound_data_tmp (data_id, item_no, item_data) values (a_data_id, a_set_id, a_xml); end; - function is_pk_exists(a_expected_cursor xmltype,a_actual_cursor xmltype, a_exclude_xpath varchar2, a_include_xpath varchar2,a_join_by_xpath varchar2) - return tt_missing_pk is - l_pk_xpath_tabs ut_varchar2_list := ut_varchar2_list(); - l_column_filter varchar2(32767); - l_no_missing_keys tt_missing_pk := tt_missing_pk(); + function get_row_data_as_xml(a_data_id raw, a_max_rows integer) return ut_utils.t_clob_tab is + l_results ut_utils.t_clob_tab; + begin + select /*+ no_parallel */ xmlserialize( content ucd.item_data no indent) + bulk collect into l_results + from ut_compound_data_tmp tmp + ,xmltable ( '/ROWSET' passing tmp.item_data + columns item_data xmltype PATH '*' + ) ucd + where tmp.data_id = a_data_id + and rownum <= a_max_rows; + return l_results; + end; + + function type_no_length ( a_type_name varchar2) return boolean is + begin + return case + when g_type_no_length_map.exists(a_type_name) then + true + else + false + end; + end; + + function compare_json_data(a_act_json_data ut_json_leaf_tab,a_exp_json_data ut_json_leaf_tab) return tt_json_diff_tab is + l_result_diff tt_json_diff_tab := tt_json_diff_tab(); + begin + + with + differences as ( + select case + when (a.element_name is null or e.element_name is null) then gc_json_missing + when a.json_type != e.json_type then gc_json_type + when (decode(a.element_value,e.element_value,1,0) = 0) then gc_json_notequal + else gc_json_unknown + end as difference_type, + case + when (a.element_name is null or e.element_name is null) then 1 + when a.json_type != e.json_type then 2 + when (decode(a.element_value,e.element_value,1,0) = 0) then 3 + else 4 + end as order_by_type, + a.element_name as act_element_name, + a.element_value as act_element_value, + a.hierarchy_level as act_hierarchy_level, + a.index_position as act_index_position, + a.json_type as act_json_type, + a.access_path as act_access_path, + a.parent_name as act_par_name, + a.parent_path as act_parent_path, + e.element_name as exp_element_name, + e.element_value as exp_element_value, + e.hierarchy_level as exp_hierarchy_level, + e.index_position as exp_index_position, + e.json_type as exp_json_type, + e.access_path as exp_access_path, + e.parent_name as exp_par_name, + e.parent_path as exp_parent_path + from table(a_act_json_data) a + full outer join table(a_exp_json_data) e + on decode(a.parent_name,e.parent_name,1,0)= 1 + and decode(a.parent_path,e.parent_path,1,0)= 1 + and ( + case when a.parent_type = 'object' or e.parent_type = 'object' then + decode(a.element_name,e.element_name,1,0) + else 1 end = 1 + ) + and ( + case when a.parent_type = 'array' or e.parent_type = 'array' then + decode(a.index_position,e.index_position,1,0) + else 1 end = 1 + ) + and a.hierarchy_level = e.hierarchy_level + where (a.element_name is null or e.element_name is null) + or (a.json_type != e.json_type) + or (decode(a.element_value,e.element_value,1,0) = 0) + ) + select /*+ no_parallel */ difference_type, + act_element_name, act_element_value, act_json_type, act_access_path, act_parent_path, + exp_element_name, exp_element_value, exp_json_type, exp_access_path, exp_parent_path + bulk collect into l_result_diff + from differences a + where not exists ( + select 1 from differences b + where (a.act_par_name = b.act_element_name and a.act_hierarchy_level - 1 = b.act_hierarchy_level) + or (a.exp_par_name = b.exp_element_name and a.exp_hierarchy_level - 1 = b.exp_hierarchy_level) + and a.difference_type = gc_json_missing and b.difference_type = gc_json_missing + ) + order by order_by_type, + nvl(act_hierarchy_level,exp_hierarchy_level), + nvl(act_index_position,exp_index_position) nulls first, + nvl(act_element_name,exp_element_name) ; + return l_result_diff; + end; + + function insert_json_diffs(a_diff_id raw, a_act_json_data ut_json_leaf_tab, a_exp_json_data ut_json_leaf_tab) return integer is + l_diffs tt_json_diff_tab := compare_json_data(a_act_json_data,a_exp_json_data); + begin + forall i in 1..l_diffs.count + insert /*+ no_parallel */ into ut_json_data_diff_tmp ( + diff_id, difference_type, + act_element_name, act_element_value, act_json_type, act_access_path, act_parent_path, + exp_element_name, exp_element_value, exp_json_type, exp_access_path, exp_parent_path + ) + values ( + a_diff_id,l_diffs(i).difference_type, + l_diffs(i).act_element_name,l_diffs(i).act_element_value,l_diffs(i).act_json_type, l_diffs(i).act_access_path, l_diffs(i).act_parent_path, + l_diffs(i).exp_element_name,l_diffs(i).exp_element_value,l_diffs(i).exp_json_type,l_diffs(i).exp_access_path, l_diffs(i).exp_parent_path + ); + + return l_diffs.count; + end; + + function get_json_diffs_type(a_diff_id raw) return tt_json_diff_type_tab is + l_diffs_summary tt_json_diff_type_tab := tt_json_diff_type_tab(); begin - if a_join_by_xpath is not null then - l_pk_xpath_tabs := ut_utils.string_to_table(a_join_by_xpath,'|'); - l_column_filter := get_columns_row_filter(a_exclude_xpath, a_include_xpath); + select /*+ no_parallel */ d.difference_type,count(1) + bulk collect into l_diffs_summary + from ut_json_data_diff_tmp d + where diff_id = a_diff_id + group by d.difference_type; - execute immediate q'[ - with xpaths_tab as (select column_value xpath from table(:xpath_tabs)), - expected_column_info as ( select :expected as item_data from dual ), - actual_column_info as ( select :actual as item_data from dual ) - select REGEXP_SUBSTR (xpath,'[^(/\*/)](.+)$'),diif_type from - ( - (select xpath,'e' diif_type from xpaths_tab - minus - select xpath,'e' diif_type - from ( select ]'||l_column_filter||q'[ from expected_column_info ucd) x - ,xpaths_tab - where xmlexists (xpaths_tab.xpath passing x.item_data) - ) - union all - (select xpath,'a' diif_type from xpaths_tab - minus - select xpath,'a' diif_type - from ( select ]'||l_column_filter||q'[ from actual_column_info ucd) x - ,xpaths_tab - where xmlexists (xpaths_tab.xpath passing x.item_data) - ) - )]' bulk collect into l_no_missing_keys - using l_pk_xpath_tabs,a_expected_cursor,a_actual_cursor, - a_exclude_xpath, a_include_xpath, - a_exclude_xpath, a_include_xpath; + return l_diffs_summary; + end; + + function get_json_diffs_tmp(a_diff_id raw) return tt_json_diff_tab is + l_diffs tt_json_diff_tab; + begin + select /*+ no_parallel */ difference_type, + act_element_name, act_element_value, act_json_type, act_access_path, act_parent_path, + exp_element_name, exp_element_value, exp_json_type, exp_access_path, exp_parent_path + bulk collect into l_diffs + from ut_json_data_diff_tmp + where diff_id = a_diff_id; + + return l_diffs; + end; + + function get_json_object(a_json_t json) return json_element_t is + l_obj json_element_t; + begin + $if dbms_db_version.version >= 21 $then + l_obj := case when a_json_t is null then cast (null as json_element_t ) else json_element_t.parse(json_query(a_json_t, '$' returning clob)) end; + $end + return l_obj; + end; + +begin + g_anytype_name_map(dbms_types.typecode_date) := 'DATE'; + g_anytype_name_map(dbms_types.typecode_number) := 'NUMBER'; + g_anytype_name_map(3 /*INTEGER in object type*/) := 'NUMBER'; + g_anytype_name_map(dbms_types.typecode_raw) := 'RAW'; + g_anytype_name_map(dbms_types.typecode_char) := 'CHAR'; + g_anytype_name_map(dbms_types.typecode_varchar2) := 'VARCHAR2'; + g_anytype_name_map(dbms_types.typecode_varchar) := 'VARCHAR'; + g_anytype_name_map(dbms_types.typecode_blob) := 'BLOB'; + g_anytype_name_map(dbms_types.typecode_bfile) := 'BFILE'; + g_anytype_name_map(dbms_types.typecode_clob) := 'CLOB'; + g_anytype_name_map(dbms_types.typecode_timestamp) := 'TIMESTAMP'; + g_anytype_name_map(dbms_types.typecode_timestamp_tz) := 'TIMESTAMP WITH TIME ZONE'; + g_anytype_name_map(dbms_types.typecode_timestamp_ltz) := 'TIMESTAMP WITH LOCAL TIME ZONE'; + g_anytype_name_map(dbms_types.typecode_interval_ym) := 'INTERVAL YEAR TO MONTH'; + g_anytype_name_map(dbms_types.typecode_interval_ds) := 'INTERVAL DAY TO SECOND'; + g_anytype_name_map(dbms_types.typecode_bfloat) := 'BINARY_FLOAT'; + g_anytype_name_map(dbms_types.typecode_bdouble) := 'BINARY_DOUBLE'; + g_anytype_name_map(dbms_types.typecode_urowid) := 'UROWID'; + g_anytype_name_map(dbms_types.typecode_varray) := 'VARRRAY'; + g_anytype_name_map(dbms_types.typecode_table) := 'TABLE'; + g_anytype_name_map(dbms_types.typecode_namedcollection) := 'NAMEDCOLLECTION'; + g_anytype_name_map(dbms_types.typecode_object) := 'OBJECT'; + + g_type_name_map( dbms_sql.binary_bouble_type ) := 'BINARY_DOUBLE'; + g_type_name_map( dbms_sql.bfile_type ) := 'BFILE'; + g_type_name_map( dbms_sql.binary_float_type ) := 'BINARY_FLOAT'; + g_type_name_map( dbms_sql.blob_type ) := 'BLOB'; + g_type_name_map( dbms_sql.long_raw_type ) := 'LONG RAW'; + g_type_name_map( dbms_sql.char_type ) := 'CHAR'; + g_type_name_map( dbms_sql.clob_type ) := 'CLOB'; + g_type_name_map( dbms_sql.long_type ) := 'LONG'; + g_type_name_map( dbms_sql.date_type ) := 'DATE'; + g_type_name_map( dbms_sql.interval_day_to_second_type ) := 'INTERVAL DAY TO SECOND'; + g_type_name_map( dbms_sql.interval_year_to_month_type ) := 'INTERVAL YEAR TO MONTH'; + g_type_name_map( dbms_sql.raw_type ) := 'RAW'; + g_type_name_map( dbms_sql.timestamp_type ) := 'TIMESTAMP'; + g_type_name_map( dbms_sql.timestamp_with_tz_type ) := 'TIMESTAMP WITH TIME ZONE'; + g_type_name_map( dbms_sql.timestamp_with_local_tz_type ) := 'TIMESTAMP WITH LOCAL TIME ZONE'; + g_type_name_map( dbms_sql.varchar2_type ) := 'VARCHAR2'; + g_type_name_map( dbms_sql.number_type ) := 'NUMBER'; + g_type_name_map( dbms_sql.rowid_type ) := 'ROWID'; + g_type_name_map( dbms_sql.urowid_type ) := 'UROWID'; + g_type_name_map( dbms_sql.user_defined_type ) := 'USER_DEFINED_TYPE'; + g_type_name_map( dbms_sql.ref_type ) := 'REF_TYPE'; - end if; - return l_no_missing_keys; - end; - + /** + * List of types that have no length but can produce a max_len from desc_cursor function. + */ + g_type_no_length_map('ROWID') := 'ROWID'; + g_type_no_length_map('INTERVAL DAY TO SECOND') := 'INTERVAL DAY TO SECOND'; + g_type_no_length_map('INTERVAL YEAR TO MONTH') := 'INTERVAL YEAR TO MONTH'; + g_type_no_length_map('BINARY_DOUBLE') := 'BINARY_DOUBLE'; + g_type_no_length_map('BINARY_FLOAT') := 'BINARY_FLOAT'; end; / diff --git a/source/expectations/data_values/ut_compound_data_helper.pks b/source/expectations/data_values/ut_compound_data_helper.pks index ab3693920..451cd9bac 100644 --- a/source/expectations/data_values/ut_compound_data_helper.pks +++ b/source/expectations/data_values/ut_compound_data_helper.pks @@ -1,7 +1,7 @@ create or replace package ut_compound_data_helper authid definer is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -16,10 +16,14 @@ create or replace package ut_compound_data_helper authid definer is limitations under the License. */ - gc_compare_join_by constant varchar2(10):='join_by'; gc_compare_unordered constant varchar2(10):='unordered'; gc_compare_normal constant varchar2(10):='normal'; + gc_json_missing constant varchar2(30) := 'missing properties'; + gc_json_type constant varchar2(30) := 'incorrect types'; + gc_json_notequal constant varchar2(30) := 'unequal values'; + gc_json_unknown constant varchar2(30) := 'unknown'; + type t_column_diffs is record( diff_type varchar2(1), expected_name varchar2(250), @@ -32,13 +36,6 @@ create or replace package ut_compound_data_helper authid definer is type tt_column_diffs is table of t_column_diffs; - type t_missing_pk is record( - missingxpath varchar2(250), - diff_type varchar2(1) - ); - - type tt_missing_pk is table of t_missing_pk; - type t_row_diffs is record( rn integer, diff_type varchar2(250), @@ -48,38 +45,96 @@ create or replace package ut_compound_data_helper authid definer is type tt_row_diffs is table of t_row_diffs; - function get_column_info_xml(a_column_details ut_key_anyval_pair) return xmltype; - - function get_columns_filter( - a_exclude_xpath varchar2, a_include_xpath varchar2, - a_table_alias varchar2 := 'ucd', a_column_alias varchar2 := 'item_data' - ) return varchar2; + type t_diff_rec is record ( + act_item_data xmltype, + act_data_id raw(32), + exp_item_data xmltype, + exp_data_id raw(32), + item_no number, + dup_no number + ); + type t_diff_tab is table of t_diff_rec; + + type t_json_diff_rec is record ( + difference_type varchar2(50), + act_element_name varchar2(4000), + act_element_value varchar2(4000), + act_json_type varchar2(4000), + act_access_path varchar2(4000), + act_parent_path varchar2(4000), + exp_element_name varchar2(4000), + exp_element_value varchar2(4000), + exp_json_type varchar2(4000), + exp_access_path varchar2(4000), + exp_parent_path varchar2(4000) + ); + + type tt_json_diff_tab is table of t_json_diff_rec; + + type t_json_diff_type_rec is record ( + difference_type varchar2(50), + no_of_occurence integer + ); + + type tt_json_diff_type_tab is table of t_json_diff_type_rec; + function get_columns_diff( - a_expected xmltype, a_actual xmltype, a_exclude_xpath varchar2, a_include_xpath varchar2 + a_expected ut_cursor_column_tab, a_actual ut_cursor_column_tab,a_order_enforced boolean := false ) return tt_column_diffs; - function get_pk_value (a_join_by_xpath varchar2,a_item_data xmltype) return clob; - - function compare_type(a_join_by_xpath in varchar2,a_unordered boolean) return varchar2; - - function get_rows_diff( + function get_rows_diff_by_sql( + a_act_cursor_info ut_cursor_column_tab,a_exp_cursor_info ut_cursor_column_tab, a_expected_dataset_guid raw, a_actual_dataset_guid raw, a_diff_id raw, - a_max_rows integer, a_exclude_xpath varchar2, a_include_xpath varchar2, - a_join_by_xpath varchar2,a_unorderdered boolean + a_join_by_list ut_varchar2_list, a_unordered boolean, a_enforce_column_order boolean := false, + a_extract_path varchar2 ) return tt_row_diffs; - subtype t_hash is raw(128); + function get_fixed_size_hash(a_string varchar2, a_base integer :=0,a_size integer :=9999999) return number; + + function gen_compare_sql( + a_other ut_data_value_refcursor, + a_join_by_list ut_varchar2_list, + a_unordered boolean, + a_inclusion_type boolean, + a_is_negated boolean + ) return clob; + + procedure insert_diffs_result(a_diff_tab t_diff_tab, a_diff_id raw); + + procedure set_rows_diff(a_rows_diff integer); + + procedure cleanup_diff; + + function get_rows_diff_count return integer; + + function is_sql_compare_allowed(a_type_name varchar2) return boolean; + + function get_column_type_desc(a_type_code in integer, a_dbms_sql_desc in boolean) return varchar2; + + function get_compare_cursor(a_diff_cursor_text in clob,a_self_id raw, a_other_id raw) return sys_refcursor; + + function create_err_cursor_msg(a_error_stack varchar2) return varchar2; - function get_hash(a_data raw, a_hash_type binary_integer := dbms_crypto.hash_sh1) return t_hash; - function get_hash(a_data clob, a_hash_type binary_integer := dbms_crypto.hash_sh1) return t_hash; - function columns_hash( - a_data_value_cursor ut_data_value_refcursor, a_exclude_xpath varchar2, a_include_xpath varchar2, - a_hash_type binary_integer := dbms_crypto.hash_sh1 - ) return t_hash; - - function is_pk_exists(a_expected_cursor xmltype, a_actual_cursor xmltype, a_exclude_xpath varchar2, a_include_xpath varchar2,a_join_by_xpath varchar2) - return tt_missing_pk; + procedure save_cursor_data_for_diff(a_data_id raw, a_set_id integer, a_xml xmltype); + function get_row_data_as_xml(a_data_id raw, a_max_rows integer) return ut_utils.t_clob_tab; + + /* + * Function to return true or false if the type dont have an length + */ + function type_no_length ( a_type_name varchar2) return boolean; + + function compare_json_data(a_act_json_data ut_json_leaf_tab,a_exp_json_data ut_json_leaf_tab) return tt_json_diff_tab; + + function insert_json_diffs(a_diff_id raw, a_act_json_data ut_json_leaf_tab,a_exp_json_data ut_json_leaf_tab) return integer; + + function get_json_diffs_tmp(a_diff_id raw) return tt_json_diff_tab; + + + function get_json_diffs_type(a_diff_id raw) return tt_json_diff_type_tab; + + function get_json_object(a_json_t json) return json_element_t; + end; / diff --git a/source/expectations/data_values/ut_compound_data_tmp.sql b/source/expectations/data_values/ut_compound_data_tmp.sql index a4c6516af..1bfa77fca 100644 --- a/source/expectations/data_values/ut_compound_data_tmp.sql +++ b/source/expectations/data_values/ut_compound_data_tmp.sql @@ -1,7 +1,7 @@ create global temporary table ut_compound_data_tmp( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 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 @@ -18,5 +18,6 @@ create global temporary table ut_compound_data_tmp( item_hash raw(128), pk_hash raw(128), duplicate_no integer, - constraint ut_cmp_data_tmp_hash_pk unique (data_id,item_no, item_hash , duplicate_no) -) on commit preserve rows; + constraint ut_cmp_data_tmp_hash_pk unique (data_id, item_no, duplicate_no) +) on commit delete rows; +--xmltype column item_data store as binary xml; \ No newline at end of file diff --git a/source/expectations/data_values/ut_compound_data_value.tpb b/source/expectations/data_values/ut_compound_data_value.tpb index 113c5153e..2c52ff8fa 100644 --- a/source/expectations/data_values/ut_compound_data_value.tpb +++ b/source/expectations/data_values/ut_compound_data_value.tpb @@ -1,7 +1,7 @@ create or replace type body ut_compound_data_value as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -16,9 +16,14 @@ create or replace type body ut_compound_data_value as limitations under the License. */ + member function get_elements_count_info return varchar2 is + begin + return case when elements_count is null then ' [ null ]' else ' [ count = '||elements_count||' ]' end; + end; + overriding member function get_object_info return varchar2 is begin - return self.data_type||' [ count = '||self.elements_count||' ]'; + return self.data_type||get_elements_count_info(); end; overriding member function is_null return boolean is @@ -36,29 +41,17 @@ create or replace type body ut_compound_data_value as return not self.is_null(); end; - overriding member function compare_implementation(a_other ut_data_value) return integer is - begin - return compare_implementation( a_other, null, null); - end; - overriding member function to_string return varchar2 is - l_results ut_utils.t_clob_tab; - c_max_rows constant integer := 20; l_result clob; l_result_string varchar2(32767); begin if not self.is_null() then dbms_lob.createtemporary(l_result, true); ut_utils.append_to_clob(l_result,'Data:'||chr(10)); - --return first c_max_rows rows - execute immediate ' - select xmlserialize( content ucd.item_data no indent) - from '|| ut_utils.ut_owner ||'.ut_compound_data_tmp ucd - where ucd.data_id = :data_id - and ucd.item_no <= :max_rows' - bulk collect into l_results using self.data_id, c_max_rows; - - ut_utils.append_to_clob(l_result,l_results); + ut_utils.append_to_clob( + l_result, + ut_compound_data_helper.get_row_data_as_xml( self.data_id, ut_utils.gc_diff_max_rows ) + ); l_result_string := ut_utils.to_string(l_result,null); dbms_lob.freetemporary(l_result); @@ -66,230 +59,5 @@ create or replace type body ut_compound_data_value as return l_result_string; end; - overriding member function diff( a_other ut_data_value, a_exclude_xpath varchar2, a_include_xpath varchar2, a_join_by_xpath varchar2, a_unordered boolean := false ) return varchar2 is - l_result clob; - l_result_string varchar2(32767); - begin - l_result := get_data_diff(a_other, a_exclude_xpath, a_include_xpath, a_join_by_xpath,a_unordered); - l_result_string := ut_utils.to_string(l_result,null); - dbms_lob.freetemporary(l_result); - return l_result_string; - end; - - member function get_data_diff(a_other ut_data_value, a_exclude_xpath varchar2, a_include_xpath varchar2, - a_join_by_xpath varchar2, a_unordered boolean) return clob is - c_max_rows constant integer := 20; - l_result clob; - l_results ut_utils.t_clob_tab := ut_utils.t_clob_tab(); - l_message varchar2(32767); - l_ut_owner varchar2(250) := ut_utils.ut_owner; - l_diff_row_count integer; - l_actual ut_compound_data_value; - l_diff_id ut_compound_data_helper.t_hash; - l_row_diffs ut_compound_data_helper.tt_row_diffs; - l_compare_type varchar2(10); - - function get_diff_message (a_row_diff ut_compound_data_helper.t_row_diffs,a_compare_type varchar2) return varchar2 is - begin - if a_compare_type = ut_compound_data_helper.gc_compare_join_by and a_row_diff.pk_value is not null then - return ' PK '||a_row_diff.pk_value||' - '||rpad(a_row_diff.diff_type,10)||a_row_diff.diffed_row; - elsif a_compare_type = ut_compound_data_helper.gc_compare_join_by or a_compare_type = ut_compound_data_helper.gc_compare_normal then - return ' Row No. '||a_row_diff.rn||' - '||rpad(a_row_diff.diff_type,10)||a_row_diff.diffed_row; - elsif a_compare_type = ut_compound_data_helper.gc_compare_unordered then - return rpad(a_row_diff.diff_type,10)||a_row_diff.diffed_row; - end if; - end; - - begin - if not a_other is of (ut_compound_data_value) then - raise value_error; - end if; - l_actual := treat(a_other as ut_compound_data_value); - - dbms_lob.createtemporary(l_result,true); - - --diff rows and row elements - l_diff_id := ut_compound_data_helper.get_hash(self.data_id||l_actual.data_id); - - -- First tell how many rows are different - execute immediate 'select count('||case when a_join_by_xpath is not null then 'distinct pk_hash' else '*' end||') from ' - || l_ut_owner || '.ut_compound_data_diff_tmp - where diff_id = :diff_id' into l_diff_row_count using l_diff_id; - - if l_diff_row_count > 0 then - l_compare_type := ut_compound_data_helper.compare_type(a_join_by_xpath,a_unordered); - l_row_diffs := ut_compound_data_helper.get_rows_diff( - self.data_id, l_actual.data_id, l_diff_id, c_max_rows, a_exclude_xpath, a_include_xpath, a_join_by_xpath, a_unordered); - l_message := chr(10) - ||'Rows: [ ' || l_diff_row_count ||' differences' - || case when l_diff_row_count > c_max_rows and l_row_diffs.count > 0 then ', showing first '||c_max_rows end - ||' ]' || chr(10) - || case when l_row_diffs.count = 0 - then ' All rows are different as the columns are not matching.' end; - ut_utils.append_to_clob( l_result, l_message ); - for i in 1 .. l_row_diffs.count loop - l_results.extend; - l_results(l_results.last) := get_diff_message(l_row_diffs(i),l_compare_type); - end loop; - ut_utils.append_to_clob(l_result,l_results); - end if; - return l_result; - end; - - - member function compare_implementation(a_other ut_data_value, a_exclude_xpath varchar2, a_include_xpath varchar2) return integer is - l_other ut_compound_data_value; - l_ut_owner varchar2(250) := ut_utils.ut_owner; - l_column_filter varchar2(32767); - l_diff_id ut_compound_data_helper.t_hash; - l_result integer; - --the XML stylesheet is applied on XML representation of data to exclude column names from comparison - --column names and data-types are compared separately - --user CHR(38) instead of ampersand to eliminate define request when installing through some IDEs - l_xml_data_fmt constant xmltype := xmltype( - q'[ - - - - - - '||CHR(38)||'#xD; - , - - - - ]'); - begin - if not a_other is of (ut_compound_data_value) then - raise value_error; - end if; - - l_other := treat(a_other as ut_compound_data_value); - - l_diff_id := ut_compound_data_helper.get_hash(self.data_id||l_other.data_id); - l_column_filter := ut_compound_data_helper.get_columns_filter(a_exclude_xpath, a_include_xpath); - -- Find differences - execute immediate 'insert into ' || l_ut_owner || '.ut_compound_data_diff_tmp ( diff_id, item_no ) - select :diff_id, nvl(exp.item_no, act.item_no) - from (select '||l_column_filter||', ucd.item_no - from ' || l_ut_owner || '.ut_compound_data_tmp ucd where ucd.data_id = :self_guid) exp - full outer join - (select '||l_column_filter||', ucd.item_no - from ' || l_ut_owner || '.ut_compound_data_tmp ucd where ucd.data_id = :l_other_guid) act - on exp.item_no = act.item_no '|| - 'where nvl( dbms_lob.compare(' || - /*the xmltransform removes column names and leaves column data to be compared only*/ - ' xmltransform(exp.item_data, :l_xml_data_fmt).getclobval()' || - ', xmltransform(act.item_data, :l_xml_data_fmt).getclobval())' || - ',1' || - ') != 0' - using in l_diff_id, a_exclude_xpath, a_include_xpath, self.data_id, - a_exclude_xpath, a_include_xpath, l_other.data_id, l_xml_data_fmt, l_xml_data_fmt; - --result is OK only if both are same - if sql%rowcount = 0 and self.elements_count = l_other.elements_count then - l_result := 0; - else - l_result := 1; - end if; - return l_result; - end; - - member function compare_implementation(a_other ut_data_value, a_exclude_xpath varchar2, a_include_xpath varchar2, a_join_by_xpath varchar2, a_unordered boolean ) return integer is - l_other ut_compound_data_value; - l_ut_owner varchar2(250) := ut_utils.ut_owner; - l_column_filter varchar2(32767); - l_diff_id ut_compound_data_helper.t_hash; - l_result integer; - l_row_diffs ut_compound_data_helper.tt_row_diffs; - c_max_rows constant integer := 20; - - function get_column_pk_hash(a_join_by_xpath varchar2) return varchar2 is - l_column varchar2(32767); - begin - /* due to possibility of key being to columns we cannot use xmlextractvalue - usage of xmlagg is possible however it greatly complicates code and performance is impacted. - xpath to be looked at or regex - */ - if a_join_by_xpath is not null then - l_column := l_ut_owner ||'.ut_compound_data_helper.get_hash(extract(ucd.item_data,:join_by_xpath).GetClobVal()) pk_hash'; - else - l_column := ':join_by_xpath pk_hash'; - end if; - return l_column; - end; - - begin - if not a_other is of (ut_compound_data_value) then - raise value_error; - end if; - - l_other := treat(a_other as ut_compound_data_value); - - l_diff_id := ut_compound_data_helper.get_hash(self.data_id||l_other.data_id); - l_column_filter := ut_compound_data_helper.get_columns_filter(a_exclude_xpath, a_include_xpath); - - /** - * Due to incompatibility issues in XML between 11 and 12.2 and 12.1 versions we will prepopulate pk_hash upfront to - * avoid optimizer incorrectly rewrite and causing NULL error or ORA-600 - **/ - execute immediate 'merge into ' || l_ut_owner || '.ut_compound_data_tmp tgt - using ( - select '||l_ut_owner ||'.ut_compound_data_helper.get_hash(ucd.item_data.getclobval()) item_hash, - pk_hash, ucd.item_no, ucd.data_id - from - ( - select '||l_column_filter||','||get_column_pk_hash(a_join_by_xpath)||', item_no, data_id - from ' || l_ut_owner || q'[.ut_compound_data_tmp ucd - where data_id = :self_guid or data_id = :other_guid - ) ucd - ) src - on (tgt.item_no = src.item_no and tgt.data_id = src.data_id) - when matched then update - set tgt.item_hash = src.item_hash, - tgt.pk_hash = src.pk_hash ]' - using a_exclude_xpath, a_include_xpath,a_join_by_xpath,self.data_id, l_other.data_id; - - /* Peform minus on two sets two get diffrences that will be used later on to print results */ - execute immediate 'insert into ' || l_ut_owner || '.ut_compound_data_diff_tmp ( diff_id,item_hash,pk_hash,duplicate_no) - with source_data as - ( select t.data_id,t.item_hash,row_number() over (partition by t.pk_hash,t.item_hash,t.data_id order by 1,2) duplicate_no, - pk_hash - from ' || l_ut_owner || '.ut_compound_data_tmp t - where data_id = :self_guid or data_id = :other_guid - ) - select distinct :diff_id,tmp.item_hash,tmp.pk_hash,tmp.duplicate_no - from( - ( - select t.item_hash,t. duplicate_no,t.pk_hash - from source_data t - where t.data_id = :self_guid - minus - select t.item_hash,t. duplicate_no,t.pk_hash - from source_data t - where t.data_id = :other_guid - ) - union all - ( - select t.item_hash,t. duplicate_no,t.pk_hash - from source_data t - where t.data_id = :other_guid - minus - select t.item_hash,t. duplicate_no,t.pk_hash - from source_data t - where t.data_id = :self_guid - ))tmp' - using self.data_id, l_other.data_id, - l_diff_id, - self.data_id, l_other.data_id, - l_other.data_id,self.data_id; - --result is OK only if both are same - if sql%rowcount = 0 and self.elements_count = l_other.elements_count then - l_result := 0; - else - l_result := 1; - end if; - return l_result; - end; - end; / diff --git a/source/expectations/data_values/ut_compound_data_value.tps b/source/expectations/data_values/ut_compound_data_value.tps index bf942c92e..c14dadceb 100644 --- a/source/expectations/data_values/ut_compound_data_value.tps +++ b/source/expectations/data_values/ut_compound_data_value.tps @@ -1,7 +1,7 @@ create or replace type ut_compound_data_value force under ut_data_value( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -34,16 +34,17 @@ create or replace type ut_compound_data_value force under ut_data_value( * Holds unique id for retrieving the data from ut_compound_data_tmp temp table */ data_id raw(16), + + /** + * Holds name for the type of compound + */ + compound_type varchar2(50), + member function get_elements_count_info return varchar2, overriding member function get_object_info return varchar2, overriding member function is_null return boolean, overriding member function is_diffable return boolean, overriding member function to_string return varchar2, - overriding member function is_multi_line return boolean, - overriding member function compare_implementation(a_other ut_data_value) return integer, - overriding member function diff( a_other ut_data_value, a_exclude_xpath varchar2, a_include_xpath varchar2, a_join_by_xpath varchar2, a_unordered boolean := false ) return varchar2, - member function get_data_diff(a_other ut_data_value, a_exclude_xpath varchar2, a_include_xpath varchar2, a_join_by_xpath varchar2, a_unordered boolean) return clob, - member function compare_implementation(a_other ut_data_value, a_exclude_xpath varchar2, a_include_xpath varchar2) return integer, - member function compare_implementation(a_other ut_data_value, a_exclude_xpath varchar2, a_include_xpath varchar2, a_join_by_xpath varchar2, a_unordered boolean ) return integer + overriding member function is_multi_line return boolean ) not final not instantiable / diff --git a/source/expectations/data_values/ut_curr_usr_compound_helper.pkb b/source/expectations/data_values/ut_curr_usr_compound_helper.pkb deleted file mode 100644 index b610ee13c..000000000 --- a/source/expectations/data_values/ut_curr_usr_compound_helper.pkb +++ /dev/null @@ -1,244 +0,0 @@ -create or replace package body ut_curr_usr_compound_helper is - - type t_type_name_map is table of varchar2(100) index by binary_integer; - g_type_name_map t_type_name_map; - g_anytype_name_map t_type_name_map; - g_anytype_collection_name t_type_name_map; - g_user_defined_type pls_integer := dbms_sql.user_defined_type; - g_is_collection boolean := false; - - procedure set_collection_state(a_is_collection boolean) is - begin - --Make sure that we set a g_is_collection only once so we dont reset from true to false. - if not g_is_collection then - g_is_collection := a_is_collection; - end if; - end; - - function get_column_type(a_desc_rec dbms_sql.desc_rec3, a_desc_user_types boolean := false) return ut_key_anyval_pair is - l_data ut_data_value; - l_result ut_key_anyval_pair; - l_data_type varchar2(500) := 'unknown datatype'; - - function is_collection (a_owner varchar2,a_type_name varchar2) return boolean is - l_type_view varchar2(200) := ut_metadata.get_dba_view('dba_types'); - l_typecode varchar2(100); - begin - execute immediate 'select typecode from '||l_type_view ||' - where owner = :owner and type_name = :typename' - into l_typecode using a_owner,a_type_name; - - return l_typecode = 'COLLECTION'; - end; - - begin - if g_type_name_map.exists(a_desc_rec.col_type) then - l_data := ut_data_value_varchar2(g_type_name_map(a_desc_rec.col_type)); - /*If its a collection regardless is we want to describe user defined types we will return just a name - and capture that name */ - elsif a_desc_rec.col_type = g_user_defined_type and is_collection(a_desc_rec.col_schema_name,a_desc_rec.col_type_name) then - l_data := ut_data_value_varchar2(a_desc_rec.col_schema_name||'.'||a_desc_rec.col_type_name); - set_collection_state(true); - elsif a_desc_rec.col_type = g_user_defined_type and a_desc_user_types then - l_data :=ut_data_value_xmltype(get_user_defined_type(a_desc_rec.col_schema_name,a_desc_rec.col_type_name)); - elsif a_desc_rec.col_schema_name is not null and a_desc_rec.col_type_name is not null then - l_data := ut_data_value_varchar2(a_desc_rec.col_schema_name||'.'||a_desc_rec.col_type_name); - end if; - return ut_key_anyval_pair(a_desc_rec.col_name,l_data); - end; - - function get_columns_info( - a_columns_tab dbms_sql.desc_tab3, a_columns_count integer, a_desc_user_types boolean := false - ) return ut_key_anyval_pairs is - l_result ut_key_anyval_pairs := ut_key_anyval_pairs(); - begin - for i in 1 .. a_columns_count loop - l_result.extend; - l_result(l_result.last) := get_column_type(a_columns_tab(i),a_desc_user_types); - end loop; - return l_result; - end; - - procedure get_descr_cursor( - a_cursor in out nocopy sys_refcursor, - a_columns_tab in out nocopy ut_key_anyval_pairs, - a_join_by_tab in out nocopy ut_key_anyval_pairs - ) is - l_cursor_number integer; - l_columns_count pls_integer; - l_columns_desc dbms_sql.desc_tab3; - begin - if a_cursor is null or not a_cursor%isopen then - a_columns_tab := null; - a_join_by_tab := null; - end if; - l_cursor_number := dbms_sql.to_cursor_number( a_cursor ); - dbms_sql.describe_columns3( l_cursor_number, l_columns_count, l_columns_desc ); - a_cursor := dbms_sql.to_refcursor( l_cursor_number ); - a_columns_tab := get_columns_info( l_columns_desc, l_columns_count, false); - a_join_by_tab := get_columns_info( l_columns_desc, l_columns_count, true); - end; - - procedure get_columns_info( - a_cursor in out nocopy sys_refcursor, - a_columns_info out nocopy xmltype, - a_join_by_info out nocopy xmltype, - a_contains_collection out nocopy number - ) is - l_columns_info xmltype; - l_join_by_info xmltype; - l_result_tmp xmltype; - l_columns_tab ut_key_anyval_pairs; - l_join_by_tab ut_key_anyval_pairs; - begin - - get_descr_cursor(a_cursor,l_columns_tab,l_join_by_tab); - - for i in 1..l_columns_tab.COUNT - loop - l_result_tmp := ut_compound_data_helper.get_column_info_xml(l_columns_tab(i)); - select xmlconcat(l_columns_info,l_result_tmp) into l_columns_info from dual; - end loop; - - for i in 1..l_join_by_tab.COUNT - loop - l_result_tmp := ut_compound_data_helper.get_column_info_xml(l_join_by_tab(i)); - select xmlconcat(l_join_by_info,l_result_tmp) into l_join_by_info from dual; - end loop; - - select XMLELEMENT("ROW",l_columns_info ),XMLELEMENT("ROW",l_join_by_info ) - into a_columns_info,a_join_by_info from dual; - - a_contains_collection := ut_utils.boolean_to_int(g_is_collection); - end; - - function get_anytype_attribute_count (a_anytype anytype) return pls_integer is - l_attribute_typecode pls_integer; - l_schema_name varchar2(32767); - l_version varchar2(32767); - l_type_name varchar2(32767); - l_attributes pls_integer; - l_prec pls_integer; - l_scale pls_integer; - l_len pls_integer; - l_csid pls_integer; - l_csfrm pls_integer; - begin - l_attribute_typecode := a_anytype.getinfo( - prec => l_prec, - scale => l_scale, - len => l_len, - csid => l_csid, - csfrm => l_csfrm, - schema_name => l_schema_name, - type_name => l_type_name, - version => l_version, - numelems => l_attributes); - return l_attributes; - end; - - function get_anytype_attributes_info (a_anytype anytype) return ut_key_value_pairs is - l_result ut_key_value_pairs := ut_key_value_pairs(); - l_attribute_typecode pls_integer; - l_aname varchar2(32767); - l_prec pls_integer; - l_scale pls_integer; - l_len pls_integer; - l_csid pls_integer; - l_csfrm pls_integer; - l_attr_elt_type anytype; - begin - for i in 1..get_anytype_attribute_count(a_anytype) loop - l_attribute_typecode := a_anytype.getAttrElemInfo( - pos => i, --First attribute - prec => l_prec, - scale => l_scale, - len => l_len, - csid => l_csid, - csfrm => l_csfrm, - attr_elt_type => l_attr_elt_type, - aname => l_aname); - - l_result.extend; - l_result(l_result.last) := ut_key_value_pair(l_aname, g_anytype_name_map(l_attribute_typecode)); - --check for collection - if g_anytype_collection_name.exists(l_attribute_typecode) then - set_collection_state(true); - end if; - end loop; - return l_result; - end; - - function get_user_defined_type(a_owner varchar2,a_type_name varchar2) return xmltype is - l_anydata anydata; - l_anytype anytype; - l_typecode pls_integer; - l_result xmltype; - l_columns_tab ut_key_value_pairs := ut_key_value_pairs(); - - begin - execute immediate 'declare - l_v '||a_owner||'.'||a_type_name||'; - begin - :anydata := anydata.convertobject(l_v); - end;' USING IN OUT l_anydata; - - l_typecode := l_anydata.gettype(l_anytype); - l_columns_tab := get_anytype_attributes_info(l_anytype); - - select xmlagg(xmlelement(evalname key,value)) - into l_result from table(l_columns_tab); - - return l_result; - - end; - - begin - g_anytype_name_map(dbms_types.typecode_date) :=' DATE'; - g_anytype_name_map(dbms_types.typecode_number) := 'NUMBER'; - g_anytype_name_map(dbms_types.typecode_raw) := 'RAW'; - g_anytype_name_map(dbms_types.typecode_char) := 'CHAR'; - g_anytype_name_map(dbms_types.typecode_varchar2) := 'VARCHAR2'; - g_anytype_name_map(dbms_types.typecode_varchar) := 'VARCHAR'; - g_anytype_name_map(dbms_types.typecode_blob) := 'BLOB'; - g_anytype_name_map(dbms_types.typecode_bfile) := 'BFILE'; - g_anytype_name_map(dbms_types.typecode_clob) := 'CLOB'; - g_anytype_name_map(dbms_types.typecode_timestamp) := 'TIMESTAMP'; - g_anytype_name_map(dbms_types.typecode_timestamp_tz) := 'TIMESTAMP WITH TIME ZONE'; - g_anytype_name_map(dbms_types.typecode_timestamp_ltz) := 'TIMESTAMP WITH LOCAL TIME ZONE'; - g_anytype_name_map(dbms_types.typecode_interval_ym) := 'INTERVAL YEAR TO MONTH'; - g_anytype_name_map(dbms_types.typecode_interval_ds) := 'INTERVAL DAY TO SECOND'; - g_anytype_name_map(dbms_types.typecode_bfloat) := 'BINARY_FLOAT'; - g_anytype_name_map(dbms_types.typecode_bdouble) := 'BINARY_DOUBLE'; - g_anytype_name_map(dbms_types.typecode_urowid) := 'UROWID'; - g_anytype_name_map(dbms_types.typecode_varray) := 'VARRRAY'; - g_anytype_name_map(dbms_types.typecode_table) := 'TABLE'; - g_anytype_name_map(dbms_types.typecode_namedcollection) := 'NAMEDCOLLECTION'; - - g_anytype_collection_name(dbms_types.typecode_varray) := 'VARRRAY'; - g_anytype_collection_name(dbms_types.typecode_table) := 'TABLE'; - g_anytype_collection_name(dbms_types.typecode_namedcollection) := 'NAMEDCOLLECTION'; - - - g_type_name_map( dbms_sql.binary_bouble_type ) := 'BINARY_DOUBLE'; - g_type_name_map( dbms_sql.bfile_type ) := 'BFILE'; - g_type_name_map( dbms_sql.binary_float_type ) := 'BINARY_FLOAT'; - g_type_name_map( dbms_sql.blob_type ) := 'BLOB'; - g_type_name_map( dbms_sql.long_raw_type ) := 'LONG RAW'; - g_type_name_map( dbms_sql.char_type ) := 'CHAR'; - g_type_name_map( dbms_sql.clob_type ) := 'CLOB'; - g_type_name_map( dbms_sql.long_type ) := 'LONG'; - g_type_name_map( dbms_sql.date_type ) := 'DATE'; - g_type_name_map( dbms_sql.interval_day_to_second_type ) := 'INTERVAL DAY TO SECOND'; - g_type_name_map( dbms_sql.interval_year_to_month_type ) := 'INTERVAL YEAR TO MONTH'; - g_type_name_map( dbms_sql.raw_type ) := 'RAW'; - g_type_name_map( dbms_sql.timestamp_type ) := 'TIMESTAMP'; - g_type_name_map( dbms_sql.timestamp_with_tz_type ) := 'TIMESTAMP WITH TIME ZONE'; - g_type_name_map( dbms_sql.timestamp_with_local_tz_type ) := 'TIMESTAMP WITH LOCAL TIME ZONE'; - g_type_name_map( dbms_sql.varchar2_type ) := 'VARCHAR2'; - g_type_name_map( dbms_sql.number_type ) := 'NUMBER'; - g_type_name_map( dbms_sql.rowid_type ) := 'ROWID'; - g_type_name_map( dbms_sql.urowid_type ) := 'UROWID'; - -end; -/ diff --git a/source/expectations/data_values/ut_curr_usr_compound_helper.pks b/source/expectations/data_values/ut_curr_usr_compound_helper.pks deleted file mode 100644 index d662f51f9..000000000 --- a/source/expectations/data_values/ut_curr_usr_compound_helper.pks +++ /dev/null @@ -1,13 +0,0 @@ -create or replace package ut_curr_usr_compound_helper authid current_user is - - procedure get_columns_info( - a_cursor in out nocopy sys_refcursor, - a_columns_info out nocopy xmltype, - a_join_by_info out nocopy xmltype, - a_contains_collection out nocopy number - ); - - function get_user_defined_type(a_owner varchar2, a_type_name varchar2) return xmltype; - -end; -/ diff --git a/source/expectations/data_values/ut_cursor_column.tpb b/source/expectations/data_values/ut_cursor_column.tpb new file mode 100644 index 000000000..a9fb6b0f4 --- /dev/null +++ b/source/expectations/data_values/ut_cursor_column.tpb @@ -0,0 +1,74 @@ +create or replace type body ut_cursor_column as + + member procedure init( + self in out nocopy ut_cursor_column, + a_col_name varchar2, a_col_schema_name varchar2, + a_col_type_name varchar2, a_col_max_len integer, a_parent_name varchar2 := null, a_hierarchy_level integer := 1, + a_col_position integer, a_col_type varchar2, a_collection integer,a_access_path in varchar2, a_col_precision in integer, + a_col_scale integer + ) is + begin + self.parent_name := a_parent_name; --Name of the parent if its nested + self.hierarchy_level := a_hierarchy_level; --Hierarchy level + self.column_position := a_col_position; --Position of the column in cursor/ type + self.column_len := a_col_max_len; --length of column + self.column_precision := a_col_precision; + self.column_scale := a_col_scale; + self.column_type_name := coalesce(a_col_type_name,a_col_type); --type name e.g. test_dummy_object or varchar2 + self.column_name := case when a_col_name is null and a_collection = 1 then + self.column_type_name + else TRIM( BOTH '''' FROM a_col_name) + end; --name of the column, however in nested object for collection name is not defined in cursor. + self.xml_valid_name := ut_utils.get_valid_xml_name(self.column_name); + self.display_path := case when a_access_path is null then + self.column_name + else + a_access_path||'/'||self.column_name + end; --Access path used for incldue exclude eg/ TEST_DUMMY_OBJECT/VARCHAR2 + self.access_path := case when a_access_path is null then + self.xml_valid_name + else + a_access_path||'/'||self.xml_valid_name + end; --Access path used for XMLTABLE query + self.filter_path := '/'||self.access_path; --Filter path will differ from access path in anydata type + --Transformed name needs to be build on full access path to avoid ambiguity when there is 3 or more levels of nesting. + self.transformed_name := case when length(self.xml_valid_name) > 30 then + '"'||ut_compound_data_helper.get_fixed_size_hash(self.access_path)||'"' + when self.parent_name is null then + '"'||self.xml_valid_name||'"' + else + '"'||ut_compound_data_helper.get_fixed_size_hash(self.access_path)||'"' + end; --when is nestd we need to hash name to make sure we dont exceed 30 char + self.column_type := a_col_type; --column type e.g. user_defined , varchar2 + self.column_schema := a_col_schema_name; -- schema name + self.is_sql_diffable := case + when lower(self.column_type) = 'user_defined_type' then + 0 + -- Due to bug in 11g/12.1 collection fails on varchar 4000+ + when (lower(self.column_type) in ('varchar2','char')) and (self.column_len > 4000) then + 0 + else + ut_utils.boolean_to_int(ut_compound_data_helper.is_sql_compare_allowed(self.column_type)) + end; --can we directly compare or do we need to hash value + self.is_collection := a_collection; + self.has_nested_col := case when lower(self.column_type) = 'user_defined_type' and self.is_collection = 0 then 1 else 0 end; + end; + + constructor function ut_cursor_column( self in out nocopy ut_cursor_column, + a_col_name varchar2, a_col_schema_name varchar2, + a_col_type_name varchar2, a_col_max_len integer, a_parent_name varchar2 := null, a_hierarchy_level integer := 1, + a_col_position integer, a_col_type in varchar2, a_collection integer,a_access_path in varchar2, a_col_precision in integer, + a_col_scale integer + ) return self as result is + begin + init(a_col_name, a_col_schema_name, a_col_type_name, a_col_max_len, a_parent_name,a_hierarchy_level, a_col_position, + a_col_type, a_collection,a_access_path,a_col_precision,a_col_scale); + return; + end; + + constructor function ut_cursor_column( self in out nocopy ut_cursor_column) return self as result is + begin + return; + end; +end; +/ diff --git a/source/expectations/data_values/ut_cursor_column.tps b/source/expectations/data_values/ut_cursor_column.tps new file mode 100644 index 000000000..77bf78f01 --- /dev/null +++ b/source/expectations/data_values/ut_cursor_column.tps @@ -0,0 +1,52 @@ +create or replace type ut_cursor_column authid current_user as object ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + */ + parent_name varchar2(4000), + access_path varchar2(4000), + filter_path varchar2(4000), + display_path varchar2(4000), + has_nested_col number(1,0), + transformed_name varchar2(2000), + hierarchy_level number, + column_position number, + xml_valid_name varchar2(2000), + column_name varchar2(2000), + column_type varchar2(128), + column_type_name varchar2(128), + column_schema varchar2(128), + column_len integer, + column_precision integer, + column_scale integer, + is_sql_diffable number(1, 0), + is_collection number(1, 0), + + member procedure init(self in out nocopy ut_cursor_column, + a_col_name varchar2, a_col_schema_name varchar2, + a_col_type_name varchar2, a_col_max_len integer, a_parent_name varchar2 := null, a_hierarchy_level integer := 1, + a_col_position integer, a_col_type in varchar2, a_collection integer,a_access_path in varchar2, a_col_precision in integer, + a_col_scale integer), + + constructor function ut_cursor_column( self in out nocopy ut_cursor_column, + a_col_name varchar2, a_col_schema_name varchar2, + a_col_type_name varchar2, a_col_max_len integer, a_parent_name varchar2 := null, a_hierarchy_level integer := 1, + a_col_position integer, a_col_type in varchar2, a_collection integer, a_access_path in varchar2, a_col_precision in integer, + a_col_scale integer) + return self as result, + + constructor function ut_cursor_column( self in out nocopy ut_cursor_column) return self as result +) +/ diff --git a/source/expectations/data_values/ut_cursor_column_tab.tps b/source/expectations/data_values/ut_cursor_column_tab.tps new file mode 100644 index 000000000..106023d96 --- /dev/null +++ b/source/expectations/data_values/ut_cursor_column_tab.tps @@ -0,0 +1,19 @@ +create or replace type ut_cursor_column_tab as + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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_cursor_column +/ \ No newline at end of file diff --git a/source/expectations/data_values/ut_cursor_details.tpb b/source/expectations/data_values/ut_cursor_details.tpb new file mode 100644 index 000000000..b823ff944 --- /dev/null +++ b/source/expectations/data_values/ut_cursor_details.tpb @@ -0,0 +1,260 @@ +create or replace type body ut_cursor_details as + + member function equals( a_other ut_cursor_details, a_match_options ut_matcher_options ) return boolean is + l_diffs integer; + begin + select /*+ no_parallel */ count(1) into l_diffs + from table(self.cursor_columns_info) a + full outer join table(a_other.cursor_columns_info) e + on decode(a.parent_name,e.parent_name,1,0)= 1 + and a.column_name = e.column_name + and replace(a.column_type,'VARCHAR2','CHAR') = replace(e.column_type,'VARCHAR2','CHAR') + and ( a.column_position = e.column_position or a_match_options.columns_are_unordered_flag = 1 ) + where a.column_name is null or e.column_name is null; + return l_diffs = 0; + end; + + member procedure desc_compound_data( + self in out nocopy ut_cursor_details, a_compound_data anytype, + a_parent_name in varchar2, a_level in integer, a_access_path in varchar2 + ) is + l_idx pls_integer := 1; + l_elements_info ut_metadata.t_anytype_members_rec; + l_element_info ut_metadata.t_anytype_elem_info_rec; + l_is_collection boolean; + begin + l_elements_info := ut_metadata.get_anytype_members_info( a_compound_data ); + l_is_collection := ut_metadata.is_collection(l_elements_info.type_code); + if l_elements_info.elements_count is null then + l_element_info := ut_metadata.get_attr_elem_info( a_compound_data ); + self.cursor_columns_info.extend; + self.cursor_columns_info(cursor_columns_info.last) := + ut_cursor_column( + l_elements_info.type_name, + l_elements_info.schema_name, + null, + l_elements_info.length, + a_parent_name, + a_level, + l_idx, + ut_compound_data_helper.get_column_type_desc(l_elements_info.type_code,false), + ut_utils.boolean_to_int(l_is_collection), + a_access_path, + l_elements_info.precision, + l_elements_info.scale + ); + if l_element_info.attr_elt_type is not null then + desc_compound_data( + l_element_info.attr_elt_type, l_elements_info.type_name, + a_level + 1, a_access_path || '/' || l_elements_info.type_name + ); + end if; + else + while l_idx <= l_elements_info.elements_count loop + l_element_info := ut_metadata.get_attr_elem_info( a_compound_data, l_idx ); + + self.cursor_columns_info.extend; + self.cursor_columns_info(cursor_columns_info.last) := + ut_cursor_column( + l_element_info.attribute_name, + l_elements_info.schema_name, + null, + l_element_info.length, + a_parent_name, + a_level, + l_idx, + ut_compound_data_helper.get_column_type_desc(l_element_info.type_code,false), + ut_utils.boolean_to_int(l_is_collection), + a_access_path, + l_elements_info.precision, + l_elements_info.scale + ); + if l_element_info.attr_elt_type is not null then + desc_compound_data( + l_element_info.attr_elt_type, l_element_info.attribute_name, + a_level + 1, a_access_path || '/' || l_element_info.attribute_name + ); + end if; + l_idx := l_idx + 1; + end loop; + end if; + end; + + constructor function ut_cursor_details(self in out nocopy ut_cursor_details) return self as result is + begin + self.cursor_columns_info := ut_cursor_column_tab(); + return; + end; + + constructor function ut_cursor_details( + self in out nocopy ut_cursor_details, + a_cursor_number in number + ) return self as result is + l_columns_count pls_integer; + $if dbms_db_version.version = 12 and dbms_db_version.release = 1 or dbms_db_version.version < 12 $then + l_columns_desc dbms_sql.desc_tab3; + $else + l_columns_desc dbms_sql.desc_tab4; + $end + l_is_collection boolean; + l_hierarchy_level integer := 1; + begin + self.cursor_columns_info := ut_cursor_column_tab(); + self.is_anydata := 0; + dbms_sql.describe_columns3(a_cursor_number, l_columns_count, l_columns_desc); + + /** + * Due to a bug with object being part of cursor in ANYDATA scenario + * oracle fails to revert number to cursor. We ar using dbms_sql.close cursor to close it + * to avoid leaving open cursors behind. + * a_cursor := dbms_sql.to_refcursor(l_cursor_number); + **/ + for pos in 1 .. l_columns_count loop + l_is_collection := ut_metadata.is_collection( l_columns_desc(pos).col_schema_name, l_columns_desc(pos).col_type_name ); + self.cursor_columns_info.extend; + self.cursor_columns_info(self.cursor_columns_info.last) := + ut_cursor_column( + l_columns_desc(pos).col_name, + l_columns_desc(pos).col_schema_name, + l_columns_desc(pos).col_type_name, + l_columns_desc(pos).col_max_len, + null, + l_hierarchy_level, + pos, + ut_compound_data_helper.get_column_type_desc(l_columns_desc(pos).col_type,true), + ut_utils.boolean_to_int(l_is_collection), + null, + l_columns_desc(pos).col_precision, + l_columns_desc(pos).col_scale + ); + + if l_columns_desc(pos).col_type = dbms_sql.user_defined_type or l_is_collection then + desc_compound_data( + ut_metadata.get_user_defined_type( l_columns_desc(pos).col_schema_name, l_columns_desc(pos).col_type_name ), + l_columns_desc(pos).col_name, + l_hierarchy_level + 1, + l_columns_desc(pos).col_name + ); + end if; + end loop; + return; + end; + + member function contains_collection return boolean is + l_collection_elements number; + begin + select /*+ no_parallel */ count(1) into l_collection_elements + from table(cursor_columns_info) c + where c.is_collection = 1 and rownum = 1; + return l_collection_elements > 0; + end; + + member function get_missing_join_by_columns( a_expected_columns ut_varchar2_list ) return ut_varchar2_list is + l_result ut_varchar2_list; + begin + --regexp_replace(c.access_path,'^\/?([^\/]+\/){1}') + select /*+ no_parallel */ fl.column_value + bulk collect into l_result + from table(a_expected_columns) fl + where not exists ( + select 1 from table(self.cursor_columns_info) c + where regexp_like(c.filter_path,'^/?'||fl.column_value||'($|/.*)' ) + ) + order by fl.column_value; + return l_result; + end; + + member procedure filter_columns(self in out nocopy ut_cursor_details, a_match_options ut_matcher_options) is + l_result ut_cursor_details := self; + l_column_tab ut_cursor_column_tab := ut_cursor_column_tab(); + l_column ut_cursor_column; + c_xpath_extract_reg constant varchar2(50) := '^((/ROW/)|^(//)|^(/\*/))?(.*)'; + begin + if l_result.cursor_columns_info is not null then + + --limit columns to those on the include items minus exclude items + if a_match_options.include.items.count > 0 then + -- if include - exclude = 0 then keep all columns + if a_match_options.include.items != a_match_options.exclude.items then + with included_columns as ( + select regexp_replace( column_value, c_xpath_extract_reg, '\5' ) col_names + from table(a_match_options.include.items) + minus + select regexp_replace( column_value, c_xpath_extract_reg, '\5' ) col_names + from table(a_match_options.exclude.items) + ) + select /*+ no_parallel */ value(x) + bulk collect into l_result.cursor_columns_info + from table(self.cursor_columns_info) x + where exists( + select 1 from included_columns f where regexp_like(x.filter_path,'^/?'||f.col_names||'($|/.*)' ) + ) + or x.hierarchy_level = case when self.is_anydata = 1 then 1 else 0 end ; + end if; + elsif a_match_options.exclude.items.count > 0 then + with excluded_columns as ( + select regexp_replace( column_value, c_xpath_extract_reg, '\5' ) col_names + from table(a_match_options.exclude.items) + ) + select /*+ no_parallel */ value(x) + bulk collect into l_result.cursor_columns_info + from table(self.cursor_columns_info) x + where not exists( + select 1 from excluded_columns f where regexp_like(x.filter_path,'^/?'||f.col_names||'($|/.*)' ) + ); + end if; + + --Rewrite column order after columns been excluded + for i in ( + select /*+ no_parallel */ parent_name, access_path, display_path, has_nested_col, + transformed_name, hierarchy_level, + rownum as new_position, xml_valid_name, + column_name, column_type, column_type_name, column_schema, + column_len, column_precision ,column_scale ,is_sql_diffable, is_collection,value(x) col_info + from table(l_result.cursor_columns_info) x + order by x.column_position asc + ) loop + l_column := i.col_info; + l_column.column_position := i.new_position; + l_column_tab.extend; + l_column_tab(l_column_tab.last) := l_column; + end loop; + + l_result.cursor_columns_info := l_column_tab; + self := l_result; + end if; + end; + + member function get_xml_children(a_parent_name varchar2 := null) return xmltype is + l_result xmltype; + begin + select /*+ no_parallel */ xmlagg(xmlelement(evalname t.column_name,t.column_type_name)) + into l_result + from table(self.cursor_columns_info) t + where (a_parent_name is null and parent_name is null and hierarchy_level = 1 and column_name is not null) + having count(*) > 0; + return l_result; + end; + + member function get_root return varchar2 is + l_root varchar2(250); + begin + if self.cursor_columns_info.count > 0 then + select /*+ no_parallel */ x.access_path into l_root from table(self.cursor_columns_info) x + where x.hierarchy_level = 1; + else + l_root := null; + end if; + return l_root; + end; + + member procedure strip_root_from_anydata(self in out nocopy ut_cursor_details) is + l_root varchar2(250) := get_root(); + begin + self.is_anydata := 1; + for i in 1..cursor_columns_info.count loop + self.cursor_columns_info(i).filter_path := '/'||ut_utils.strip_prefix(self.cursor_columns_info(i).access_path,l_root); + end loop; + end; +end; +/ diff --git a/source/expectations/data_values/ut_cursor_details.tps b/source/expectations/data_values/ut_cursor_details.tps new file mode 100644 index 000000000..e7f9405eb --- /dev/null +++ b/source/expectations/data_values/ut_cursor_details.tps @@ -0,0 +1,41 @@ +create or replace type ut_cursor_details authid current_user as object ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + */ + cursor_columns_info ut_cursor_column_tab, + + /*if type is anydata we need to skip level 1 on joinby / inlude / exclude as its artificial cursor*/ + is_anydata number(1,0), + constructor function ut_cursor_details(self in out nocopy ut_cursor_details) return self as result, + constructor function ut_cursor_details( + self in out nocopy ut_cursor_details,a_cursor_number in number + ) return self as result, + member function equals(a_other ut_cursor_details, a_match_options ut_matcher_options) return boolean, + member procedure desc_compound_data( + self in out nocopy ut_cursor_details, + a_compound_data anytype, + a_parent_name in varchar2, + a_level in integer, + a_access_path in varchar2 + ), + member function contains_collection return boolean, + member function get_missing_join_by_columns( a_expected_columns ut_varchar2_list ) return ut_varchar2_list, + member procedure filter_columns(self in out nocopy ut_cursor_details, a_match_options ut_matcher_options), + member function get_xml_children(a_parent_name varchar2 := null) return xmltype, + member function get_root return varchar2, + member procedure strip_root_from_anydata(self in out nocopy ut_cursor_details) +) +/ diff --git a/source/expectations/data_values/ut_data_value.tpb b/source/expectations/data_values/ut_data_value.tpb index 4237ba040..6b1763dd0 100644 --- a/source/expectations/data_values/ut_data_value.tpb +++ b/source/expectations/data_values/ut_data_value.tpb @@ -1,7 +1,7 @@ create or replace type body ut_data_value as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -30,7 +30,7 @@ create or replace type body ut_data_value as raise value_error; end; - member function diff( a_other ut_data_value, a_exclude_xpath varchar2, a_include_xpath varchar2, a_join_by_xpath varchar2, a_unordered boolean :=false ) return varchar2 is + member function diff( a_other ut_data_value, a_match_options ut_matcher_options ) return varchar2 is begin return null; end; @@ -59,7 +59,7 @@ create or replace type body ut_data_value as l_result := l_result || chr(10); end if; else - l_result := self.to_string() || ' ' || l_info || ' '; + l_result := self.to_string() || ' ' || l_info; end if; return l_result; end; diff --git a/source/expectations/data_values/ut_data_value.tps b/source/expectations/data_values/ut_data_value.tps index 793a25942..beda3d911 100644 --- a/source/expectations/data_values/ut_data_value.tps +++ b/source/expectations/data_values/ut_data_value.tps @@ -1,7 +1,7 @@ create or replace type ut_data_value force authid current_user as object ( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ create or replace type ut_data_value force authid current_user as object ( limitations under the License. */ data_type varchar2(250 char), + data_type_plsql varchar2(250 char), self_type varchar2(250 char), not instantiable member function is_null return boolean, not instantiable member function to_string return varchar2, @@ -25,7 +26,7 @@ create or replace type ut_data_value force authid current_user as object ( order member function compare( a_other ut_data_value ) return integer, member function is_diffable return boolean, member function is_empty return boolean, - member function diff( a_other ut_data_value, a_exclude_xpath varchar2, a_include_xpath varchar2, a_join_by_xpath varchar2, a_unordered boolean := false ) return varchar2, + member function diff( a_other ut_data_value, a_match_options ut_matcher_options ) return varchar2, not instantiable member function compare_implementation( a_other ut_data_value ) return integer ) not final not instantiable / diff --git a/source/expectations/data_values/ut_data_value_anydata.tpb b/source/expectations/data_values/ut_data_value_anydata.tpb index 7d5322cca..f6fbdc840 100644 --- a/source/expectations/data_values/ut_data_value_anydata.tpb +++ b/source/expectations/data_values/ut_data_value_anydata.tpb @@ -1,7 +1,7 @@ create or replace type body ut_data_value_anydata as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -14,65 +14,129 @@ create or replace type body ut_data_value_anydata as 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. - */ - - final member procedure init(self in out nocopy ut_data_value_anydata, a_value anydata, a_data_object_type varchar2, a_extract_path varchar2) is - l_query sys_refcursor; - l_ctx number; - l_ut_owner varchar2(250) := ut_utils.ut_owner; + */ + + overriding member function get_object_info return varchar2 is begin - self.data_type := case when a_value is not null then lower(a_value.gettypename) else 'undefined' end; - self.data_id := sys_guid(); - if a_value is not null then - execute immediate ' + return self.data_type || case when self.compound_type = 'collection' then self.get_elements_count_info() end; + end; + + member function get_extract_path(a_data_value anydata) return varchar2 is + l_path varchar2(10); + begin + if self.compound_type = 'object' then + l_path := '/*/*'; + else + case when ut_metadata.has_collection_members(a_data_value) then + l_path := '/*/*'; + else + l_path := '/*'; + end case; + end if; + return l_path; + end; + + member function get_cursor_sql_from_anydata(a_data_value anydata) return varchar2 is + l_cursor_sql varchar2(32767); + begin + l_cursor_sql := ' declare l_data '||self.data_type||'; l_value anydata := :a_value; l_status integer; + l_tmp_refcursor sys_refcursor; begin - l_status := l_value.get'||a_data_object_type||'(l_data); - :l_data_is_null := case when l_data is null then 1 else 0 end; - end;' using in a_value, out self.is_data_null; - else - self.is_data_null := 1; - end if; + l_status := l_value.get'||self.compound_type||'(l_data); '|| + case when self.compound_type = 'collection' then + q'[ open :l_tmp_refcursor for select /*+ no_parallel */ value(x) as "]'|| + ut_metadata.get_object_name(ut_metadata.get_collection_element(a_data_value))|| + q'[" from table(l_data) x;]' + else + q'[ open :l_tmp_refcursor for select /*+ no_parallel */ l_data as "]'||ut_metadata.get_object_name(self.data_type)|| + q'[" from dual;]' + end || + 'end;'; + return l_cursor_sql; + end; + + member procedure init(self in out nocopy ut_data_value_anydata, a_value anydata) is + l_refcursor sys_refcursor; + cursor_not_open exception; + l_cursor_number number; + l_anydata_sql varchar2(32767); + begin + self.data_type := ut_metadata.get_anydata_typename(a_value); + self.compound_type := get_instance(a_value); + self.is_data_null := ut_metadata.is_anytype_null(a_value,self.compound_type); + self.data_id := sys_guid(); + self.self_type := $$plsql_unit; + self.cursor_details := ut_cursor_details(); + + ut_compound_data_helper.cleanup_diff; + if not self.is_null() then - ut_expectation_processor.set_xml_nls_params(); - open l_query for select a_value val from dual; - l_ctx := sys.dbms_xmlgen.newcontext( l_query ); - dbms_xmlgen.setrowtag(l_ctx, ''); - dbms_xmlgen.setrowsettag(l_ctx, ''); - dbms_xmlgen.setnullhandling(l_ctx,2); - execute immediate - 'insert into ' || l_ut_owner || '.ut_compound_data_tmp(data_id, item_no, item_data) ' || - 'select :self_guid, rownum, value(a) ' || - ' from table( xmlsequence( extract(:l_xml, :xpath ) ) ) a' - using in self.data_id, dbms_xmlgen.getXMLtype(l_ctx), a_extract_path; - self.elements_count := sql%rowcount; - dbms_xmlgen.closecontext (l_ctx); - ut_expectation_processor.reset_nls_params(); + self.extract_path := get_extract_path(a_value); + l_anydata_sql := get_cursor_sql_from_anydata(a_value); + execute immediate l_anydata_sql using in a_value, in out l_refcursor; + if l_refcursor%isopen then + self.extract_cursor(l_refcursor); + l_cursor_number := dbms_sql.to_cursor_number(l_refcursor); + self.cursor_details := ut_cursor_details(l_cursor_number); + self.cursor_details.strip_root_from_anydata; + dbms_sql.close_cursor(l_cursor_number); + elsif not l_refcursor%isopen then + raise cursor_not_open; + end if; end if; + exception + when cursor_not_open then + raise_application_error(-20155, 'Cursor is not open'); + when others then + if l_refcursor%isopen then + close l_refcursor; + end if; + raise; end; - static function get_instance(a_data_value anydata) return ut_data_value_anydata is - l_result ut_data_value_anydata := ut_data_value_object(null); - l_type anytype; - l_type_code integer; + member function get_instance(a_data_value anydata) return varchar2 is + l_result varchar2(30); begin - if a_data_value is not null then - l_type_code := a_data_value.gettype(l_type); - if l_type_code in (dbms_types.typecode_table, dbms_types.typecode_varray, dbms_types.typecode_namedcollection, dbms_types.typecode_object) then - if l_type_code = dbms_types.typecode_object then - l_result := ut_data_value_object(a_data_value); - else - l_result := ut_data_value_collection(a_data_value); - end if; - else - raise_application_error(-20000, 'Data type '||a_data_value.gettypename||' in ANYDATA is not supported by utPLSQL'); - end if; + l_result := ut_metadata.get_anydata_compound_type(a_data_value); + if l_result not in ('object','collection') then + raise_application_error(-20000, 'Data type '||a_data_value.gettypename||' in ANYDATA is not supported by utPLSQL'); end if; return l_result; end; + constructor function ut_data_value_anydata(self in out nocopy ut_data_value_anydata, a_value anydata) return self as result + is + begin + init(a_value); + return; + end; + + overriding member function compare_implementation( + a_other ut_data_value, + a_match_options ut_matcher_options, + a_inclusion_compare boolean := false, + a_is_negated boolean := false + ) return integer is + l_result integer := 0; + begin + if not a_other is of (ut_data_value_anydata) then + raise value_error; + end if; + l_result := l_result + (self as ut_data_value_refcursor).compare_implementation(a_other,a_match_options,a_inclusion_compare,a_is_negated); + return l_result; + end; + + overriding member function is_empty return boolean is + begin + if self.compound_type = 'collection' then + return self.elements_count = 0; + else + raise value_error; + end if; + end; end; / diff --git a/source/expectations/data_values/ut_data_value_anydata.tps b/source/expectations/data_values/ut_data_value_anydata.tps index caabe36b6..60dba5515 100644 --- a/source/expectations/data_values/ut_data_value_anydata.tps +++ b/source/expectations/data_values/ut_data_value_anydata.tps @@ -1,7 +1,7 @@ -create or replace type ut_data_value_anydata under ut_compound_data_value( +create or replace type ut_data_value_anydata under ut_data_value_refcursor( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -15,8 +15,19 @@ create or replace type ut_data_value_anydata under ut_compound_data_value( See the License for the specific language governing permissions and limitations under the License. */ - - final member procedure init(self in out nocopy ut_data_value_anydata, a_value anydata, a_data_object_type varchar2, a_extract_path varchar2), - static function get_instance(a_data_value anydata) return ut_data_value_anydata -) not final not instantiable + + overriding member function get_object_info return varchar2, + member function get_extract_path(a_data_value anydata) return varchar2, + member function get_cursor_sql_from_anydata(a_data_value anydata) return varchar2, + member procedure init(self in out nocopy ut_data_value_anydata, a_value anydata), + member function get_instance(a_data_value anydata) return varchar2, + constructor function ut_data_value_anydata(self in out nocopy ut_data_value_anydata, a_value anydata) return self as result, + overriding member function compare_implementation( + a_other ut_data_value, + a_match_options ut_matcher_options, + a_inclusion_compare boolean := false, + a_is_negated boolean := false + ) return integer, + overriding member function is_empty return boolean +) / diff --git a/source/expectations/data_values/ut_data_value_blob.tpb b/source/expectations/data_values/ut_data_value_blob.tpb index c597af023..e145a8d4f 100644 --- a/source/expectations/data_values/ut_data_value_blob.tpb +++ b/source/expectations/data_values/ut_data_value_blob.tpb @@ -1,7 +1,7 @@ create or replace type body ut_data_value_blob as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ create or replace type body ut_data_value_blob as self.data_value := a_value; self.self_type := $$plsql_unit; self.data_type := 'blob'; + self.data_type_plsql := 'blob'; return; end; diff --git a/source/expectations/data_values/ut_data_value_blob.tps b/source/expectations/data_values/ut_data_value_blob.tps index ed6aa2afe..6df3f3273 100644 --- a/source/expectations/data_values/ut_data_value_blob.tps +++ b/source/expectations/data_values/ut_data_value_blob.tps @@ -1,7 +1,7 @@ create or replace type ut_data_value_blob under ut_data_value( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/data_values/ut_data_value_boolean.tpb b/source/expectations/data_values/ut_data_value_boolean.tpb index bc8c1e2f9..867c3c19c 100644 --- a/source/expectations/data_values/ut_data_value_boolean.tpb +++ b/source/expectations/data_values/ut_data_value_boolean.tpb @@ -1,7 +1,7 @@ create or replace type body ut_data_value_boolean as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ create or replace type body ut_data_value_boolean as self.data_value := ut_utils.boolean_to_int(a_value); self.self_type := $$plsql_unit; self.data_type := 'boolean'; + self.data_type_plsql := 'boolean'; return; end; diff --git a/source/expectations/data_values/ut_data_value_boolean.tps b/source/expectations/data_values/ut_data_value_boolean.tps index 62b413e10..e25b6e0fd 100644 --- a/source/expectations/data_values/ut_data_value_boolean.tps +++ b/source/expectations/data_values/ut_data_value_boolean.tps @@ -1,7 +1,7 @@ create or replace type ut_data_value_boolean under ut_data_value( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/data_values/ut_data_value_clob.tpb b/source/expectations/data_values/ut_data_value_clob.tpb index 7b7c7ffd8..f8a53a035 100644 --- a/source/expectations/data_values/ut_data_value_clob.tpb +++ b/source/expectations/data_values/ut_data_value_clob.tpb @@ -1,7 +1,7 @@ create or replace type body ut_data_value_clob as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ create or replace type body ut_data_value_clob as self.data_value := a_value; self.self_type := $$plsql_unit; self.data_type := 'clob'; + self.data_type_plsql := 'clob'; return; end; diff --git a/source/expectations/data_values/ut_data_value_clob.tps b/source/expectations/data_values/ut_data_value_clob.tps index 4212efb3c..6869798d1 100644 --- a/source/expectations/data_values/ut_data_value_clob.tps +++ b/source/expectations/data_values/ut_data_value_clob.tps @@ -1,7 +1,7 @@ create or replace type ut_data_value_clob under ut_data_value( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/data_values/ut_data_value_collection.tpb b/source/expectations/data_values/ut_data_value_collection.tpb deleted file mode 100644 index 15298c801..000000000 --- a/source/expectations/data_values/ut_data_value_collection.tpb +++ /dev/null @@ -1,45 +0,0 @@ -create or replace type body ut_data_value_collection 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. - */ - - constructor function ut_data_value_collection(self in out nocopy ut_data_value_collection, a_value anydata) return self as result is - begin - self.self_type := $$plsql_unit; - self.init(a_value, 'collection', '/*/*/*'); - if a_value is not null then - execute immediate ' - declare - l_data '||a_value.gettypename()||'; - l_value anydata := :a_value; - l_status integer; - begin - l_status := l_value.getCollection(l_data); - if l_data is not null then - :l_count := l_data.count; - end if; - end;' using in a_value, out self.elements_count; - end if; - return; - end; - - overriding member function is_empty return boolean is - begin - return self.elements_count = 0; - end; - -end; -/ diff --git a/source/expectations/data_values/ut_data_value_date.tpb b/source/expectations/data_values/ut_data_value_date.tpb index 727f624d4..20424d193 100644 --- a/source/expectations/data_values/ut_data_value_date.tpb +++ b/source/expectations/data_values/ut_data_value_date.tpb @@ -1,7 +1,7 @@ create or replace type body ut_data_value_date as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ create or replace type body ut_data_value_date as self.data_value := a_value; self.self_type := $$plsql_unit; self.data_type := 'date'; + self.data_type_plsql := 'date'; return; end; diff --git a/source/expectations/data_values/ut_data_value_date.tps b/source/expectations/data_values/ut_data_value_date.tps index e1c358789..f64a577e0 100644 --- a/source/expectations/data_values/ut_data_value_date.tps +++ b/source/expectations/data_values/ut_data_value_date.tps @@ -1,7 +1,7 @@ create or replace type ut_data_value_date under ut_data_value( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/data_values/ut_data_value_dsinterval.tpb b/source/expectations/data_values/ut_data_value_dsinterval.tpb index 6b49a5d1c..026d4970f 100644 --- a/source/expectations/data_values/ut_data_value_dsinterval.tpb +++ b/source/expectations/data_values/ut_data_value_dsinterval.tpb @@ -1,7 +1,7 @@ create or replace type body ut_data_value_dsinterval as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ create or replace type body ut_data_value_dsinterval as self.data_value := a_value; self.self_type := $$plsql_unit; self.data_type := 'interval day to second'; + self.data_type_plsql := 'dsinterval_unconstrained'; return; end; @@ -31,7 +32,7 @@ create or replace type body ut_data_value_dsinterval as overriding member function to_string return varchar2 is begin - return ut_utils.to_string(self.data_value); + return ut_utils.interval_to_text(self.data_value); end; overriding member function compare_implementation(a_other ut_data_value) return integer is diff --git a/source/expectations/data_values/ut_data_value_dsinterval.tps b/source/expectations/data_values/ut_data_value_dsinterval.tps index 2d3ad48f0..6f5cb708c 100644 --- a/source/expectations/data_values/ut_data_value_dsinterval.tps +++ b/source/expectations/data_values/ut_data_value_dsinterval.tps @@ -1,7 +1,7 @@ create or replace type ut_data_value_dsinterval under ut_data_value( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ create or replace type ut_data_value_dsinterval under ut_data_value( See the License for the specific language governing permissions and limitations under the License. */ - data_value dsinterval_unconstrained, + data_value interval day(9) to second(9), constructor function ut_data_value_dsinterval(self in out nocopy ut_data_value_dsinterval, a_value dsinterval_unconstrained) return self as result, overriding member function is_null return boolean, overriding member function to_string return varchar2, diff --git a/source/expectations/data_values/ut_data_value_json.tpb b/source/expectations/data_values/ut_data_value_json.tpb new file mode 100644 index 000000000..b703af181 --- /dev/null +++ b/source/expectations/data_values/ut_data_value_json.tpb @@ -0,0 +1,174 @@ +create or replace type body ut_data_value_json as + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + */ + + member procedure init (self in out nocopy ut_data_value_json, a_value json_element_t) is + begin + self.is_data_null := case when a_value is null then 1 else 0 end; + self.data_value := case when a_value is null then null else a_value.to_clob end; + self.self_type := $$plsql_unit; + self.data_type := 'json'; + self.json_tree := ut_json_tree_details(a_value); + self.data_id := sys_guid(); + end; + + constructor function ut_data_value_json(self in out nocopy ut_data_value_json, a_value json_element_t) return self as result is + begin + init(a_value); + return; + end; + + constructor function ut_data_value_json(self in out nocopy ut_data_value_json, a_value json) return self as result is + l_value json_element_t := ut_compound_data_helper.get_json_object(a_value); + begin + init(l_value); + return; + end; + + overriding member function is_null return boolean is + begin + return (ut_utils.int_to_boolean(self.is_data_null)); + end; + + overriding member function is_empty return boolean is + begin + return self.data_value = '{}'; + end; + + overriding member function to_string return varchar2 is + begin + return ut_utils.to_string(self.data_value); + end; + + overriding member function diff( a_other ut_data_value, a_match_options ut_matcher_options ) return varchar2 is + l_result clob; + l_results ut_utils.t_clob_tab := ut_utils.t_clob_tab(); + l_result_string varchar2(32767); + l_other ut_data_value_json; + l_self ut_data_value_json := self; + l_diff_id ut_utils.t_hash; + c_max_rows integer := ut_utils.gc_diff_max_rows; + l_diffs ut_compound_data_helper.tt_json_diff_tab; + l_message varchar2(32767); + + function get_diff_by_type(a_diff_id raw) return clob is + l_diff_summary ut_compound_data_helper.tt_json_diff_type_tab := ut_compound_data_helper.get_json_diffs_type(a_diff_id); + l_message_list ut_varchar2_list := ut_varchar2_list(); + begin + for i in 1..l_diff_summary.count loop + l_message_list.extend; + l_message_list(l_message_list.last) := l_diff_summary(i).no_of_occurence||' '||l_diff_summary(i).difference_type; + end loop; + return ut_utils.table_to_clob(l_message_list,', '); + end; + + function get_json_diff_text (a_json_diff ut_compound_data_helper.t_json_diff_rec) return clob is + begin + return + case + when a_json_diff.difference_type = ut_compound_data_helper.gc_json_missing + then + case + when a_json_diff.act_element_name is not null then q'[ Missing property: ]'||a_json_diff.act_element_name + when a_json_diff.exp_element_name is not null then q'[ Extra property: ]'||a_json_diff.exp_element_name + end || ' on path: '||nvl(a_json_diff.act_parent_path,a_json_diff.exp_parent_path) + else + case + when a_json_diff.difference_type = ut_compound_data_helper.gc_json_type + then q'[ Actual type: ']'||a_json_diff.act_json_type||q'[' was expected to be: ']'||a_json_diff.exp_json_type||q'[']' + when a_json_diff.difference_type = ut_compound_data_helper.gc_json_notequal + then q'[ Actual value: ]'||a_json_diff.act_element_value||q'[ was expected to be: ]'||a_json_diff.exp_element_value + end || ' on path: '||nvl(a_json_diff.act_access_path,a_json_diff.exp_access_path) + end; + end; + + begin + if not a_other is of (ut_data_value_json) then + raise value_error; + end if; + dbms_lob.createtemporary(l_result, true); + l_other := treat(a_other as ut_data_value_json); + l_diff_id := ut_utils.get_hash(self.data_id||l_other.data_id); + + if not l_self.is_null and not l_other.is_null then + l_diffs := ut_compound_data_helper.get_json_diffs_tmp(l_diff_id); + + l_message := ' '||l_diffs.count|| ' differences found' || + case when l_diffs.count > c_max_rows then ', showing first '|| c_max_rows else null end||chr(10); + ut_utils.append_to_clob( l_result, l_message ); + l_message := get_diff_by_type(l_diff_id)||chr(10); + ut_utils.append_to_clob( l_result, l_message ); + + for i in 1 .. least( c_max_rows, l_diffs.count ) loop + l_results.extend; + l_results(l_results.last) := get_json_diff_text(l_diffs(i)); + end loop; + ut_utils.append_to_clob(l_result, l_results); + + end if; + + if l_result != empty_clob() then + l_result_string := chr(10) || 'Diff:' || ut_utils.to_string(l_result,null); + end if; + dbms_lob.freetemporary(l_result); + return l_result_string; + end; + + overriding member function compare_implementation(a_other ut_data_value) return integer is + l_self ut_data_value_json := self; + l_other ut_data_value := a_other; + begin + return l_self.compare_implementation( l_other, null ); + end; + + member function compare_implementation(a_other in ut_data_value,a_match_options ut_matcher_options) return + integer is + l_result integer; + l_other ut_data_value_json; + l_diff_id ut_utils.t_hash; + begin + if a_other is of (ut_data_value_json) then + l_other := treat(a_other as ut_data_value_json); + l_diff_id := ut_utils.get_hash(self.data_id||l_other.data_id); + l_result := + case + when ut_compound_data_helper.insert_json_diffs( + l_diff_id, l_other.json_tree.json_tree_info, self.json_tree.json_tree_info + ) > 0 then 1 + else 0 + end; + end if; + return l_result; + end; + + member function get_elements_count return integer is + begin + return json_element_t.parse(self.data_value).get_size; + end; + + member function get_json_count_info return varchar2 is + begin + return self.data_type||' [ count = '||self.get_elements_count||' ]'; + end; + + overriding member function get_object_info return varchar2 is + begin + return self.data_type; + end; + +end; +/ diff --git a/source/expectations/data_values/ut_data_value_json.tps b/source/expectations/data_values/ut_data_value_json.tps new file mode 100644 index 000000000..3b77e54eb --- /dev/null +++ b/source/expectations/data_values/ut_data_value_json.tps @@ -0,0 +1,33 @@ +create or replace type ut_data_value_json under ut_compound_data_value( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + */ + data_value clob, + json_tree ut_json_tree_details, + member procedure init (self in out nocopy ut_data_value_json, a_value json_element_t), + constructor function ut_data_value_json(self in out nocopy ut_data_value_json, a_value json_element_t) return self as result, + constructor function ut_data_value_json(self in out nocopy ut_data_value_json, a_value json) return self as result, + overriding member function is_null return boolean, + overriding member function is_empty return boolean, + overriding member function to_string return varchar2, + overriding member function diff( a_other ut_data_value, a_match_options ut_matcher_options ) return varchar2, + overriding member function compare_implementation(a_other ut_data_value) return integer, + member function compare_implementation(a_other ut_data_value,a_match_options ut_matcher_options) return integer, + member function get_elements_count return integer, + member function get_json_count_info return varchar2, + overriding member function get_object_info return varchar2 +) +/ diff --git a/source/expectations/data_values/ut_data_value_number.tpb b/source/expectations/data_values/ut_data_value_number.tpb index cbd524f42..382e6e9aa 100644 --- a/source/expectations/data_values/ut_data_value_number.tpb +++ b/source/expectations/data_values/ut_data_value_number.tpb @@ -1,7 +1,7 @@ create or replace type body ut_data_value_number as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ create or replace type body ut_data_value_number as self.data_value := a_value; self.self_type := $$plsql_unit; self.data_type := 'number'; + self.data_type_plsql := 'number'; return; end; diff --git a/source/expectations/data_values/ut_data_value_number.tps b/source/expectations/data_values/ut_data_value_number.tps index 674dd89fe..86d68f356 100644 --- a/source/expectations/data_values/ut_data_value_number.tps +++ b/source/expectations/data_values/ut_data_value_number.tps @@ -1,7 +1,7 @@ create or replace type ut_data_value_number under ut_data_value( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/data_values/ut_data_value_refcursor.tpb b/source/expectations/data_values/ut_data_value_refcursor.tpb index 1c7619be0..a4f0cf7a0 100644 --- a/source/expectations/data_values/ut_data_value_refcursor.tpb +++ b/source/expectations/data_values/ut_data_value_refcursor.tpb @@ -1,7 +1,7 @@ create or replace type body ut_data_value_refcursor as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -15,87 +15,105 @@ create or replace type body ut_data_value_refcursor as See the License for the specific language governing permissions and limitations under the License. */ - - constructor function ut_data_value_refcursor(self in out nocopy ut_data_value_refcursor, a_value sys_refcursor) return self as result is + + constructor function ut_data_value_refcursor(self in out nocopy ut_data_value_refcursor, a_value sys_refcursor) + return self as result is begin init(a_value); return; end; - member procedure init(self in out nocopy ut_data_value_refcursor, a_value sys_refcursor) is - c_bulk_rows constant integer := 1000; + member procedure extract_cursor(self in out nocopy ut_data_value_refcursor, a_value sys_refcursor) + is + c_bulk_rows constant integer := 10000; l_cursor sys_refcursor := a_value; - l_ctx number; - l_xml xmltype; - l_current_date_format varchar2(4000); - cursor_not_open exception; - l_ut_owner varchar2(250) := ut_utils.ut_owner; + l_ctx number; + l_xml xmltype; + l_ut_owner varchar2(250) := ut_utils.ut_owner; + l_set_id integer := 0; + l_elements_count number := 0; + begin + -- We use DBMS_XMLGEN in order to: + -- 1) be able to process data in bulks (set of rows) + -- 2) be able to influence the ROWSET/ROW tags + -- 3) be able to influence the way NULL values are handled (empty TAG) + -- 4) be able to influence the way TIMESTAMP is formatted. + -- Due to Oracle feature/bug, it is not possible to change the DATE formatting of cursor data + -- AFTER the cursor was opened. + -- The only solution for this is to change NLS settings before opening the cursor. + -- + -- This would work fine if we could use DBMS_XMLGEN.restartQuery. + -- The restartQuery fails however if PLSQL variables of TIMESTAMP/INTERVAL or CLOB/BLOB are used. + ut_expectation_processor.set_xml_nls_params(); + l_ctx := dbms_xmlgen.newContext(l_cursor); + dbms_xmlgen.setNullHandling(l_ctx, dbms_xmlgen.empty_tag); + dbms_xmlgen.setMaxRows(l_ctx, c_bulk_rows); + loop + l_xml := dbms_xmlgen.getxmltype(l_ctx); + exit when dbms_xmlgen.getNumRowsProcessed(l_ctx) = 0; + --Bug in oracle 12.2+ where XML binary storage trimming insignificant whitespaces. + $if dbms_db_version.version = 12 and dbms_db_version.release >= 2 or dbms_db_version.version > 12 $then + l_xml := xmltype( replace(l_xml.getClobVal(),' 0 then + ut_utils.append_to_clob( l_result, self.cursor_details.get_xml_children().getclobval() ); + end if; ut_utils.append_to_clob(l_result,chr(10)||(self as ut_compound_data_value).to_string()); l_result_string := ut_utils.to_string(l_result,null); dbms_lob.freetemporary(l_result); @@ -112,14 +132,25 @@ create or replace type body ut_data_value_refcursor as return l_result_string; end; - overriding member function diff( a_other ut_data_value, a_exclude_xpath varchar2, a_include_xpath varchar2, a_join_by_xpath varchar2, a_unordered boolean := false ) return varchar2 is + overriding member function diff( a_other ut_data_value, a_match_options ut_matcher_options ) return varchar2 is l_result clob; l_results ut_utils.t_clob_tab := ut_utils.t_clob_tab(); l_result_string varchar2(32767); - l_actual ut_data_value_refcursor; - l_column_diffs ut_compound_data_helper.tt_column_diffs := ut_compound_data_helper.tt_column_diffs(); - l_exclude_xpath varchar2(32767) := a_exclude_xpath; - l_missing_pk ut_compound_data_helper.tt_missing_pk := ut_compound_data_helper.tt_missing_pk(); + l_other ut_data_value_refcursor; + l_self ut_data_value_refcursor := self; + l_column_diffs ut_compound_data_helper.tt_column_diffs; + + l_other_cols ut_cursor_column_tab; + l_self_cols ut_cursor_column_tab; + + l_act_missing_pk ut_varchar2_list := ut_varchar2_list(); + l_exp_missing_pk ut_varchar2_list := ut_varchar2_list(); + + c_max_rows integer := ut_utils.gc_diff_max_rows; + l_diff_id ut_utils.t_hash; + l_diff_row_count integer; + l_row_diffs ut_compound_data_helper.tt_row_diffs; + l_message varchar2(32767); function get_col_diff_text(a_col ut_compound_data_helper.t_column_diffs) return varchar2 is begin @@ -135,125 +166,224 @@ create or replace type body ut_data_value_refcursor as ' Column <'||a_col.actual_name||'> is misplaced. Expected position: '||a_col.expected_pos||',' ||' actual position: '||a_col.actual_pos||'.' end; end; - - function get_missing_key_message(a_missing_keys ut_compound_data_helper.t_missing_pk) return varchar2 is - l_message varchar2(200); - begin - - if a_missing_keys.diff_type = 'a' then - l_message := ' Join key '||a_missing_keys.missingxpath||' does not exists in actual'; - elsif a_missing_keys.diff_type = 'e' then - l_message := ' Join key '||a_missing_keys.missingxpath||' does not exists in expected'; - end if; - return l_message; - end; - - function add_incomparable_cols_to_xpath( - a_column_diffs ut_compound_data_helper.tt_column_diffs, a_exclude_xpath varchar2 - ) return varchar2 is - l_incomparable_cols ut_varchar2_list := ut_varchar2_list(); - l_result varchar2(32767); + function remove_incomparable_cols( + a_cursor_details ut_cursor_column_tab, a_column_diffs ut_compound_data_helper.tt_column_diffs + ) return ut_cursor_column_tab is + l_missing_cols ut_varchar2_list := ut_varchar2_list(); + l_result ut_cursor_column_tab; begin for i in 1 .. a_column_diffs.count loop if a_column_diffs(i).diff_type in ('-','+') then - l_incomparable_cols.extend; - l_incomparable_cols(l_incomparable_cols.last) := ut_utils.xmlgen_escaped_string(coalesce(a_column_diffs(i).expected_name,a_column_diffs(i).actual_name)); - end if; + l_missing_cols.extend; + l_missing_cols(l_missing_cols.last) := coalesce(a_column_diffs(i).expected_name, a_column_diffs(i).actual_name); + end if; end loop; - l_result := ut_utils.to_xpath(l_incomparable_cols); - if a_exclude_xpath is not null and l_result is not null then - l_result := l_result ||'|'||a_exclude_xpath; - else - l_result := coalesce(a_exclude_xpath, l_result); - end if; + select /*+ no_parallel */ value(i) bulk collect into l_result + from table(a_cursor_details) i + where i.access_path not in ( + select c.column_value + from table(l_missing_cols) c + ); return l_result; end; + function get_diff_message (a_row_diff ut_compound_data_helper.t_row_diffs, a_is_unordered boolean) return varchar2 is + begin + if a_is_unordered then + if a_row_diff.pk_value is not null then + return ' PK '||a_row_diff.pk_value||' - '||rpad(a_row_diff.diff_type,10)||a_row_diff.diffed_row; + else + return rpad(a_row_diff.diff_type,10)||a_row_diff.diffed_row; + end if; + else + return ' Row No. '||a_row_diff.rn||' - '||rpad(a_row_diff.diff_type,10)||a_row_diff.diffed_row; + end if; + end; + begin if not a_other is of (ut_data_value_refcursor) then raise value_error; end if; - l_actual := treat(a_other as ut_data_value_refcursor); + l_other := treat(a_other as ut_data_value_refcursor); + l_other.cursor_details.filter_columns(a_match_options); + l_self.cursor_details.filter_columns(a_match_options); - dbms_lob.createtemporary(l_result,true); + l_other_cols := l_other.cursor_details.cursor_columns_info; + l_self_cols := l_self.cursor_details.cursor_columns_info; + dbms_lob.createtemporary(l_result,true); --diff columns - if not self.is_null and not l_actual.is_null then - l_column_diffs := ut_compound_data_helper.get_columns_diff(self.columns_info, l_actual.columns_info, a_exclude_xpath, a_include_xpath); - - if l_column_diffs.count > 0 then + if not l_self.is_null and not l_other.is_null then + l_column_diffs := ut_compound_data_helper.get_columns_diff( + l_self.cursor_details.cursor_columns_info, + l_other.cursor_details.cursor_columns_info, + a_match_options.ordered_columns() + ); + + if l_column_diffs is not empty then ut_utils.append_to_clob(l_result,chr(10) || 'Columns:' || chr(10)); + l_other_cols := remove_incomparable_cols( l_other_cols, l_column_diffs ); + l_self_cols := remove_incomparable_cols( l_self_cols, l_column_diffs ); + for i in 1 .. l_column_diffs.count loop + l_results.extend; + l_results(l_results.last) := get_col_diff_text(l_column_diffs(i)); + end loop; + ut_utils.append_to_clob(l_result, l_results); end if; - - for i in 1 .. l_column_diffs.count loop - l_results.extend; - l_results(l_results.last) := get_col_diff_text(l_column_diffs(i)); - end loop; - ut_utils.append_to_clob(l_result, l_results); - l_exclude_xpath := add_incomparable_cols_to_xpath(l_column_diffs, a_exclude_xpath); end if; --check for missing pk - if (a_join_by_xpath is not null) then - l_missing_pk := ut_compound_data_helper.is_pk_exists(self.key_info, l_actual.key_info, a_exclude_xpath, a_include_xpath,a_join_by_xpath); + if a_match_options.join_by.items.count > 0 then + l_act_missing_pk := l_other.cursor_details.get_missing_join_by_columns( a_match_options.join_by.items ); + l_exp_missing_pk := l_self.cursor_details.get_missing_join_by_columns( a_match_options.join_by.items ); end if; --diff rows and row elements if the pk is not missing - if l_missing_pk.count = 0 then - ut_utils.append_to_clob(l_result, self.get_data_diff(a_other, a_exclude_xpath, a_include_xpath, a_join_by_xpath, a_unordered)); - else - ut_utils.append_to_clob(l_result,chr(10) || 'Unable to join sets:' || chr(10)); - for i in 1 .. l_missing_pk.count loop + if l_act_missing_pk.count + l_exp_missing_pk.count = 0 then + l_diff_id := ut_utils.get_hash( l_self.data_id || l_other.data_id ); + + -- First tell how many rows are different + l_diff_row_count := ut_compound_data_helper.get_rows_diff_count; + if l_diff_row_count > 0 then + l_row_diffs := ut_compound_data_helper.get_rows_diff_by_sql( + l_self_cols, l_other_cols, l_self.data_id, l_other.data_id, + l_diff_id, + case + when + l_self.cursor_details.is_anydata = 1 then ut_utils.add_prefix(a_match_options.join_by.items, l_self.cursor_details.get_root) + else + a_match_options.join_by.items + end, + a_match_options.unordered,a_match_options.ordered_columns(), self.extract_path + ); + l_message := chr(10) + ||'Rows: [ ' || l_diff_row_count ||' differences' + || case when l_diff_row_count > c_max_rows and l_row_diffs.count > 0 then ', showing first '||c_max_rows end + ||' ]'||chr(10)|| case when l_row_diffs.count = 0 then ' All rows are different as the columns are not matching.' else null end; + ut_utils.append_to_clob( l_result, l_message ); + l_results := ut_utils.t_clob_tab(); + for i in 1 .. l_row_diffs.count loop l_results.extend; - ut_utils.append_to_clob(l_result, get_missing_key_message(l_missing_pk(i))|| chr(10)); + l_results(l_results.last) := get_diff_message(l_row_diffs(i),a_match_options.unordered); end loop; - - if ut_utils.int_to_boolean(self.contain_collection) or ut_utils.int_to_boolean(l_actual.contain_collection) then - ut_utils.append_to_clob(l_result,' Please make sure that your join clause is not refferring to collection element'|| chr(10)); - end if; + ut_utils.append_to_clob(l_result,l_results); + elsif l_column_diffs is not empty then + l_message:= chr(10)||'Rows: [ all different ]'||chr(10)||' All rows are different as the columns position is not matching.'; + ut_utils.append_to_clob( l_result, l_message ); + end if; + else + ut_utils.append_to_clob(l_result,chr(10) || 'Unable to join sets:' || chr(10)); + + for i in 1 .. l_exp_missing_pk.count loop + ut_utils.append_to_clob(l_result, ' Join key '||l_exp_missing_pk(i)||' does not exists in expected'||chr(10)); + end loop; + + for i in 1 .. l_act_missing_pk.count loop + ut_utils.append_to_clob(l_result, ' Join key '||l_act_missing_pk(i)||' does not exists in actual'||chr(10)); + end loop; + + if l_self.cursor_details.contains_collection() or l_other.cursor_details.contains_collection() then + ut_utils.append_to_clob(l_result,' Please make sure that your join clause is not refferring to collection element'|| chr(10)); + end if; end if; - - l_result_string := ut_utils.to_string(l_result,null); + if l_result != empty_clob() then + l_result_string := chr(10) || 'Diff:' || ut_utils.to_string(l_result,null); + end if; dbms_lob.freetemporary(l_result); return l_result_string; end; - overriding member function compare_implementation (a_other ut_data_value, a_exclude_xpath varchar2, a_include_xpath varchar2, a_join_by_xpath varchar2, a_unordered boolean) return integer is - l_result integer := 0; - l_other ut_data_value_refcursor; - function is_pk_missing (a_pk_missing_tab ut_compound_data_helper.tt_missing_pk) return integer is + overriding member function compare_implementation(a_other ut_data_value) return integer is + begin + return compare_implementation( a_other, null ); + end; + + member function compare_implementation( + a_other ut_data_value, + a_match_options ut_matcher_options, + a_inclusion_compare boolean := false, + a_is_negated boolean := false + ) return integer is + l_result integer := 0; + l_self ut_data_value_refcursor := self; + l_other ut_data_value_refcursor; + l_diff_cursor_text clob; + + function compare_data( + a_self ut_data_value_refcursor, + a_other ut_data_value_refcursor, + a_diff_cursor_text clob + ) return integer is + l_diff_id ut_utils.t_hash; + l_result integer; + --We will start with number od differences being displayed. + l_cursor sys_refcursor; + l_diff_tab ut_compound_data_helper.t_diff_tab; + l_diif_rowcount integer :=0; begin - return case when a_pk_missing_tab.count > 0 then 1 else 0 end; + l_diff_id := ut_utils.get_hash(a_self.data_id||a_other.data_id); + + begin + l_cursor := ut_compound_data_helper.get_compare_cursor(a_diff_cursor_text, + a_self.data_id, a_other.data_id); + --fetch and save rows for display of diff + fetch l_cursor bulk collect into l_diff_tab limit ut_utils.gc_diff_max_rows; + exception when others then + if l_cursor%isopen then + close l_cursor; + end if; + raise; + end; + + ut_compound_data_helper.insert_diffs_result( l_diff_tab, l_diff_id ); + --fetch rows for count only + loop + exit when l_diff_tab.count = 0; + l_diif_rowcount := l_diif_rowcount + l_diff_tab.count; + fetch l_cursor bulk collect into l_diff_tab limit ut_utils.gc_bc_fetch_limit; + end loop; + + ut_compound_data_helper.set_rows_diff(l_diif_rowcount); + + --result is OK only if both are same + if l_diif_rowcount = 0 and a_self.is_null = a_other.is_null then + l_result := 0; + else + l_result := 1; + end if; + close l_cursor; + return l_result; end; begin if not a_other is of (ut_data_value_refcursor) then raise value_error; end if; - l_other := treat(a_other as ut_data_value_refcursor); - - --if we join by key and key is missing fail and report error - if a_join_by_xpath is not null then - l_result := is_pk_missing(ut_compound_data_helper.is_pk_exists(self.key_info, l_other.key_info, a_exclude_xpath, a_include_xpath,a_join_by_xpath)); + l_other := treat(a_other as ut_data_value_refcursor); + l_other.cursor_details.filter_columns( a_match_options ); + l_self.cursor_details.filter_columns( a_match_options ); + + if a_match_options.join_by.items.count > 0 then + l_result := + l_self.cursor_details.get_missing_join_by_columns( a_match_options.join_by.items ).count + + l_other.cursor_details.get_missing_join_by_columns( a_match_options.join_by.items ).count; end if; - + if l_result = 0 then - --if column names/types are not equal - build a diff of column names and types - if ut_compound_data_helper.columns_hash( self, a_exclude_xpath, a_include_xpath ) - != ut_compound_data_helper.columns_hash( l_other, a_exclude_xpath, a_include_xpath ) - then + if not l_self.is_null() and not l_other.is_null() and not l_self.cursor_details.equals( l_other.cursor_details, a_match_options ) then l_result := 1; end if; - - if a_unordered then - l_result := l_result + (self as ut_compound_data_value).compare_implementation(a_other, a_exclude_xpath, a_include_xpath, a_join_by_xpath, a_unordered); - else - l_result := l_result + (self as ut_compound_data_value).compare_implementation(a_other, a_exclude_xpath, a_include_xpath); - end if; + l_diff_cursor_text := ut_compound_data_helper.gen_compare_sql( + l_other, + a_match_options.join_by.items, + a_match_options.unordered(), + a_inclusion_compare, + a_is_negated + ); + l_result := l_result + compare_data( l_self, l_other, l_diff_cursor_text ); end if; - return l_result; end; @@ -262,6 +392,5 @@ create or replace type body ut_data_value_refcursor as return self.elements_count = 0; end; - end; / diff --git a/source/expectations/data_values/ut_data_value_refcursor.tps b/source/expectations/data_values/ut_data_value_refcursor.tps index 02ded0b39..594695e32 100644 --- a/source/expectations/data_values/ut_data_value_refcursor.tps +++ b/source/expectations/data_values/ut_data_value_refcursor.tps @@ -1,7 +1,7 @@ create or replace type ut_data_value_refcursor under ut_compound_data_value( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -24,28 +24,29 @@ create or replace type ut_data_value_refcursor under ut_compound_data_value( * Determines if the cursor is null */ is_cursor_null integer, + + /* + *columns info + */ + cursor_details ut_cursor_details, - /** - * hold information if the cursor contains collection object - */ - contain_collection number(1,0), - - /** - * Holds information about column names and column data-types - */ - columns_info xmltype, - - /** - * Holds more detailed information regarding the pk joins + /* + * extract path of elements, important for collectiosn and objects */ - key_info xmltype, + extract_path varchar2(10), constructor function ut_data_value_refcursor(self in out nocopy ut_data_value_refcursor, a_value sys_refcursor) return self as result, + member procedure extract_cursor(self in out nocopy ut_data_value_refcursor, a_value sys_refcursor), member procedure init(self in out nocopy ut_data_value_refcursor, a_value sys_refcursor), overriding member function to_string return varchar2, - overriding member function diff( a_other ut_data_value, a_exclude_xpath varchar2, a_include_xpath varchar2, a_join_by_xpath varchar2, a_unordered boolean := false ) return varchar2, - overriding member function compare_implementation(a_other ut_data_value, a_exclude_xpath varchar2, a_include_xpath varchar2, a_join_by_xpath varchar2, a_unordered boolean) return integer, + overriding member function diff( a_other ut_data_value, a_match_options ut_matcher_options ) return varchar2, + overriding member function compare_implementation(a_other ut_data_value) return integer, + member function compare_implementation( + a_other ut_data_value, + a_match_options ut_matcher_options, + a_inclusion_compare boolean := false, + a_is_negated boolean := false + ) return integer, overriding member function is_empty return boolean - -) +) not final / diff --git a/source/expectations/data_values/ut_data_value_timestamp.tpb b/source/expectations/data_values/ut_data_value_timestamp.tpb index 7b9d15e41..318f799a3 100644 --- a/source/expectations/data_values/ut_data_value_timestamp.tpb +++ b/source/expectations/data_values/ut_data_value_timestamp.tpb @@ -1,7 +1,7 @@ create or replace type body ut_data_value_timestamp as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ create or replace type body ut_data_value_timestamp as self.data_value := a_value; self.self_type := $$plsql_unit; self.data_type := 'timestamp'; + self.data_type_plsql := 'timestamp_unconstrained'; return; end; diff --git a/source/expectations/data_values/ut_data_value_timestamp.tps b/source/expectations/data_values/ut_data_value_timestamp.tps index e32f855a6..c047e3c79 100644 --- a/source/expectations/data_values/ut_data_value_timestamp.tps +++ b/source/expectations/data_values/ut_data_value_timestamp.tps @@ -1,7 +1,7 @@ create or replace type ut_data_value_timestamp under ut_data_value( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/data_values/ut_data_value_timestamp_ltz.tpb b/source/expectations/data_values/ut_data_value_timestamp_ltz.tpb index 8abbfce12..6127de5f1 100644 --- a/source/expectations/data_values/ut_data_value_timestamp_ltz.tpb +++ b/source/expectations/data_values/ut_data_value_timestamp_ltz.tpb @@ -1,7 +1,7 @@ create or replace type body ut_data_value_timestamp_ltz as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ create or replace type body ut_data_value_timestamp_ltz as self.data_value := a_value; self.self_type := $$plsql_unit; self.data_type := 'timestamp with local time zone'; + self.data_type_plsql := 'timestamp_ltz_unconstrained'; return; end; diff --git a/source/expectations/data_values/ut_data_value_timestamp_ltz.tps b/source/expectations/data_values/ut_data_value_timestamp_ltz.tps index 869197c98..7bb296bc9 100644 --- a/source/expectations/data_values/ut_data_value_timestamp_ltz.tps +++ b/source/expectations/data_values/ut_data_value_timestamp_ltz.tps @@ -1,7 +1,7 @@ create or replace type ut_data_value_timestamp_ltz under ut_data_value( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/data_values/ut_data_value_timestamp_tz.tpb b/source/expectations/data_values/ut_data_value_timestamp_tz.tpb index a61d60e33..d5d5cdd13 100644 --- a/source/expectations/data_values/ut_data_value_timestamp_tz.tpb +++ b/source/expectations/data_values/ut_data_value_timestamp_tz.tpb @@ -1,7 +1,7 @@ create or replace type body ut_data_value_timestamp_tz as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ create or replace type body ut_data_value_timestamp_tz as self.data_value := a_value; self.self_type := $$plsql_unit; self.data_type := 'timestamp with time zone'; + self.data_type_plsql := 'timestamp_tz_unconstrained'; return; end; diff --git a/source/expectations/data_values/ut_data_value_timestamp_tz.tps b/source/expectations/data_values/ut_data_value_timestamp_tz.tps index 55aa3a803..01cf11124 100644 --- a/source/expectations/data_values/ut_data_value_timestamp_tz.tps +++ b/source/expectations/data_values/ut_data_value_timestamp_tz.tps @@ -1,7 +1,7 @@ create or replace type ut_data_value_timestamp_tz under ut_data_value( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/data_values/ut_data_value_varchar2.tpb b/source/expectations/data_values/ut_data_value_varchar2.tpb index 4f80ee161..d04398697 100644 --- a/source/expectations/data_values/ut_data_value_varchar2.tpb +++ b/source/expectations/data_values/ut_data_value_varchar2.tpb @@ -1,7 +1,7 @@ create or replace type body ut_data_value_varchar2 as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ create or replace type body ut_data_value_varchar2 as self.data_value := a_value; self.self_type := $$plsql_unit; self.data_type := 'varchar2'; + self.data_type_plsql := 'varchar2(32767)'; return; end; diff --git a/source/expectations/data_values/ut_data_value_varchar2.tps b/source/expectations/data_values/ut_data_value_varchar2.tps index ce5954a09..3fbeb378b 100644 --- a/source/expectations/data_values/ut_data_value_varchar2.tps +++ b/source/expectations/data_values/ut_data_value_varchar2.tps @@ -1,7 +1,7 @@ create or replace type ut_data_value_varchar2 under ut_data_value( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/data_values/ut_data_value_xmltype.tpb b/source/expectations/data_values/ut_data_value_xmltype.tpb index ecefb664d..4b21a8937 100644 --- a/source/expectations/data_values/ut_data_value_xmltype.tpb +++ b/source/expectations/data_values/ut_data_value_xmltype.tpb @@ -1,7 +1,7 @@ create or replace type body ut_data_value_xmltype as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ create or replace type body ut_data_value_xmltype as self.data_value := a_value; self.self_type := $$plsql_unit; self.data_type := 'xmltype'; + self.data_type_plsql := 'xmltype'; return; end; diff --git a/source/expectations/data_values/ut_data_value_xmltype.tps b/source/expectations/data_values/ut_data_value_xmltype.tps index 42c54ae05..9ba738b88 100644 --- a/source/expectations/data_values/ut_data_value_xmltype.tps +++ b/source/expectations/data_values/ut_data_value_xmltype.tps @@ -1,7 +1,7 @@ create or replace type ut_data_value_xmltype under ut_data_value( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/data_values/ut_data_value_yminterval.tpb b/source/expectations/data_values/ut_data_value_yminterval.tpb index 38f3cf857..a3a1e7a2f 100644 --- a/source/expectations/data_values/ut_data_value_yminterval.tpb +++ b/source/expectations/data_values/ut_data_value_yminterval.tpb @@ -1,7 +1,7 @@ create or replace type body ut_data_value_yminterval as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ create or replace type body ut_data_value_yminterval as self.data_value := a_value; self.self_type := $$plsql_unit; self.data_type := 'interval year to month'; + self.data_type_plsql := 'yminterval_unconstrained'; return; end; @@ -31,7 +32,7 @@ create or replace type body ut_data_value_yminterval as overriding member function to_string return varchar2 is begin - return ut_utils.to_string(self.data_value); + return ut_utils.interval_to_text(self.data_value); end; overriding member function compare_implementation(a_other ut_data_value) return integer is diff --git a/source/expectations/data_values/ut_data_value_yminterval.tps b/source/expectations/data_values/ut_data_value_yminterval.tps index efc9e0e48..c9ad2e776 100644 --- a/source/expectations/data_values/ut_data_value_yminterval.tps +++ b/source/expectations/data_values/ut_data_value_yminterval.tps @@ -1,7 +1,7 @@ create or replace type ut_data_value_yminterval under ut_data_value( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ create or replace type ut_data_value_yminterval under ut_data_value( See the License for the specific language governing permissions and limitations under the License. */ - data_value yminterval_unconstrained, + data_value interval year(9) to month, constructor function ut_data_value_yminterval(self in out nocopy ut_data_value_yminterval, a_value yminterval_unconstrained) return self as result, overriding member function is_null return boolean, overriding member function to_string return varchar2, diff --git a/source/expectations/data_values/ut_json_data_diff_tmp.sql b/source/expectations/data_values/ut_json_data_diff_tmp.sql new file mode 100644 index 000000000..5ff3440d8 --- /dev/null +++ b/source/expectations/data_values/ut_json_data_diff_tmp.sql @@ -0,0 +1,27 @@ +create global temporary table ut_json_data_diff_tmp( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + */ + diff_id raw(128), + difference_type varchar2(250), + act_element_name varchar2(2000), + act_element_value varchar2(4000), + act_json_type varchar2(100), + act_access_path varchar2(4000), + act_parent_path varchar2(4000), + exp_element_name varchar2(2000), + exp_element_value varchar2(4000), + exp_json_type varchar2(2000), + exp_access_path varchar2(4000), + exp_parent_path varchar2(4000) +) on commit delete rows; diff --git a/source/expectations/data_values/ut_json_leaf.tpb b/source/expectations/data_values/ut_json_leaf.tpb new file mode 100644 index 000000000..83f1009ef --- /dev/null +++ b/source/expectations/data_values/ut_json_leaf.tpb @@ -0,0 +1,32 @@ +create or replace type body ut_json_leaf as + + member procedure init( self in out nocopy ut_json_leaf, + a_element_name varchar2, a_element_value varchar2,a_parent_name varchar2, + a_access_path varchar2, a_hierarchy_level integer, a_index_position integer, a_json_type in varchar2, + a_parent_type varchar2, a_array_element integer:=0, a_parent_path varchar2) is + begin + self.element_name := a_element_name; + self.element_value := a_element_value; + self.parent_name := a_parent_name; + self.hierarchy_level := a_hierarchy_level; + self.access_path := a_access_path; + self.index_position := a_index_position; + self.json_type := a_json_type; + self.is_array_element := a_array_element; + self.parent_type := a_parent_type; + self.parent_path := a_parent_path; + end; + + constructor function ut_json_leaf( self in out nocopy ut_json_leaf, + a_element_name varchar2, a_element_value varchar2,a_parent_name varchar2, + a_access_path varchar2, a_hierarchy_level integer, a_index_position integer, a_json_type in varchar2, + a_parent_type varchar2, a_array_element integer:=0, a_parent_path varchar2) + return self as result is + begin + init(a_element_name,a_element_value,a_parent_name, a_access_path, a_hierarchy_level, a_index_position, + a_json_type,a_parent_type,a_array_element, a_parent_path); + return; + end; + +end; +/ diff --git a/source/expectations/data_values/ut_json_leaf.tps b/source/expectations/data_values/ut_json_leaf.tps new file mode 100644 index 000000000..8aa8afd6a --- /dev/null +++ b/source/expectations/data_values/ut_json_leaf.tps @@ -0,0 +1,42 @@ +create or replace type ut_json_leaf authid current_user as object ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + */ + element_name varchar2(4000), + element_value varchar2(4000), + parent_name varchar2(4000), + access_path varchar2(4000), + tlength integer, + display_path varchar2(4000), + hierarchy_level integer, + index_position integer, + json_type varchar2(2000), + is_array_element integer, + parent_type varchar2(2000), + parent_path varchar2(4000), + + member procedure init(self in out nocopy ut_json_leaf, + a_element_name varchar2, a_element_value varchar2,a_parent_name varchar2, + a_access_path varchar2, a_hierarchy_level integer, a_index_position integer, a_json_type in varchar2, + a_parent_type varchar2, a_array_element integer:=0, a_parent_path varchar2), + + constructor function ut_json_leaf( self in out nocopy ut_json_leaf, + a_element_name varchar2, a_element_value varchar2,a_parent_name varchar2, + a_access_path varchar2, a_hierarchy_level integer, a_index_position integer, a_json_type in varchar2, + a_parent_type varchar2, a_array_element integer:=0, a_parent_path varchar2) + return self as result +) +/ diff --git a/source/expectations/data_values/ut_json_leaf_tab.tps b/source/expectations/data_values/ut_json_leaf_tab.tps new file mode 100644 index 000000000..395ab5d9e --- /dev/null +++ b/source/expectations/data_values/ut_json_leaf_tab.tps @@ -0,0 +1,19 @@ +create or replace type ut_json_leaf_tab as + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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_json_leaf +/ \ No newline at end of file diff --git a/source/expectations/data_values/ut_json_tree_details.tpb b/source/expectations/data_values/ut_json_tree_details.tpb new file mode 100644 index 000000000..a333ea71c --- /dev/null +++ b/source/expectations/data_values/ut_json_tree_details.tpb @@ -0,0 +1,207 @@ +create or replace type body ut_json_tree_details as + + member function get_json_type(a_json_piece json_element_t) return varchar2 is + begin + return + case + when a_json_piece.is_object then 'object' + when a_json_piece.is_array then 'array' + when a_json_piece.is_string then 'string' + when a_json_piece.is_number then 'number' + when a_json_piece.is_boolean then 'boolean' + when a_json_piece.is_true then 'true' + when a_json_piece.is_false then 'false' + when a_json_piece.is_null then 'null' + when a_json_piece.is_date then 'date' + when a_json_piece.is_timestamp then 'timestamp' + when a_json_piece.is_scalar then 'scalar' + else null + end; + end; + + member function get_json_value(a_json_piece json_element_t, a_key varchar2) return varchar2 is + l_json_el json_element_t; + l_val varchar2(4000); + begin + l_json_el := treat(a_json_piece as json_object_t).get(a_key); + case + when l_json_el.is_string then l_val := ut_utils.to_string(l_json_el.to_string(),null); + when l_json_el.is_number then l_val := ut_utils.to_string(l_json_el.to_number()); + when l_json_el.is_boolean then l_val := ut_utils.to_string(l_json_el.to_boolean()); +-- when l_json_el.is_true then l_val := ut_utils.to_string(l_json_el.to_boolean()); +-- when l_json_el.is_false then l_val := ut_utils.to_string(l_json_el.to_boolean()); + when l_json_el.is_date then l_val := ut_utils.to_string(l_json_el.to_date()); + when l_json_el.is_timestamp then l_val := ut_utils.to_string(l_json_el.to_date()); + else null; + end case; + return l_val; + end; + + member function get_json_value(a_json_piece json_element_t, a_key integer) return varchar2 is + l_json_el json_element_t; + l_val varchar2(4000); + begin + l_json_el := treat(a_json_piece as json_array_t).get(a_key); + case + when l_json_el.is_string then l_val := ut_utils.to_string(l_json_el.to_string(),null); + when l_json_el.is_number then l_val := ut_utils.to_string(l_json_el.to_number()); + when l_json_el.is_boolean then l_val := ut_utils.to_string(l_json_el.to_boolean()); +-- when l_json_el.is_true then l_val := ut_utils.to_string(l_json_el.to_boolean()); +-- when l_json_el.is_false then l_val := ut_utils.to_string(l_json_el.to_boolean()); + when l_json_el.is_date then l_val := ut_utils.to_string(l_json_el.to_date()); + when l_json_el.is_timestamp then l_val := ut_utils.to_string(l_json_el.to_date()); + else null; + end case; + return l_val; + end; + + member procedure add_json_leaf( + self in out nocopy ut_json_tree_details, + a_element_name varchar2, + a_element_value varchar2, + a_parent_name varchar2, + a_access_path varchar2, + a_hierarchy_level integer, + a_index_position integer, + a_json_type varchar2, + a_parent_type varchar2, + a_array_element integer := 0, + a_parent_path varchar2 + ) is + begin + self.json_tree_info.extend; + self.json_tree_info(self.json_tree_info.last) := + ut_json_leaf( + a_element_name, a_element_value, a_parent_name, a_access_path, + a_hierarchy_level, a_index_position,a_json_type, a_parent_type, + a_array_element, a_parent_path + ); + end; + + member procedure traverse_object( + self in out nocopy ut_json_tree_details, + a_json_piece json_element_t, + a_parent_name varchar2 := null, + a_hierarchy_level integer := 1, + a_access_path varchar2 := '$' + ) as + l_keys json_key_list; + l_object json_object_t := treat(a_json_piece as json_object_t); + l_path varchar2(32767); + l_type varchar2(50); + l_name varchar2(4000); + begin + l_keys := coalesce(l_object.get_keys,json_key_list()); + + for i in 1 .. l_keys.count loop + l_type := get_json_type(l_object.get(l_keys(i))); + l_name := '"'||l_keys(i)||'"'; + l_path := a_access_path||'.'||l_name; + + add_json_leaf( + l_name, + get_json_value(l_object,l_keys(i)), + a_parent_name, + l_path, + a_hierarchy_level, + i, + l_type, + 'object', + 0, + a_access_path + ); + case l_type + when 'array' then + traverse_array ( + treat (l_object.get (l_keys(i)) as json_array_t), + l_name, + a_hierarchy_level + 1, + l_path + ); + when 'object' then + traverse_object( + treat (l_object.get (l_keys(i)) as json_object_t), + l_name, + a_hierarchy_level+1, + l_path + ); + else + null; + end case; + end loop; + end traverse_object; + + member procedure traverse_array( + self in out nocopy ut_json_tree_details, + a_json_piece json_element_t, + a_parent_name varchar2 := null, + a_hierarchy_level integer := 1, + a_access_path varchar2 := '$' + ) as + l_array json_array_t; + l_type varchar2(50); + l_name varchar2(4000); + l_path varchar2(32767); + begin + l_array := treat(a_json_piece as json_array_t); + + for i in 0 .. l_array.get_size - 1 loop + l_type := get_json_type(l_array.get(i)); + l_name := case when l_type = 'object' then l_type else l_array.get(i).stringify end; + l_path := a_access_path||'['||i||']'; + + add_json_leaf( + l_name, + get_json_value(a_json_piece,i), + a_parent_name, + l_path, + a_hierarchy_level, + i, + l_type, + 'array', + 1, + l_path + ); + case l_type + when 'array' then + traverse_array ( + treat (l_array.get (i) as json_array_t), + l_name, + a_hierarchy_level + 1, + l_path + ); + when 'object' then + traverse_object( + treat (l_array.get (i) as json_object_t), + l_name, + a_hierarchy_level + 1, + l_path + ); + else + null; + end case; + end loop; + end traverse_array; + + member procedure init(self in out nocopy ut_json_tree_details,a_json_doc in json_element_t, a_level_in integer := 0) is + begin + if a_json_doc.is_object then + traverse_object(treat (a_json_doc as json_object_t)); + elsif a_json_doc.is_array then + traverse_array(treat (a_json_doc as json_array_t)); + end if; + end; + + constructor function ut_json_tree_details( + self in out nocopy ut_json_tree_details, a_json_doc in json_element_t, a_level_in integer := 0 + ) return self as result is + begin + self.json_tree_info := ut_json_leaf_tab(); + if a_json_doc is not null then + init(a_json_doc,a_level_in); + end if; + return; + end; + +end; +/ diff --git a/source/expectations/data_values/ut_json_tree_details.tps b/source/expectations/data_values/ut_json_tree_details.tps new file mode 100644 index 000000000..20ac2fdcc --- /dev/null +++ b/source/expectations/data_values/ut_json_tree_details.tps @@ -0,0 +1,54 @@ +create or replace type ut_json_tree_details force as object ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + */ + json_tree_info ut_json_leaf_tab, + member function get_json_type(a_json_piece json_element_t) return varchar2, + member function get_json_value(a_json_piece json_element_t,a_key varchar2) return varchar2, + member function get_json_value(a_json_piece json_element_t,a_key integer) return varchar2, + member procedure add_json_leaf( + self in out nocopy ut_json_tree_details, + a_element_name varchar2, + a_element_value varchar2, + a_parent_name varchar2, + a_access_path varchar2, + a_hierarchy_level integer, + a_index_position integer, + a_json_type in varchar2, + a_parent_type in varchar2, + a_array_element integer := 0, + a_parent_path varchar2 + ), + member procedure traverse_object( + self in out nocopy ut_json_tree_details, + a_json_piece json_element_t, + a_parent_name varchar2 := null, + a_hierarchy_level integer := 1, + a_access_path varchar2 := '$' + ), + member procedure traverse_array( + self in out nocopy ut_json_tree_details, + a_json_piece json_element_t, + a_parent_name varchar2 := null, + a_hierarchy_level integer := 1, + a_access_path varchar2 := '$' + ), + member procedure init(self in out nocopy ut_json_tree_details,a_json_doc in json_element_t, a_level_in integer := 0), + constructor function ut_json_tree_details( + self in out nocopy ut_json_tree_details, a_json_doc in json_element_t, a_level_in integer := 0 + ) return self as result +) +/ diff --git a/source/expectations/data_values/ut_key_anyval_pair.tps b/source/expectations/data_values/ut_key_anyval_pair.tps index e0701ef28..d1068f109 100644 --- a/source/expectations/data_values/ut_key_anyval_pair.tps +++ b/source/expectations/data_values/ut_key_anyval_pair.tps @@ -1,7 +1,7 @@ create or replace type ut_key_anyval_pair force as object( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/data_values/ut_key_anyval_pairs.tps b/source/expectations/data_values/ut_key_anyval_pairs.tps index 40748c5a5..7e10bf50f 100644 --- a/source/expectations/data_values/ut_key_anyval_pairs.tps +++ b/source/expectations/data_values/ut_key_anyval_pairs.tps @@ -1,7 +1,7 @@ create or replace type ut_key_anyval_pairs as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/data_values/ut_key_anyvalues.tpb b/source/expectations/data_values/ut_key_anyvalues.tpb new file mode 100644 index 000000000..d30d8a841 --- /dev/null +++ b/source/expectations/data_values/ut_key_anyvalues.tpb @@ -0,0 +1,90 @@ +create or replace type body ut_key_anyvalues as + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + constructor function ut_key_anyvalues(self in out nocopy ut_key_anyvalues) return self as result is + begin + self.self_type := $$plsql_unit; + self.pairs := ut_key_anyval_pairs(); + return; + end; + member function put(a_item ut_key_anyval_pair) return ut_key_anyvalues is + l_result ut_key_anyvalues := self; + begin + l_result.pairs.extend(); + l_result.pairs(l_result.pairs.last) := a_item; + return l_result; + end; + member function put(a_key varchar2, a_value anydata) return ut_key_anyvalues is + begin + return put(ut_key_anyval_pair(a_key, ut_data_value_anydata(a_value))); + end; + + member function put(a_key varchar2, a_value blob) return ut_key_anyvalues is + begin + return put(ut_key_anyval_pair(a_key, ut_data_value_blob(a_value))); + end; + + member function put(a_key varchar2, a_value boolean) return ut_key_anyvalues is + begin + return put(ut_key_anyval_pair(a_key, ut_data_value_boolean(a_value))); + end; + + member function put(a_key varchar2, a_value clob) return ut_key_anyvalues is + begin + return put(ut_key_anyval_pair(a_key, ut_data_value_clob(a_value))); + end; + + member function put(a_key varchar2, a_value date) return ut_key_anyvalues is + begin + return put(ut_key_anyval_pair(a_key, ut_data_value_date(a_value))); + end; + + member function put(a_key varchar2, a_value number) return ut_key_anyvalues is + begin + return put(ut_key_anyval_pair(a_key, ut_data_value_number(a_value))); + end; + member function put(a_key varchar2, a_value timestamp_unconstrained) return ut_key_anyvalues is + begin + return put(ut_key_anyval_pair(a_key, ut_data_value_timestamp(a_value))); + end; + + member function put(a_key varchar2, a_value timestamp_ltz_unconstrained) return ut_key_anyvalues is + begin + return put(ut_key_anyval_pair(a_key, ut_data_value_timestamp_ltz(a_value))); + end; + + member function put(a_key varchar2, a_value timestamp_tz_unconstrained) return ut_key_anyvalues is + begin + return put(ut_key_anyval_pair(a_key, ut_data_value_timestamp_tz(a_value))); + end; + + member function put(a_key varchar2, a_value varchar2) return ut_key_anyvalues is + begin + return put(ut_key_anyval_pair(a_key, ut_data_value_varchar2(a_value))); + end; + + member function put(a_key varchar2, a_value yminterval_unconstrained) return ut_key_anyvalues is + begin + return put(ut_key_anyval_pair(a_key, ut_data_value_yminterval(a_value))); + end; + + member function put(a_key varchar2, a_value dsinterval_unconstrained) return ut_key_anyvalues is + begin + return put(ut_key_anyval_pair(a_key, ut_data_value_dsinterval(a_value))); + end; +end; +/ diff --git a/source/expectations/data_values/ut_key_anyvalues.tps b/source/expectations/data_values/ut_key_anyvalues.tps new file mode 100644 index 000000000..8c672bd00 --- /dev/null +++ b/source/expectations/data_values/ut_key_anyvalues.tps @@ -0,0 +1,34 @@ +create or replace type ut_key_anyvalues under ut_event_item ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + */ + pairs ut_key_anyval_pairs, + constructor function ut_key_anyvalues(self in out nocopy ut_key_anyvalues) return self as result, + member function put(a_item ut_key_anyval_pair) return ut_key_anyvalues, + member function put(a_key varchar2, a_value anydata) return ut_key_anyvalues, + member function put(a_key varchar2, a_value blob) return ut_key_anyvalues, + member function put(a_key varchar2, a_value boolean) return ut_key_anyvalues, + member function put(a_key varchar2, a_value clob) return ut_key_anyvalues, + member function put(a_key varchar2, a_value date) return ut_key_anyvalues, + member function put(a_key varchar2, a_value number) return ut_key_anyvalues, + member function put(a_key varchar2, a_value timestamp_unconstrained) return ut_key_anyvalues, + member function put(a_key varchar2, a_value timestamp_ltz_unconstrained) return ut_key_anyvalues, + member function put(a_key varchar2, a_value timestamp_tz_unconstrained) return ut_key_anyvalues, + member function put(a_key varchar2, a_value varchar2) return ut_key_anyvalues, + member function put(a_key varchar2, a_value yminterval_unconstrained) return ut_key_anyvalues, + member function put(a_key varchar2, a_value dsinterval_unconstrained) return ut_key_anyvalues +) +/ diff --git a/source/expectations/json_objects_specs.sql b/source/expectations/json_objects_specs.sql new file mode 100644 index 000000000..a5d936afb --- /dev/null +++ b/source/expectations/json_objects_specs.sql @@ -0,0 +1,74 @@ +BEGIN + null; + $if dbms_db_version.version < 21 $then + dbms_output.put_line('Installing json structures specs for native json.'); + execute immediate q'[create or replace TYPE JSON FORCE AUTHID CURRENT_USER AS OBJECT( + dummyobjt NUMBER +) NOT FINAL NOT INSTANTIABLE;]'; + $end + $if dbms_db_version.version = 12 and dbms_db_version.release = 1 or dbms_db_version.version < 12 $then + dbms_output.put_line('Installing json structures specs.'); + execute immediate q'[create or replace TYPE JSON_Element_T FORCE AUTHID CURRENT_USER AS OBJECT( + dummyobjt NUMBER, + STATIC FUNCTION parse(jsn VARCHAR2) RETURN JSON_Element_T, + STATIC FUNCTION parse(jsn CLOB) RETURN JSON_Element_T, + STATIC FUNCTION parse(jsn BLOB) RETURN JSON_Element_T, + MEMBER FUNCTION to_Clob RETURN CLOB, + MEMBER FUNCTION stringify RETURN VARCHAR2, + MEMBER FUNCTION is_Object RETURN BOOLEAN, + MEMBER FUNCTION is_Array RETURN BOOLEAN, + MEMBER FUNCTION is_Scalar RETURN BOOLEAN, + MEMBER FUNCTION is_String RETURN BOOLEAN, + MEMBER FUNCTION is_Number RETURN BOOLEAN, + MEMBER FUNCTION is_Boolean RETURN BOOLEAN, + MEMBER FUNCTION is_True RETURN BOOLEAN, + MEMBER FUNCTION is_False RETURN BOOLEAN, + MEMBER FUNCTION is_Null RETURN BOOLEAN, + MEMBER FUNCTION is_Date RETURN BOOLEAN, + MEMBER FUNCTION is_Timestamp RETURN BOOLEAN, + MEMBER FUNCTION to_string RETURN VARCHAR2, + MEMBER FUNCTION to_number RETURN NUMBER, + MEMBER FUNCTION to_boolean RETURN BOOLEAN, + MEMBER FUNCTION to_date RETURN VARCHAR2, + + MEMBER FUNCTION get_Size(self IN JSON_ELEMENT_T) RETURN NUMBER +) NOT FINAL NOT INSTANTIABLE;]'; + + execute immediate q'[create or replace TYPE JSON_KEY_LIST FORCE AS VARRAY(32767) OF VARCHAR2(4000);]'; + + execute immediate q'[create or replace TYPE JSON_Array_T FORCE AUTHID CURRENT_USER UNDER JSON_Element_T( + CONSTRUCTOR FUNCTION JSON_Array_T RETURN SELF AS RESULT, + MEMBER FUNCTION get(pos NUMBER) RETURN JSON_Element_T, + MEMBER FUNCTION get_String(pos NUMBER) RETURN VARCHAR2, + MEMBER FUNCTION get_Number(pos NUMBER) RETURN NUMBER, + MEMBER FUNCTION get_Boolean(pos NUMBER) RETURN BOOLEAN, + MEMBER FUNCTION get_Date(pos NUMBER) RETURN DATE, + MEMBER FUNCTION get_Timestamp(pos NUMBER) RETURN TIMESTAMP, + MEMBER FUNCTION get_Clob(pos NUMBER) RETURN CLOB, + MEMBER PROCEDURE get_Clob(pos NUMBER, c IN OUT NOCOPY CLOB), + MEMBER FUNCTION get_Blob(pos NUMBER) RETURN BLOB, + MEMBER PROCEDURE get_Blob(pos NUMBER, b IN OUT NOCOPY BLOB), + MEMBER FUNCTION get_Type(pos NUMBER) RETURN VARCHAR2 +) FINAL;]'; + + execute immediate q'[create or replace TYPE JSON_Object_T AUTHID CURRENT_USER UNDER JSON_Element_T( + CONSTRUCTOR FUNCTION JSON_Object_T RETURN SELF AS RESULT, + MEMBER FUNCTION get(key VARCHAR2) RETURN JSON_Element_T, + MEMBER FUNCTION get_Object(key VARCHAR2) RETURN JSON_OBJECT_T, + MEMBER FUNCTION get_Array(key VARCHAR2) RETURN JSON_ARRAY_T, + MEMBER FUNCTION get_String(key VARCHAR2) RETURN VARCHAR2, + MEMBER FUNCTION get_Number(key VARCHAR2) RETURN NUMBER, + MEMBER FUNCTION get_Boolean(key VARCHAR2) RETURN BOOLEAN, + MEMBER FUNCTION get_Date(key VARCHAR2) RETURN DATE, + MEMBER FUNCTION get_Timestamp(key VARCHAR2) RETURN TIMESTAMP, + MEMBER FUNCTION get_Clob(key VARCHAR2) RETURN CLOB, + MEMBER PROCEDURE get_Clob(key VARCHAR2, c IN OUT NOCOPY CLOB), + MEMBER FUNCTION get_Blob(key VARCHAR2) RETURN BLOB, + MEMBER PROCEDURE get_Blob(key VARCHAR2, b IN OUT NOCOPY BLOB), + MEMBER FUNCTION get_Type(key VARCHAR2) RETURN VARCHAR2, + MEMBER FUNCTION get_Keys RETURN JSON_KEY_LIST +) FINAL;]'; + $end + +END; +/ \ No newline at end of file diff --git a/source/expectations/matchers/ut_be_between.tpb b/source/expectations/matchers/ut_be_between.tpb index f4bf24aab..6aea96f55 100644 --- a/source/expectations/matchers/ut_be_between.tpb +++ b/source/expectations/matchers/ut_be_between.tpb @@ -1,7 +1,7 @@ create or replace type body ut_be_between is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_between.tps b/source/expectations/matchers/ut_be_between.tps index 79c4ec2fe..9e984085b 100644 --- a/source/expectations/matchers/ut_be_between.tps +++ b/source/expectations/matchers/ut_be_between.tps @@ -1,7 +1,7 @@ create or replace type ut_be_between under ut_matcher( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_empty.tpb b/source/expectations/matchers/ut_be_empty.tpb index 82ad95d5a..e5e02f6b2 100644 --- a/source/expectations/matchers/ut_be_empty.tpb +++ b/source/expectations/matchers/ut_be_empty.tpb @@ -1,7 +1,7 @@ create or replace type body ut_be_empty as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_empty.tps b/source/expectations/matchers/ut_be_empty.tps index 0acb80e55..9e9f899d0 100644 --- a/source/expectations/matchers/ut_be_empty.tps +++ b/source/expectations/matchers/ut_be_empty.tps @@ -1,7 +1,7 @@ create or replace type ut_be_empty under ut_matcher( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_false.tpb b/source/expectations/matchers/ut_be_false.tpb index 6e2f3ba1f..4cc88600a 100644 --- a/source/expectations/matchers/ut_be_false.tpb +++ b/source/expectations/matchers/ut_be_false.tpb @@ -1,7 +1,7 @@ create or replace type body ut_be_false as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_false.tps b/source/expectations/matchers/ut_be_false.tps index 06bb290d4..ede510719 100644 --- a/source/expectations/matchers/ut_be_false.tps +++ b/source/expectations/matchers/ut_be_false.tps @@ -1,7 +1,7 @@ create or replace type ut_be_false under ut_matcher( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_greater_or_equal.tpb b/source/expectations/matchers/ut_be_greater_or_equal.tpb index 978d821e1..1c2a19c09 100644 --- a/source/expectations/matchers/ut_be_greater_or_equal.tpb +++ b/source/expectations/matchers/ut_be_greater_or_equal.tpb @@ -1,7 +1,7 @@ create or replace type body ut_be_greater_or_equal AS /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_greater_or_equal.tps b/source/expectations/matchers/ut_be_greater_or_equal.tps index b97589bb0..b3ab54ff1 100644 --- a/source/expectations/matchers/ut_be_greater_or_equal.tps +++ b/source/expectations/matchers/ut_be_greater_or_equal.tps @@ -1,7 +1,7 @@ create or replace type ut_be_greater_or_equal under ut_comparison_matcher( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_greater_than.tpb b/source/expectations/matchers/ut_be_greater_than.tpb index b7b52af9a..9cce79119 100644 --- a/source/expectations/matchers/ut_be_greater_than.tpb +++ b/source/expectations/matchers/ut_be_greater_than.tpb @@ -1,7 +1,7 @@ create or replace type body ut_be_greater_than AS /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_greater_than.tps b/source/expectations/matchers/ut_be_greater_than.tps index 9963a6277..a5a44692d 100644 --- a/source/expectations/matchers/ut_be_greater_than.tps +++ b/source/expectations/matchers/ut_be_greater_than.tps @@ -1,7 +1,7 @@ create or replace type ut_be_greater_than under ut_comparison_matcher( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_less_or_equal.tpb b/source/expectations/matchers/ut_be_less_or_equal.tpb index 6f6b7febd..6acec1dda 100644 --- a/source/expectations/matchers/ut_be_less_or_equal.tpb +++ b/source/expectations/matchers/ut_be_less_or_equal.tpb @@ -1,7 +1,7 @@ create or replace type body ut_be_less_or_equal AS /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_less_or_equal.tps b/source/expectations/matchers/ut_be_less_or_equal.tps index a9fe9492b..118611a41 100644 --- a/source/expectations/matchers/ut_be_less_or_equal.tps +++ b/source/expectations/matchers/ut_be_less_or_equal.tps @@ -1,7 +1,7 @@ create or replace type ut_be_less_or_equal under ut_comparison_matcher( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_less_than.tpb b/source/expectations/matchers/ut_be_less_than.tpb index 7d3e06d62..7608e4917 100644 --- a/source/expectations/matchers/ut_be_less_than.tpb +++ b/source/expectations/matchers/ut_be_less_than.tpb @@ -1,7 +1,7 @@ create or replace type body ut_be_less_than as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_less_than.tps b/source/expectations/matchers/ut_be_less_than.tps index f6ae1f0e4..b652de789 100644 --- a/source/expectations/matchers/ut_be_less_than.tps +++ b/source/expectations/matchers/ut_be_less_than.tps @@ -1,7 +1,7 @@ create or replace type ut_be_less_than under ut_comparison_matcher( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_like.tpb b/source/expectations/matchers/ut_be_like.tpb index 315f43d6c..6865c2942 100644 --- a/source/expectations/matchers/ut_be_like.tpb +++ b/source/expectations/matchers/ut_be_like.tpb @@ -1,7 +1,7 @@ create or replace type body ut_be_like as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_like.tps b/source/expectations/matchers/ut_be_like.tps index 1e8430e32..dae93a1d9 100644 --- a/source/expectations/matchers/ut_be_like.tps +++ b/source/expectations/matchers/ut_be_like.tps @@ -1,7 +1,7 @@ create or replace type ut_be_like under ut_matcher( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_not_null.tpb b/source/expectations/matchers/ut_be_not_null.tpb index 595a94b75..194e2ea32 100644 --- a/source/expectations/matchers/ut_be_not_null.tpb +++ b/source/expectations/matchers/ut_be_not_null.tpb @@ -1,7 +1,7 @@ create or replace type body ut_be_not_null as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_not_null.tps b/source/expectations/matchers/ut_be_not_null.tps index 42e899701..196aac9fb 100644 --- a/source/expectations/matchers/ut_be_not_null.tps +++ b/source/expectations/matchers/ut_be_not_null.tps @@ -1,7 +1,7 @@ create or replace type ut_be_not_null under ut_matcher( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_null.tpb b/source/expectations/matchers/ut_be_null.tpb index 82a4391d6..8c672791b 100644 --- a/source/expectations/matchers/ut_be_null.tpb +++ b/source/expectations/matchers/ut_be_null.tpb @@ -1,7 +1,7 @@ create or replace type body ut_be_null as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_null.tps b/source/expectations/matchers/ut_be_null.tps index ef30feea1..3b2d6ac84 100644 --- a/source/expectations/matchers/ut_be_null.tps +++ b/source/expectations/matchers/ut_be_null.tps @@ -1,7 +1,7 @@ create or replace type ut_be_null under ut_matcher( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_true.tpb b/source/expectations/matchers/ut_be_true.tpb index 3c83002e0..fe78b4e22 100644 --- a/source/expectations/matchers/ut_be_true.tpb +++ b/source/expectations/matchers/ut_be_true.tpb @@ -1,7 +1,7 @@ create or replace type body ut_be_true as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_true.tps b/source/expectations/matchers/ut_be_true.tps index f73c7700b..8b5491e39 100644 --- a/source/expectations/matchers/ut_be_true.tps +++ b/source/expectations/matchers/ut_be_true.tps @@ -1,7 +1,7 @@ create or replace type ut_be_true under ut_matcher( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_be_within.tpb b/source/expectations/matchers/ut_be_within.tpb new file mode 100644 index 000000000..e2aa792d0 --- /dev/null +++ b/source/expectations/matchers/ut_be_within.tpb @@ -0,0 +1,137 @@ +create or replace type body ut_be_within as + /* + utPLSQL - Version 3 + Copyright 2016 - 2019 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + constructor function ut_be_within(self in out nocopy ut_be_within, a_distance_from_expected number) return self as result is + begin + self.init(ut_data_value_number(a_distance_from_expected), $$plsql_unit); + return; + end; + + constructor function ut_be_within(self in out nocopy ut_be_within, a_distance_from_expected dsinterval_unconstrained) return self as result is + begin + self.init(ut_data_value_dsinterval(a_distance_from_expected), $$plsql_unit); + return; + end; + + constructor function ut_be_within(self in out nocopy ut_be_within, a_distance_from_expected yminterval_unconstrained) return self as result is + begin + self.init(ut_data_value_yminterval(a_distance_from_expected), $$plsql_unit); + return; + end; + + member procedure of_(self in ut_be_within, a_expected date) is + l_result ut_be_within := self; + begin + l_result.expected := ut_data_value_date(a_expected); + if l_result.is_negated_flag = 1 then + l_result.expectation.not_to(l_result); + else + l_result.expectation.to_(l_result); + end if; + end; + + member function of_(self in ut_be_within, a_expected date) return ut_be_within is + l_result ut_be_within := self; + begin + l_result.expected := ut_data_value_date(a_expected); + return l_result; + end; + + member procedure of_(self in ut_be_within, a_expected timestamp_unconstrained) is + l_result ut_be_within := self; + begin + l_result.expected := ut_data_value_timestamp(a_expected); + if l_result.is_negated_flag = 1 then + l_result.expectation.not_to(l_result); + else + l_result.expectation.to_(l_result); + end if; + end; + + member function of_(self in ut_be_within, a_expected timestamp_unconstrained) return ut_be_within is + l_result ut_be_within := self; + begin + l_result.expected := ut_data_value_timestamp(a_expected); + return l_result; + end; + + member procedure of_(self in ut_be_within, a_expected timestamp_tz_unconstrained) is + l_result ut_be_within := self; + begin + l_result.expected := ut_data_value_timestamp_tz(a_expected); + if l_result.is_negated_flag = 1 then + l_result.expectation.not_to(l_result); + else + l_result.expectation.to_(l_result); + end if; + end; + + member function of_(self in ut_be_within, a_expected timestamp_tz_unconstrained) return ut_be_within is + l_result ut_be_within := self; + begin + l_result.expected := ut_data_value_timestamp_tz(a_expected); + return l_result; + end; + + member procedure of_(self in ut_be_within, a_expected timestamp_ltz_unconstrained) is + l_result ut_be_within := self; + begin + l_result.expected := ut_data_value_timestamp_ltz(a_expected); + if l_result.is_negated_flag = 1 then + l_result.expectation.not_to(l_result); + else + l_result.expectation.to_(l_result); + end if; + end; + + member function of_(self in ut_be_within, a_expected timestamp_ltz_unconstrained) return ut_be_within is + l_result ut_be_within := self; + begin + l_result.expected := ut_data_value_timestamp_ltz(a_expected); + return l_result; + end; + + overriding member function run_matcher(self in out nocopy ut_be_within, a_actual ut_data_value) return boolean is + l_result boolean; + begin + if self.expected.data_type = a_actual.data_type + and ( + self.expected is of (ut_data_value_date, ut_data_value_timestamp, ut_data_value_timestamp_tz, ut_data_value_timestamp_ltz) + and self.distance_from_expected is of (ut_data_value_yminterval, ut_data_value_dsinterval) + or self.expected is of (ut_data_value_number) and self.distance_from_expected is of (ut_data_value_number) + ) + then + l_result := ut_be_within_helper.values_within_abs_distance( a_actual, self.expected, self.distance_from_expected) ; + else + l_result := (self as ut_matcher).run_matcher(a_actual); + end if; + return l_result; + end; + + overriding member function failure_message(a_actual ut_data_value) return varchar2 is + begin + return (self as ut_matcher).failure_message(a_actual) || ' '||self.distance_from_expected.to_string ||' of '|| expected.to_string_report(); + end; + + overriding member function failure_message_when_negated(a_actual ut_data_value) return varchar2 is + begin + return (self as ut_matcher).failure_message_when_negated(a_actual) || ' '||self.distance_from_expected.to_string ||' of '|| expected.to_string_report(); + end; + +end; +/ diff --git a/source/expectations/matchers/ut_be_within.tps b/source/expectations/matchers/ut_be_within.tps new file mode 100644 index 000000000..576f9ff37 --- /dev/null +++ b/source/expectations/matchers/ut_be_within.tps @@ -0,0 +1,36 @@ +create or replace type ut_be_within force under ut_be_within_pct( + /* + utPLSQL - Version 3 + Copyright 2016 - 2019 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + + constructor function ut_be_within(self in out nocopy ut_be_within, a_distance_from_expected number) return self as result, + constructor function ut_be_within(self in out nocopy ut_be_within, a_distance_from_expected dsinterval_unconstrained) return self as result, + constructor function ut_be_within(self in out nocopy ut_be_within, a_distance_from_expected yminterval_unconstrained) return self as result, + member procedure of_(self in ut_be_within, a_expected date), + member function of_(self in ut_be_within, a_expected date) return ut_be_within, + member procedure of_(self in ut_be_within, a_expected timestamp_unconstrained), + member function of_(self in ut_be_within, a_expected timestamp_unconstrained) return ut_be_within, + member procedure of_(self in ut_be_within, a_expected timestamp_tz_unconstrained ), + member function of_(self in ut_be_within, a_expected timestamp_tz_unconstrained) return ut_be_within, + member procedure of_(self in ut_be_within, a_expected timestamp_ltz_unconstrained), + member function of_(self in ut_be_within, a_expected timestamp_ltz_unconstrained) return ut_be_within, + overriding member function run_matcher(self in out nocopy ut_be_within, a_actual ut_data_value) return boolean, + overriding member function failure_message(a_actual ut_data_value) return varchar2, + overriding member function failure_message_when_negated(a_actual ut_data_value) return varchar2 +) +not final +/ diff --git a/source/expectations/matchers/ut_be_within_helper.pkb b/source/expectations/matchers/ut_be_within_helper.pkb new file mode 100644 index 000000000..5dd82baa2 --- /dev/null +++ b/source/expectations/matchers/ut_be_within_helper.pkb @@ -0,0 +1,55 @@ +create or replace package body ut_be_within_helper as + /* + utPLSQL - Version 3 + Copyright 2016 - 2019 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 values_within_abs_distance( + a_actual ut_data_value, a_expected ut_data_value, a_distance ut_data_value + ) return boolean is + l_result integer; + l_YM_conversion varchar2(50) := case when a_distance is of (ut_data_value_yminterval) then ' year to month ' end; + l_formula varchar2(4000); + l_code varchar2(4000); + begin + l_formula := + case + when a_actual is of (ut_data_value_date) + then '( cast(greatest(l_actual, l_expected) as timestamp) - cast(least(l_actual, l_expected) as timestamp) ) '||l_YM_conversion||' <= l_distance' + else '( greatest(l_actual, l_expected) - least(l_actual, l_expected) ) '||l_YM_conversion||' <= l_distance' + end; + l_code := + q'[ + declare + l_actual ]'||dbms_assert.simple_sql_name(a_actual.data_type_plsql)|| q'[ := treat(:a_actual as ]'||dbms_assert.simple_sql_name(a_actual.self_type)||q'[).data_value; + l_expected ]'||dbms_assert.simple_sql_name(a_expected.data_type_plsql)||q'[ := treat(:a_expected as ]'||dbms_assert.simple_sql_name(a_expected.self_type)||q'[).data_value; + l_distance ]'||dbms_assert.simple_sql_name(a_distance.data_type_plsql)||q'[ := treat(:a_distance as ]'||dbms_assert.simple_sql_name(a_distance.self_type)||q'[).data_value; + begin + :result := + case + when + ]'||l_formula||q'[ + then 1 + else 0 + end; + end; + ]'; + execute immediate l_code + using a_actual, a_expected, a_distance, out l_result; + return l_result > 0; + end; + +end; +/ diff --git a/source/expectations/matchers/ut_be_within_helper.pks b/source/expectations/matchers/ut_be_within_helper.pks new file mode 100644 index 000000000..41737cc8f --- /dev/null +++ b/source/expectations/matchers/ut_be_within_helper.pks @@ -0,0 +1,24 @@ +create or replace package ut_be_within_helper authid definer as + /* + utPLSQL - Version 3 + Copyright 2016 - 2019 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 values_within_abs_distance( + a_actual ut_data_value, a_expected ut_data_value, a_distance ut_data_value + ) return boolean; + +end; +/ diff --git a/source/expectations/matchers/ut_be_within_pct.tpb b/source/expectations/matchers/ut_be_within_pct.tpb new file mode 100644 index 000000000..8b280ffff --- /dev/null +++ b/source/expectations/matchers/ut_be_within_pct.tpb @@ -0,0 +1,84 @@ +create or replace type body ut_be_within_pct as + /* + utPLSQL - Version 3 + Copyright 2016 - 2019 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + constructor function ut_be_within_pct(self in out nocopy ut_be_within_pct, a_pct_of_expected number) return self as result is + begin + self.init(ut_data_value_number(a_pct_of_expected), $$plsql_unit); + return; + end; + + member procedure init(self in out nocopy ut_be_within_pct, a_distance_from_expected ut_data_value, self_type varchar2) is + begin + self.distance_from_expected := a_distance_from_expected; + self.self_type := self_type; + end; + + member procedure of_(self in ut_be_within_pct, a_expected number) is + l_result ut_be_within_pct := self; + begin + l_result.expected := ut_data_value_number(a_expected); + if l_result.is_negated_flag = 1 then + l_result.expectation.not_to(l_result); + else + l_result.expectation.to_(l_result); + end if; + end; + + member function of_(self in ut_be_within_pct, a_expected number) return ut_be_within_pct is + l_result ut_be_within_pct := self; + begin + l_result.expected := ut_data_value_number(a_expected); + return l_result; + end; + + overriding member function run_matcher(self in out nocopy ut_be_within_pct, a_actual ut_data_value) return boolean is + l_result boolean; + begin + if self.expected.data_type = a_actual.data_type then + if self.expected is of (ut_data_value_number) then + l_result := + abs(treat(self.distance_from_expected as ut_data_value_number).data_value) * treat(self.expected as ut_data_value_number).data_value + >= abs( ( treat(self.expected as ut_data_value_number).data_value - treat(a_actual as ut_data_value_number).data_value ) * 100 ); + end if; + else + l_result := (self as ut_matcher).run_matcher(a_actual); + end if; + return l_result; + end; + + overriding member function failure_message(a_actual ut_data_value) return varchar2 is + begin + return rtrim( (self as ut_matcher).failure_message(a_actual), 'pct' ) || self.distance_from_expected.to_string ||' % of '|| expected.to_string_report(); + end; + + overriding member function failure_message_when_negated(a_actual ut_data_value) return varchar2 is + begin + return rtrim( (self as ut_matcher).failure_message_when_negated(a_actual), 'pct' ) || self.distance_from_expected.to_string ||' % of '|| expected.to_string_report(); + end; + + overriding member function error_message(a_actual ut_data_value) return varchar2 is + l_result varchar2(32767); + begin + if ut_utils.int_to_boolean(self.is_errored) then + l_result := 'Matcher '''||self.name()||''' cannot be used to compare Actual ('||a_actual.data_type||') with Expected ('||expected.data_type||') using distance ('||self.distance_from_expected.data_type||').'; + end if; + return l_result; + end; + +end; +/ diff --git a/source/expectations/matchers/ut_be_within_pct.tps b/source/expectations/matchers/ut_be_within_pct.tps new file mode 100644 index 000000000..499e9a2d8 --- /dev/null +++ b/source/expectations/matchers/ut_be_within_pct.tps @@ -0,0 +1,35 @@ +create or replace type ut_be_within_pct force under ut_comparison_matcher( + /* + utPLSQL - Version 3 + Copyright 2016 - 2019 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. + */ + + + /** + * Holds information about mather options + */ + distance_from_expected ut_data_value, + + constructor function ut_be_within_pct(self in out nocopy ut_be_within_pct, a_pct_of_expected number) return self as result, + member procedure init(self in out nocopy ut_be_within_pct, a_distance_from_expected ut_data_value, self_type varchar2), + member procedure of_(self in ut_be_within_pct, a_expected number), + member function of_(self in ut_be_within_pct, a_expected number) return ut_be_within_pct, + overriding member function run_matcher(self in out nocopy ut_be_within_pct, a_actual ut_data_value) return boolean, + overriding member function failure_message(a_actual ut_data_value) return varchar2, + overriding member function failure_message_when_negated(a_actual ut_data_value) return varchar2, + overriding member function error_message(a_actual ut_data_value) return varchar2 +) +not final +/ diff --git a/source/expectations/matchers/ut_comparison_matcher.tpb b/source/expectations/matchers/ut_comparison_matcher.tpb index 6eec4c11a..20ed35927 100644 --- a/source/expectations/matchers/ut_comparison_matcher.tpb +++ b/source/expectations/matchers/ut_comparison_matcher.tpb @@ -1,7 +1,7 @@ create or replace type body ut_comparison_matcher as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_comparison_matcher.tps b/source/expectations/matchers/ut_comparison_matcher.tps index d66ad8b56..68ecb4462 100644 --- a/source/expectations/matchers/ut_comparison_matcher.tps +++ b/source/expectations/matchers/ut_comparison_matcher.tps @@ -1,7 +1,7 @@ create or replace type ut_comparison_matcher under ut_matcher( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_contain.tpb b/source/expectations/matchers/ut_contain.tpb new file mode 100644 index 000000000..c9691f731 --- /dev/null +++ b/source/expectations/matchers/ut_contain.tpb @@ -0,0 +1,74 @@ +create or replace type body ut_contain as + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + constructor function ut_contain(self in out nocopy ut_contain, a_expected sys_refcursor) return self as result is + begin + self.init(ut_data_value_refcursor(a_expected), null, $$plsql_unit); + self.options.unordered(); + return; + end; + + constructor function ut_contain(self in out nocopy ut_contain, a_expected anydata) return self as result is + begin + self.init(ut_data_value_anydata(a_expected), null, $$plsql_unit); + self.options.unordered(); + return; + end; + + overriding member function run_matcher(self in out nocopy ut_contain, a_actual ut_data_value) return boolean is + l_result boolean; + begin + if self.expected.data_type = a_actual.data_type then + l_result := + ( 0 + = treat( self.expected as ut_data_value_refcursor ) + .compare_implementation( a_actual, self.options, true, self.is_negated() ) + ); + else + l_result := (self as ut_matcher).run_matcher(a_actual); + end if; + return l_result; + end; + + overriding member function run_matcher_negated(self in out nocopy ut_contain, a_actual ut_data_value) return boolean is + begin + self.negated(); + return run_matcher(a_actual); + end; + + overriding member function failure_message(a_actual ut_data_value) return varchar2 is + l_result varchar2(32767); + begin + if self.expected.data_type = a_actual.data_type and self.expected.is_diffable then + l_result := + 'Actual: '||a_actual.get_object_info()||self.description()||': '||self.expected.get_object_info() + || treat(expected as ut_data_value_refcursor).diff( a_actual, self.options ); + else + l_result := (self as ut_matcher).failure_message(a_actual) || ': '|| self.expected.to_string_report(); + end if; + return l_result; + end; + + overriding member function failure_message_when_negated(a_actual ut_data_value) return varchar2 is + l_result varchar2(32767); + begin + return (self as ut_matcher).failure_message_when_negated(a_actual) || ':'|| expected.to_string_report(); + end; + +end; +/ diff --git a/source/expectations/matchers/ut_contain.tps b/source/expectations/matchers/ut_contain.tps new file mode 100644 index 000000000..e572edf62 --- /dev/null +++ b/source/expectations/matchers/ut_contain.tps @@ -0,0 +1,33 @@ +create or replace type ut_contain under ut_equal( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + */ + + /** + * Due to nature of inclusion compare the not is bit diffrente than standard. + * Result is false when even one element belongs which can cause overlap. + * e.g. set can fail at same time not_include and include. By that we mean + * that false include not necessary mean true not include. + */ + + constructor function ut_contain(self in out nocopy ut_contain, a_expected sys_refcursor) return self as result, + constructor function ut_contain(self in out nocopy ut_contain, a_expected anydata) return self as result, + overriding member function run_matcher(self in out nocopy ut_contain, a_actual ut_data_value) return boolean, + overriding member function run_matcher_negated(self in out nocopy ut_contain, a_actual ut_data_value) return boolean, + overriding member function failure_message(a_actual ut_data_value) return varchar2, + overriding member function failure_message_when_negated(a_actual ut_data_value) return varchar2 +) +/ diff --git a/source/expectations/matchers/ut_equal.tpb b/source/expectations/matchers/ut_equal.tpb index 611b1cd1c..d514e34d0 100644 --- a/source/expectations/matchers/ut_equal.tpb +++ b/source/expectations/matchers/ut_equal.tpb @@ -1,7 +1,7 @@ create or replace type body ut_equal as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -16,25 +16,22 @@ create or replace type body ut_equal as limitations under the License. */ - member procedure init(self in out nocopy ut_equal, a_expected ut_data_value, a_nulls_are_equal boolean) is + member procedure init(self in out nocopy ut_equal, a_expected ut_data_value, a_nulls_are_equal boolean, a_self_type varchar2 := null) is begin - self.nulls_are_equal_flag := ut_utils.boolean_to_int( coalesce(a_nulls_are_equal, ut_expectation_processor.nulls_are_equal()) ); - self.self_type := $$plsql_unit; self.expected := a_expected; - self.include_list := ut_varchar2_list(); - self.exclude_list := ut_varchar2_list(); - self.join_columns := ut_varchar2_list(); + self.options := ut_matcher_options( a_nulls_are_equal ); + self.self_type := nvl( a_self_type, $$plsql_unit ); end; - + member function equal_with_nulls(a_assert_result boolean, a_actual ut_data_value) return boolean is begin ut_utils.debug_log('ut_equal.equal_with_nulls :' || ut_utils.to_test_result(a_assert_result) || ':'); - return ( a_assert_result or ( self.expected.is_null() and a_actual.is_null() and ut_utils.int_to_boolean( nulls_are_equal_flag ) ) ); + return ( a_assert_result or ( self.expected.is_null() and a_actual.is_null() and options.nulls_are_equal ) ); end; constructor function ut_equal(self in out nocopy ut_equal, a_expected anydata, a_nulls_are_equal boolean := null) return self as result is begin - init(ut_data_value_anydata.get_instance(a_expected), a_nulls_are_equal); + init(ut_data_value_anydata(a_expected), a_nulls_are_equal); return; end; @@ -45,8 +42,8 @@ create or replace type body ut_equal as 'equal( a_expected anydata, a_exclude varchar2 )', 'equal( a_expected anydata ).exclude( a_exclude varchar2 )' ); - init(ut_data_value_anydata.get_instance(a_expected), a_nulls_are_equal); - exclude_list := ut_varchar2_list(a_exclude); + init(ut_data_value_anydata(a_expected), a_nulls_are_equal); + self.options.exclude.add_items(a_exclude); return; end; @@ -56,8 +53,8 @@ create or replace type body ut_equal as 'equal( a_expected anydata, a_exclude ut_varchar2_list )', 'equal( a_expected anydata ).exclude( a_exclude ut_varchar2_list )' ); - init(ut_data_value_anydata.get_instance(a_expected), a_nulls_are_equal); - exclude_list := coalesce(a_exclude, ut_varchar2_list()); + init(ut_data_value_anydata(a_expected), a_nulls_are_equal); + self.options.exclude.add_items(a_exclude); return; end; @@ -104,7 +101,7 @@ create or replace type body ut_equal as 'equal( a_expected sys_refcursor ).exclude( a_exclude varchar2 )' ); init(ut_data_value_refcursor(a_expected), a_nulls_are_equal); - exclude_list := ut_varchar2_list(a_exclude); + self.options.exclude.add_items(a_exclude); return; end; @@ -115,7 +112,7 @@ create or replace type body ut_equal as 'equal( a_expected sys_refcursor ).exclude( a_exclude ut_varchar2_list )' ); init(ut_data_value_refcursor(a_expected), a_nulls_are_equal); - exclude_list := coalesce(a_exclude, ut_varchar2_list()); + self.options.exclude.add_items(a_exclude); return; end; @@ -155,75 +152,135 @@ create or replace type body ut_equal as return; end; + constructor function ut_equal(self in out nocopy ut_equal, a_expected json_element_t, a_nulls_are_equal boolean := null) return self as result is + begin + init(ut_data_value_json(a_expected), a_nulls_are_equal); + return; + end; + + constructor function ut_equal(self in out nocopy ut_equal, a_expected json, a_nulls_are_equal boolean := null) return self as result is + begin + init(ut_data_value_json(a_expected), a_nulls_are_equal); + return; + end; + member function include(a_items varchar2) return ut_equal is l_result ut_equal := self; begin - ut_utils.append_to_list(l_result.include_list, a_items); + l_result.options.include.add_items(a_items); return l_result; end; member function include(a_items ut_varchar2_list) return ut_equal is l_result ut_equal := self; begin - l_result.include_list := l_result.include_list multiset union all coalesce(a_items,ut_varchar2_list()); + l_result.options.include.add_items(a_items); return l_result; end; + member procedure include(self in ut_equal, a_items varchar2) is + begin + include( ut_varchar2_list( a_items ) ); + end; + + member procedure include(self in ut_equal, a_items ut_varchar2_list) is + l_result ut_equal := self; + begin + l_result.options.include.add_items(a_items); + l_result.expectation.to_(l_result ); + end; + member function exclude(a_items varchar2) return ut_equal is l_result ut_equal := self; begin - ut_utils.append_to_list(l_result.exclude_list, a_items); + l_result.options.exclude.add_items(a_items); return l_result; end; member function exclude(a_items ut_varchar2_list) return ut_equal is l_result ut_equal := self; begin - l_result.exclude_list := l_result.exclude_list multiset union all coalesce(a_items,ut_varchar2_list()); + l_result.options.exclude.add_items(a_items); return l_result; end; + member procedure exclude(self in ut_equal, a_items varchar2) is + begin + exclude( ut_varchar2_list( a_items ) ); + end; + + member procedure exclude(self in ut_equal, a_items ut_varchar2_list) is + l_result ut_equal := self; + begin + l_result.options.exclude.add_items(a_items); + l_result.expectation.to_(l_result ); + end; + member function unordered return ut_equal is l_result ut_equal := self; begin - l_result.is_unordered := ut_utils.boolean_to_int(true); + l_result.options.unordered(); return l_result; end; + member procedure unordered(self in ut_equal) is + l_result ut_equal := self; + begin + l_result.options.unordered(); + l_result.expectation.to_(l_result ); + end; + member function join_by(a_columns varchar2) return ut_equal is l_result ut_equal := self; begin - l_result.is_unordered := ut_utils.boolean_to_int(true); - ut_utils.append_to_list(l_result.join_columns, a_columns); + l_result.options.unordered(); + l_result.options.join_by.add_items(a_columns); return l_result; end; member function join_by(a_columns ut_varchar2_list) return ut_equal is l_result ut_equal := self; begin - l_result.is_unordered := ut_utils.boolean_to_int(true); - l_result.join_columns := l_result.join_columns multiset union all coalesce(a_columns,ut_varchar2_list()); + l_result.options.unordered(); + l_result.options.join_by.add_items(a_columns); return l_result; end; - member function get_include_xpath return varchar2 is + member procedure join_by(self in ut_equal, a_columns varchar2) is begin - return ut_utils.to_xpath( coalesce(include_list, ut_varchar2_list()) ); + join_by( ut_varchar2_list( a_columns ) ); end; - - member function get_exclude_xpath return varchar2 is + + member procedure join_by(self in ut_equal, a_columns ut_varchar2_list) is + l_result ut_equal := self; begin - return ut_utils.to_xpath( coalesce(exclude_list, ut_varchar2_list()) ); + l_result.options.unordered(); + l_result.options.join_by.add_items(a_columns); + l_result.expectation.to_(l_result ); + end; + + member function unordered_columns return ut_equal is + l_result ut_equal := self; + begin + l_result.options.unordered_columns(); + return l_result; end; - member function get_unordered return boolean is + member procedure unordered_columns(self in ut_equal) is + l_result ut_equal := self; begin - return ut_utils.int_to_boolean(nvl(is_unordered,0)); + l_result.options.unordered_columns(); + l_result.expectation.to_(l_result ); end; - member function get_join_by_xpath return varchar2 is + member function uc return ut_equal is + begin + return unordered_columns; + end; + + member procedure uc(self in ut_equal) is begin - return ut_utils.to_xpath( coalesce(join_columns, ut_varchar2_list()) ); + unordered_columns; end; overriding member function run_matcher(self in out nocopy ut_equal, a_actual ut_data_value) return boolean is @@ -231,9 +288,9 @@ create or replace type body ut_equal as begin if self.expected.data_type = a_actual.data_type then if self.expected is of (ut_data_value_anydata) then - l_result := 0 = treat(self.expected as ut_data_value_anydata).compare_implementation(a_actual, get_exclude_xpath(), get_include_xpath()); + l_result := 0 = treat(self.expected as ut_data_value_anydata).compare_implementation( a_actual, options ); elsif self.expected is of (ut_data_value_refcursor) then - l_result := 0 = treat(self.expected as ut_data_value_refcursor).compare_implementation(a_actual, get_exclude_xpath(), get_include_xpath(), get_join_by_xpath(), get_unordered()); + l_result := 0 = treat(self.expected as ut_data_value_refcursor).compare_implementation( a_actual, options ); else l_result := equal_with_nulls((self.expected = a_actual), a_actual); end if; @@ -248,9 +305,16 @@ create or replace type body ut_equal as l_result varchar2(32767); begin if self.expected.data_type = a_actual.data_type and self.expected.is_diffable then - l_result := - 'Actual: '||a_actual.get_object_info()||' '||self.description()||': '||self.expected.get_object_info() - || chr(10) || 'Diff:' || expected.diff(a_actual, get_exclude_xpath(), get_include_xpath(), get_join_by_xpath(), get_unordered()); + l_result := + 'Actual: '||a_actual.get_object_info()||self.description()||': '||self.expected.get_object_info() + ||case + when self.expected is of (ut_data_value_refcursor) then + treat(expected as ut_data_value_refcursor).diff( a_actual, options ) + when self.expected is of (ut_data_value_json) then + treat(expected as ut_data_value_json).diff( a_actual, options ) + else + expected.diff( a_actual, options ) + end; else l_result := (self as ut_matcher).failure_message(a_actual) || ': '|| self.expected.to_string_report(); end if; diff --git a/source/expectations/matchers/ut_equal.tps b/source/expectations/matchers/ut_equal.tps index 9968dba7f..e48b797ed 100644 --- a/source/expectations/matchers/ut_equal.tps +++ b/source/expectations/matchers/ut_equal.tps @@ -1,7 +1,7 @@ -create or replace type ut_equal under ut_comparison_matcher( +create or replace type ut_equal force under ut_comparison_matcher( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -15,28 +15,14 @@ create or replace type ut_equal under ut_comparison_matcher( See the License for the specific language governing permissions and limitations under the License. */ - nulls_are_equal_flag number(1,0), - /** - * Holds (list of columns/attributes) to exclude when comparing compound types - */ - exclude_list ut_varchar2_list, - /** - * Holds (list of columns/attributes) to incude when comparing compound types - */ - include_list ut_varchar2_list, - - /** - * Holds value if comparision on refcursor to be performed as unordered set - */ - is_unordered number(1,0), /** - * Holds list of columns to be used as a join PK on sys_refcursor comparision - */ - join_columns ut_varchar2_list, - - member procedure init(self in out nocopy ut_equal, a_expected ut_data_value, a_nulls_are_equal boolean), + * Holds information about mather options + */ + options ut_matcher_options, + + member procedure init(self in out nocopy ut_equal, a_expected ut_data_value, a_nulls_are_equal boolean, a_self_type varchar2 := null), member function equal_with_nulls( self in ut_equal, a_assert_result boolean, a_actual ut_data_value) return boolean, constructor function ut_equal(self in out nocopy ut_equal, a_expected anydata, a_nulls_are_equal boolean := null) return self as result, constructor function ut_equal(self in out nocopy ut_equal, a_expected anydata, a_exclude varchar2, a_nulls_are_equal boolean := null) return self as result, @@ -55,19 +41,29 @@ create or replace type ut_equal under ut_comparison_matcher( constructor function ut_equal(self in out nocopy ut_equal, a_expected varchar2, a_nulls_are_equal boolean := null) return self as result, constructor function ut_equal(self in out nocopy ut_equal, a_expected yminterval_unconstrained, a_nulls_are_equal boolean := null) return self as result, constructor function ut_equal(self in out nocopy ut_equal, a_expected dsinterval_unconstrained, a_nulls_are_equal boolean := null) return self as result, + constructor function ut_equal(self in out nocopy ut_equal, a_expected json_element_t, a_nulls_are_equal boolean := null) return self as result, + constructor function ut_equal(self in out nocopy ut_equal, a_expected json, a_nulls_are_equal boolean := null) return self as result, member function include(a_items varchar2) return ut_equal, - member function include(a_items ut_varchar2_list) return ut_equal, + member function include(a_items ut_varchar2_list) return ut_equal, + member procedure include(self in ut_equal, a_items varchar2), + member procedure include(self in ut_equal, a_items ut_varchar2_list), member function exclude(a_items varchar2) return ut_equal, member function exclude(a_items ut_varchar2_list) return ut_equal, + member procedure exclude(self in ut_equal, a_items varchar2), + member procedure exclude(self in ut_equal, a_items ut_varchar2_list), member function unordered return ut_equal, + member procedure unordered(self in ut_equal), member function join_by(a_columns varchar2) return ut_equal, member function join_by(a_columns ut_varchar2_list) return ut_equal, - member function get_include_xpath return varchar2, - member function get_exclude_xpath return varchar2, - member function get_unordered return boolean, - member function get_join_by_xpath return varchar2, + member procedure join_by(self in ut_equal, a_columns varchar2), + member procedure join_by(self in ut_equal, a_columns ut_varchar2_list), overriding member function run_matcher(self in out nocopy ut_equal, a_actual ut_data_value) return boolean, overriding member function failure_message(a_actual ut_data_value) return varchar2, - overriding member function failure_message_when_negated(a_actual ut_data_value) return varchar2 + overriding member function failure_message_when_negated(a_actual ut_data_value) return varchar2, + member function unordered_columns return ut_equal, + member procedure unordered_columns(self in ut_equal), + member function uc return ut_equal, + member procedure uc(self in ut_equal) ) +not final / diff --git a/source/expectations/matchers/ut_have_count.tpb b/source/expectations/matchers/ut_have_count.tpb index de2d64d1c..457cd6272 100644 --- a/source/expectations/matchers/ut_have_count.tpb +++ b/source/expectations/matchers/ut_have_count.tpb @@ -1,7 +1,7 @@ create or replace type body ut_have_count as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -26,8 +26,10 @@ create or replace type body ut_have_count as overriding member function run_matcher(self in out nocopy ut_have_count, a_actual ut_data_value) return boolean is l_result boolean; begin - if a_actual is of(ut_data_value_refcursor, ut_data_value_collection) then - l_result := ( self.expected = treat(a_actual as ut_compound_data_value).elements_count ); + if a_actual is of(ut_data_value_refcursor) and ( treat (a_actual as ut_data_value_refcursor).compound_type != 'object') then + l_result := ( self.expected = treat(a_actual as ut_data_value_refcursor).elements_count ); + elsif a_actual is of(ut_data_value_json) then + l_result := ( self.expected = treat(a_actual as ut_data_value_json).get_elements_count ); else l_result := (self as ut_matcher).run_matcher(a_actual); end if; @@ -36,12 +38,16 @@ create or replace type body ut_have_count as overriding member function failure_message(a_actual ut_data_value) return varchar2 is begin - return 'Actual: (' || a_actual.get_object_info()||') was expected to have [ count = '||ut_utils.to_string(self.expected)||' ]'; + return 'Actual: (' || case when a_actual is of (ut_data_value_json) then + treat(a_actual as ut_data_value_json).get_json_count_info() else a_actual.get_object_info() end|| + ') was expected to have [ count = '||ut_utils.to_string(self.expected)||' ]'; end; overriding member function failure_message_when_negated(a_actual ut_data_value) return varchar2 is begin - return 'Actual: ' || a_actual.get_object_info()||' was expected not to have [ count = '||ut_utils.to_string(self.expected)||' ]'; + return 'Actual: ' || case when a_actual is of (ut_data_value_json) then + treat(a_actual as ut_data_value_json).get_json_count_info() else a_actual.get_object_info() end|| + ' was expected not to have [ count = '||ut_utils.to_string(self.expected)||' ]'; end; end; diff --git a/source/expectations/matchers/ut_have_count.tps b/source/expectations/matchers/ut_have_count.tps index dc4511d72..d48dc44c8 100644 --- a/source/expectations/matchers/ut_have_count.tps +++ b/source/expectations/matchers/ut_have_count.tps @@ -1,7 +1,7 @@ create or replace type ut_have_count under ut_matcher( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_match.tpb b/source/expectations/matchers/ut_match.tpb index f85af4aac..3c7a71402 100644 --- a/source/expectations/matchers/ut_match.tpb +++ b/source/expectations/matchers/ut_match.tpb @@ -1,7 +1,7 @@ create or replace type body ut_match as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_match.tps b/source/expectations/matchers/ut_match.tps index ca9fcd34c..ee51a4c28 100644 --- a/source/expectations/matchers/ut_match.tps +++ b/source/expectations/matchers/ut_match.tps @@ -1,7 +1,7 @@ create or replace type ut_match under ut_matcher( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/expectations/matchers/ut_matcher.tpb b/source/expectations/matchers/ut_matcher.tpb index 78b05a827..6b5b98465 100644 --- a/source/expectations/matchers/ut_matcher.tpb +++ b/source/expectations/matchers/ut_matcher.tpb @@ -1,7 +1,7 @@ create or replace type body ut_matcher as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -20,11 +20,6 @@ create or replace type body ut_matcher as begin ut_utils.debug_log('Failure - ut_matcher.run_matcher'||'(a_actual '||a_actual.data_type||')'); self.is_errored := ut_utils.boolean_to_int(true); --- self.error_message := 'The matcher '''||name()||''' cannot be used'; --- if self.expected is not null then --- self.error_message := self.error_message ||' for comparison of data type ('||self.expected.data_type||')'; --- end if; --- self.error_message := self.error_message ||' with data type ('||a_actual.data_type||').'; return null; end; @@ -40,12 +35,12 @@ create or replace type body ut_matcher as member function description return varchar2 is begin - return 'was expected to '||name(); + return ' was expected to '||name(); end; member function description_when_negated return varchar2 is begin - return 'was expected not to '||name(); + return ' was expected not to '||name(); end; member function error_message(a_actual ut_data_value) return varchar2 is @@ -67,5 +62,22 @@ create or replace type body ut_matcher as return 'Actual: ' || a_actual.to_string_report(true) || description_when_negated(); end; + member procedure negated is + begin + is_negated_flag := ut_utils.boolean_to_int(true); + end; + + member function negated return ut_matcher is + l_result ut_matcher := self; + begin + l_result.negated(); + return l_result; + end; + + member function is_negated return boolean is + begin + return coalesce(ut_utils.int_to_boolean(is_negated_flag), false); + end; + end; / diff --git a/source/expectations/matchers/ut_matcher.tps b/source/expectations/matchers/ut_matcher.tps index 7aefb8ad9..a034e4ed2 100644 --- a/source/expectations/matchers/ut_matcher.tps +++ b/source/expectations/matchers/ut_matcher.tps @@ -1,7 +1,7 @@ -create or replace type ut_matcher authid current_user as object( +create or replace type ut_matcher under ut_matcher_base( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -15,9 +15,9 @@ create or replace type ut_matcher authid current_user as object( See the License for the specific language governing permissions and limitations under the License. */ - self_type varchar2(250), is_errored integer, - + is_negated_flag number(1,0), + expectation ut_expectation_base, /* function: run_matcher @@ -35,6 +35,9 @@ create or replace type ut_matcher authid current_user as object( member function description_when_negated return varchar2, member function error_message(a_actual ut_data_value) return varchar2, member function failure_message(a_actual ut_data_value) return varchar2, - member function failure_message_when_negated(a_actual ut_data_value) return varchar2 + member function failure_message_when_negated(a_actual ut_data_value) return varchar2, + member procedure negated, + member function negated return ut_matcher, + member function is_negated return boolean ) not final not instantiable / diff --git a/source/expectations/matchers/ut_matcher_base.tps b/source/expectations/matchers/ut_matcher_base.tps new file mode 100644 index 000000000..ef7fd98a2 --- /dev/null +++ b/source/expectations/matchers/ut_matcher_base.tps @@ -0,0 +1,5 @@ +create or replace type ut_matcher_base force authid current_user as object( + self_type varchar2(250) +) +not final not instantiable +/ diff --git a/source/expectations/matchers/ut_matcher_options.tpb b/source/expectations/matchers/ut_matcher_options.tpb new file mode 100644 index 000000000..8730c204b --- /dev/null +++ b/source/expectations/matchers/ut_matcher_options.tpb @@ -0,0 +1,60 @@ +create or replace type body ut_matcher_options as + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + constructor function ut_matcher_options(self in out nocopy ut_matcher_options, a_nulls_are_equal in boolean := null) return self as result is + begin + nulls_are_equal_flag := ut_utils.boolean_to_int( coalesce(a_nulls_are_equal, ut_expectation_processor.nulls_are_equal()) ); + is_unordered := ut_utils.boolean_to_int(false); + columns_are_unordered_flag := ut_utils.boolean_to_int(false); + include := ut_matcher_options_items(); + exclude := ut_matcher_options_items(); + join_by := ut_matcher_options_items(); + return; + end; + + member procedure nulls_are_equal(self in out nocopy ut_matcher_options) is + begin + self.nulls_are_equal_flag := ut_utils.boolean_to_int(true); + end; + + member function nulls_are_equal return boolean is + begin + return ut_utils.int_to_boolean(self.nulls_are_equal_flag); + end; + + member procedure unordered_columns(self in out nocopy ut_matcher_options) is + begin + columns_are_unordered_flag := ut_utils.boolean_to_int(true); + end; + + member function ordered_columns return boolean is + begin + return not ut_utils.int_to_boolean(columns_are_unordered_flag); + end; + + member procedure unordered(self in out nocopy ut_matcher_options) is + begin + is_unordered := ut_utils.boolean_to_int(true); + end; + + member function unordered return boolean is + begin + return ut_utils.int_to_boolean(is_unordered); + end; +end; +/ diff --git a/source/expectations/matchers/ut_matcher_options.tps b/source/expectations/matchers/ut_matcher_options.tps new file mode 100644 index 000000000..276cad2ec --- /dev/null +++ b/source/expectations/matchers/ut_matcher_options.tps @@ -0,0 +1,57 @@ +create or replace type ut_matcher_options authid current_user as object( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + */ + + /** + * Flag indicating that columns order is to be ignored + */ + columns_are_unordered_flag number(1,0), + + /** + * Flag indicating that rows/items order is to be ignored + */ + is_unordered number(1,0), + + /** + * Flag determining how to react to null values + */ + nulls_are_equal_flag number(1,0), + + /** + * Holds (list of columns/attributes) to exclude when comparing compound types + */ + exclude ut_matcher_options_items, + + /** + * Holds (list of columns/attributes) to incude when comparing compound types + */ + include ut_matcher_options_items, + + /** + * Holds list of columns to be used as a join PK on sys_refcursor comparision + */ + join_by ut_matcher_options_items, + + constructor function ut_matcher_options(self in out nocopy ut_matcher_options, a_nulls_are_equal in boolean := null) return self as result, + member procedure nulls_are_equal(self in out nocopy ut_matcher_options), + member function nulls_are_equal return boolean, + member procedure unordered_columns(self in out nocopy ut_matcher_options), + member function ordered_columns return boolean, + member procedure unordered(self in out nocopy ut_matcher_options), + member function unordered return boolean +) +/ diff --git a/source/expectations/matchers/ut_matcher_options_items.tpb b/source/expectations/matchers/ut_matcher_options_items.tpb new file mode 100644 index 000000000..92da588ce --- /dev/null +++ b/source/expectations/matchers/ut_matcher_options_items.tpb @@ -0,0 +1,56 @@ +create or replace type body ut_matcher_options_items is + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + constructor function ut_matcher_options_items(self in out nocopy ut_matcher_options_items) return self as result is + begin + items := ut_varchar2_list(); + return; + end; + + member procedure add_items(self in out nocopy ut_matcher_options_items, a_items varchar2) is + begin + items := + items + multiset union all + ut_utils.filter_list( + ut_utils.trim_list_elements( + ut_utils.string_to_table( replace( a_items , '|', ',' ), ',' ) + ) + , '.+' + ); + end; + + member procedure add_items(self in out nocopy ut_matcher_options_items, a_items ut_varchar2_list) is + l_idx binary_integer; + begin + if a_items is not null then + l_idx := a_items.first; + while l_idx is not null loop + add_items( a_items(l_idx) ); + l_idx := a_items.next(l_idx); + end loop; + end if; + end; + + member function to_xpath return varchar2 is + begin + return ut_utils.to_xpath(items); + end; + +end; +/ \ No newline at end of file diff --git a/source/expectations/matchers/ut_matcher_options_items.tps b/source/expectations/matchers/ut_matcher_options_items.tps new file mode 100644 index 000000000..53787070d --- /dev/null +++ b/source/expectations/matchers/ut_matcher_options_items.tps @@ -0,0 +1,29 @@ +create or replace type ut_matcher_options_items authid current_user as object( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + */ + + /** + * Attributes / columns list + */ + items ut_varchar2_list, + + constructor function ut_matcher_options_items(self in out nocopy ut_matcher_options_items) return self as result, + member procedure add_items(self in out nocopy ut_matcher_options_items, a_items varchar2), + member procedure add_items(self in out nocopy ut_matcher_options_items, a_items ut_varchar2_list), + member function to_xpath return varchar2 +) +/ diff --git a/source/expectations/ut_expectation.tpb b/source/expectations/ut_expectation.tpb index 26e0c1092..309759d48 100644 --- a/source/expectations/ut_expectation.tpb +++ b/source/expectations/ut_expectation.tpb @@ -1,7 +1,7 @@ create or replace type body ut_expectation as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -15,29 +15,6 @@ create or replace type body ut_expectation as See the License for the specific language governing permissions and limitations under the License. */ - member procedure to_(self in ut_expectation, a_matcher ut_matcher) is - l_expectation_result boolean; - l_matcher ut_matcher := a_matcher; - l_message varchar2(32767); - begin - - l_expectation_result := l_matcher.run_matcher( self.actual_data ); - l_expectation_result := coalesce(l_expectation_result,false); - l_message := coalesce( l_matcher.error_message( self.actual_data ), l_matcher.failure_message( self.actual_data ) ); - ut_expectation_processor.add_expectation_result( ut_expectation_result( ut_utils.to_test_result( l_expectation_result ), self.description, l_message ) ); - end; - - member procedure not_to(self in ut_expectation, a_matcher ut_matcher) is - l_expectation_result boolean; - l_matcher ut_matcher := a_matcher; - l_message varchar2(32767); - begin - - l_expectation_result := l_matcher.run_matcher_negated( self.actual_data ); - l_expectation_result := coalesce(l_expectation_result,false); - l_message := coalesce( l_matcher.error_message( self.actual_data ), l_matcher.failure_message_when_negated( self.actual_data ) ); - ut_expectation_processor.add_expectation_result( ut_expectation_result( ut_utils.to_test_result( l_expectation_result ), self.description, l_message ) ); - end; member procedure to_be_null(self in ut_expectation) is begin @@ -79,6 +56,16 @@ create or replace type body ut_expectation as self.not_to( ut_be_false() ); end; + member procedure to_be_empty(self in ut_expectation) is + begin + self.to_( ut_be_empty() ); + end; + + member procedure not_to_be_empty(self in ut_expectation) is + begin + self.not_to( ut_be_empty() ); + end; + member procedure to_equal(self in ut_expectation, a_expected anydata, a_nulls_are_equal boolean := null) is begin self.to_( ut_equal(a_expected, a_nulls_are_equal) ); @@ -184,6 +171,15 @@ create or replace type body ut_expectation as self.to_( ut_equal(a_expected, a_nulls_are_equal) ); end; + member procedure to_equal(self in ut_expectation, a_expected json_element_t, a_nulls_are_equal boolean := null) is + begin + self.to_( ut_equal(a_expected, a_nulls_are_equal) ); + end; + + member procedure to_equal(self in ut_expectation, a_expected json, a_nulls_are_equal boolean := null) is + begin + self.to_( ut_equal(a_expected, a_nulls_are_equal) ); + end; member procedure not_to_equal(self in ut_expectation, a_expected anydata, a_nulls_are_equal boolean := null) is begin @@ -286,6 +282,10 @@ create or replace type body ut_expectation as self.not_to( ut_equal(a_expected, a_nulls_are_equal) ); end; + member procedure not_to_equal(self in ut_expectation, a_expected json_element_t, a_nulls_are_equal boolean := null) is + begin + self.not_to( ut_equal(a_expected, a_nulls_are_equal) ); + end; member procedure to_be_like(self in ut_expectation, a_mask in varchar2, a_escape_char in varchar2 := null) is begin @@ -679,5 +679,90 @@ create or replace type body ut_expectation as self.not_to( ut_be_less_than (a_expected) ); end; + member procedure to_contain(self in ut_expectation, a_expected sys_refcursor) is + begin + self.to_( ut_contain(a_expected) ); + end; + + member procedure not_to_contain(self in ut_expectation, a_expected sys_refcursor) is + begin + self.not_to( ut_contain(a_expected)); + end; + + member procedure to_contain(self in ut_expectation, a_expected anydata) is + begin + self.to_( ut_contain(a_expected) ); + end; + + member procedure not_to_contain(self in ut_expectation, a_expected anydata) is + begin + self.not_to( ut_contain(a_expected)); + end; + + member function to_be_within(a_dist number) return ut_be_within is + l_result ut_be_within; + begin + l_result := ut_be_within(a_dist); + l_result.expectation := self; + return l_result; + end; + + member function to_be_within(a_dist dsinterval_unconstrained) return ut_be_within is + l_result ut_be_within; + begin + l_result := ut_be_within(a_dist); + l_result.expectation := self; + return l_result; + end; + + member function to_be_within(a_dist yminterval_unconstrained) return ut_be_within is + l_result ut_be_within; + begin + l_result := ut_be_within(a_dist); + l_result.expectation := self; + return l_result; + end; + + member function to_be_within_pct(a_dist number) return ut_be_within_pct is + l_result ut_be_within_pct; + begin + l_result := ut_be_within_pct(a_dist); + l_result.expectation := self; + return l_result; + end; + + member function not_to_be_within(a_dist number) return ut_be_within is + l_result ut_be_within; + begin + l_result := treat( ut_be_within(a_dist).negated() as ut_be_within); + l_result.expectation := self; + return l_result; + end; + + member function not_to_be_within(a_dist dsinterval_unconstrained) return ut_be_within is + l_result ut_be_within; + begin + l_result := treat( ut_be_within(a_dist).negated() as ut_be_within); + l_result.expectation := self; + return l_result; + end; + + member function not_to_be_within(a_dist yminterval_unconstrained) return ut_be_within is + l_result ut_be_within; + begin + l_result := treat( ut_be_within(a_dist).negated() as ut_be_within); + l_result.expectation := self; + return l_result; + end; + + member function not_to_be_within_pct(a_dist number) return ut_be_within_pct is + l_result ut_be_within_pct; + begin + l_result := treat( ut_be_within_pct(a_dist).negated() as ut_be_within_pct); + l_result.expectation := self; + return l_result; + end; + end; / + diff --git a/source/expectations/ut_expectation.tps b/source/expectations/ut_expectation.tps index d27a18377..30fe985d3 100644 --- a/source/expectations/ut_expectation.tps +++ b/source/expectations/ut_expectation.tps @@ -1,7 +1,7 @@ -create or replace type ut_expectation authid current_user as object( +create or replace type ut_expectation force under ut_expectation_base( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -15,13 +15,7 @@ create or replace type ut_expectation authid current_user as object( See the License for the specific language governing permissions and limitations under the License. */ - actual_data ut_data_value, - description varchar2(4000 char), - - --base matcher executors - member procedure to_(self in ut_expectation, a_matcher ut_matcher), - member procedure not_to(self in ut_expectation, a_matcher ut_matcher), - + --shortcuts member procedure to_be_null(self in ut_expectation), member procedure to_be_not_null(self in ut_expectation), @@ -33,6 +27,9 @@ create or replace type ut_expectation authid current_user as object( member procedure not_to_be_true(self in ut_expectation), member procedure not_to_be_false(self in ut_expectation), + member procedure to_be_empty(self in ut_expectation), + member procedure not_to_be_empty(self in ut_expectation), + -- this is done to provide strong type comparison. other comporators should be implemented in the type-specific classes member procedure to_equal(self in ut_expectation, a_expected anydata, a_nulls_are_equal boolean := null), member procedure to_equal(self in ut_expectation, a_expected anydata, a_exclude varchar2, a_nulls_are_equal boolean := null), @@ -51,6 +48,8 @@ create or replace type ut_expectation authid current_user as object( member procedure to_equal(self in ut_expectation, a_expected varchar2, a_nulls_are_equal boolean := null), member procedure to_equal(self in ut_expectation, a_expected yminterval_unconstrained, a_nulls_are_equal boolean := null), member procedure to_equal(self in ut_expectation, a_expected dsinterval_unconstrained, a_nulls_are_equal boolean := null), + member procedure to_equal(self in ut_expectation, a_expected json_element_t, a_nulls_are_equal boolean := null), + member procedure to_equal(self in ut_expectation, a_expected json, a_nulls_are_equal boolean := null), member procedure not_to_equal(self in ut_expectation, a_expected anydata, a_nulls_are_equal boolean := null), member procedure not_to_equal(self in ut_expectation, a_expected anydata, a_exclude varchar2, a_nulls_are_equal boolean := null), @@ -69,6 +68,7 @@ create or replace type ut_expectation authid current_user as object( member procedure not_to_equal(self in ut_expectation, a_expected varchar2, a_nulls_are_equal boolean := null), member procedure not_to_equal(self in ut_expectation, a_expected yminterval_unconstrained, a_nulls_are_equal boolean := null), member procedure not_to_equal(self in ut_expectation, a_expected dsinterval_unconstrained, a_nulls_are_equal boolean := null), + member procedure not_to_equal(self in ut_expectation, a_expected json_element_t, a_nulls_are_equal boolean := null), member procedure to_be_like(self in ut_expectation, a_mask in varchar2, a_escape_char in varchar2 := null), @@ -158,7 +158,21 @@ create or replace type ut_expectation authid current_user as object( member procedure not_to_be_less_than(self in ut_expectation, a_expected timestamp_unconstrained), member procedure not_to_be_less_than(self in ut_expectation, a_expected timestamp_ltz_unconstrained), member procedure not_to_be_less_than(self in ut_expectation, a_expected timestamp_tz_unconstrained), - member procedure not_to_be_less_than(self in ut_expectation, a_expected yminterval_unconstrained) + member procedure not_to_be_less_than(self in ut_expectation, a_expected yminterval_unconstrained), + + member procedure to_contain(self in ut_expectation, a_expected sys_refcursor), + member procedure not_to_contain(self in ut_expectation, a_expected sys_refcursor), + member procedure to_contain(self in ut_expectation, a_expected anydata), + member procedure not_to_contain(self in ut_expectation, a_expected anydata), + + member function to_be_within(a_dist number) return ut_be_within, + member function to_be_within(a_dist dsinterval_unconstrained) return ut_be_within, + member function to_be_within(a_dist yminterval_unconstrained) return ut_be_within, + member function to_be_within_pct(a_dist number) return ut_be_within_pct, + member function not_to_be_within(a_dist number) return ut_be_within, + member function not_to_be_within(a_dist dsinterval_unconstrained) return ut_be_within, + member function not_to_be_within(a_dist yminterval_unconstrained) return ut_be_within, + member function not_to_be_within_pct(a_dist number) return ut_be_within_pct ) not final / diff --git a/source/expectations/ut_expectation_base.tpb b/source/expectations/ut_expectation_base.tpb new file mode 100644 index 000000000..20b3e7a95 --- /dev/null +++ b/source/expectations/ut_expectation_base.tpb @@ -0,0 +1,44 @@ +create or replace type body ut_expectation_base as + /* + utPLSQL - Version 3 + Copyright 2016 - 2019 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. + */ + member procedure to_(self in ut_expectation_base, a_matcher ut_matcher_base) is + l_expectation_result boolean; + l_matcher ut_matcher := treat(a_matcher as ut_matcher); + l_message varchar2(32767); + begin + if l_matcher.is_negated() then + self.not_to( a_matcher ); + else + l_expectation_result := l_matcher.run_matcher( self.actual_data ); + l_expectation_result := coalesce(l_expectation_result,false); + l_message := coalesce( l_matcher.error_message( self.actual_data ), l_matcher.failure_message( self.actual_data ) ); + ut_expectation_processor.add_expectation_result( ut_expectation_result( ut_utils.to_test_result( l_expectation_result ), self.description, l_message ) ); + end if; + end; + + member procedure not_to(self in ut_expectation_base, a_matcher ut_matcher_base) is + l_expectation_result boolean; + l_matcher ut_matcher := treat(a_matcher as ut_matcher); + l_message varchar2(32767); + begin + l_expectation_result := coalesce( l_matcher.run_matcher_negated( self.actual_data ), false ); + + l_message := coalesce( l_matcher.error_message( self.actual_data ), l_matcher.failure_message_when_negated( self.actual_data ) ); + ut_expectation_processor.add_expectation_result( ut_expectation_result( ut_utils.to_test_result( l_expectation_result ), self.description, l_message ) ); + end; +end; +/ diff --git a/source/expectations/ut_expectation_base.tps b/source/expectations/ut_expectation_base.tps new file mode 100644 index 000000000..a542d26ea --- /dev/null +++ b/source/expectations/ut_expectation_base.tps @@ -0,0 +1,25 @@ +create or replace type ut_expectation_base authid current_user as object( + /* + utPLSQL - Version 3 + Copyright 2016 - 2019 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. + */ + actual_data ut_data_value, + description varchar2(4000 char), + + --base matcher executors + member procedure to_(self in ut_expectation_base, a_matcher ut_matcher_base), + member procedure not_to(self in ut_expectation_base, a_matcher ut_matcher_base) +) not final not instantiable +/ diff --git a/source/expectations/ut_expectation_compound.tpb b/source/expectations/ut_expectation_compound.tpb index c620ec39c..6fc2e2647 100644 --- a/source/expectations/ut_expectation_compound.tpb +++ b/source/expectations/ut_expectation_compound.tpb @@ -1,7 +1,7 @@ create or replace type body ut_expectation_compound as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -20,21 +20,9 @@ create or replace type body ut_expectation_compound as begin self.actual_data := a_actual_data; self.description := a_description; - negated := ut_utils.boolean_to_int(false); return; end; - member procedure to_be_empty(self in ut_expectation_compound) is - begin - self.to_( ut_be_empty() ); - end; - - member procedure not_to_be_empty(self in ut_expectation_compound) is - begin - self.not_to( ut_be_empty() ); - end; - - member procedure to_have_count(self in ut_expectation_compound, a_expected integer) is begin self.to_( ut_have_count(a_expected) ); @@ -46,158 +34,68 @@ create or replace type body ut_expectation_compound as end; - member function to_equal(a_expected anydata, a_nulls_are_equal boolean := null) return ut_expectation_compound is - l_result ut_expectation_compound := self; - begin - l_result.matcher := ut_equal(a_expected, a_nulls_are_equal); - return l_result; - end; - - member function to_equal(a_expected sys_refcursor, a_nulls_are_equal boolean := null) return ut_expectation_compound is - l_result ut_expectation_compound := self; + member function to_equal(a_expected anydata, a_nulls_are_equal boolean := null) return ut_equal is + l_result ut_equal; begin - l_result.matcher := ut_equal(a_expected, a_nulls_are_equal); + l_result := ut_equal(a_expected, a_nulls_are_equal); + l_result.expectation := self; return l_result; end; - member function not_to_equal(a_expected anydata, a_nulls_are_equal boolean := null) return ut_expectation_compound is - l_result ut_expectation_compound := self; + member function not_to_equal(a_expected anydata, a_nulls_are_equal boolean := null) return ut_equal is + l_result ut_matcher; begin - l_result.matcher := ut_equal(a_expected, a_nulls_are_equal); - l_result.negated := ut_utils.boolean_to_int(true); - return l_result; + l_result := ut_equal(a_expected, a_nulls_are_equal).negated(); + l_result.expectation := self; + return treat(l_result as ut_equal); end; - member function not_to_equal(a_expected sys_refcursor, a_nulls_are_equal boolean := null) return ut_expectation_compound is - l_result ut_expectation_compound := self; + member function to_equal(a_expected sys_refcursor, a_nulls_are_equal boolean := null) return ut_equal is + l_result ut_equal; begin - l_result.matcher := ut_equal(a_expected, a_nulls_are_equal); - l_result.negated := ut_utils.boolean_to_int(true); + l_result := ut_equal(a_expected, a_nulls_are_equal); + l_result.expectation := self; return l_result; end; - member function include(a_items varchar2) return ut_expectation_compound is - l_result ut_expectation_compound; + member function not_to_equal(a_expected sys_refcursor, a_nulls_are_equal boolean := null) return ut_equal is + l_result ut_matcher; begin - l_result := self; - l_result.matcher := treat(l_result.matcher as ut_equal).include(a_items); - return l_result; + l_result := ut_equal(a_expected, a_nulls_are_equal).negated(); + l_result.expectation := self; + return treat(l_result as ut_equal); end; - member function include(a_items ut_varchar2_list) return ut_expectation_compound is - l_result ut_expectation_compound; + member function to_contain(a_expected sys_refcursor) return ut_contain is + l_result ut_contain; begin - l_result := self; - l_result.matcher := treat(l_result.matcher as ut_equal).include(a_items); + l_result := ut_contain(a_expected); + l_result.expectation := self; return l_result; end; - member procedure include(self in ut_expectation_compound, a_items varchar2) is + member function not_to_contain(a_expected sys_refcursor) return ut_contain is + l_result ut_matcher; begin - if ut_utils.int_to_boolean(negated) then - self.not_to( treat(matcher as ut_equal).include(a_items) ); - else - self.to_( treat(matcher as ut_equal).include(a_items) ); - end if; + l_result := ut_contain(a_expected).negated(); + l_result.expectation := self; + return treat(l_result as ut_contain); end; - - member procedure include(self in ut_expectation_compound, a_items ut_varchar2_list) is + + member function to_contain(a_expected anydata) return ut_contain is + l_result ut_contain; begin - - if ut_utils.int_to_boolean(negated) then - self.not_to( treat(matcher as ut_equal).include(a_items) ); - else - self.to_( treat(matcher as ut_equal).include(a_items) ); - end if; - end; - - - member function exclude(a_items varchar2) return ut_expectation_compound is - l_result ut_expectation_compound; - begin - l_result := self; - l_result.matcher := treat(l_result.matcher as ut_equal).exclude(a_items); - return l_result; - end; - - member function exclude(a_items ut_varchar2_list) return ut_expectation_compound is - l_result ut_expectation_compound; - begin - l_result := self; - l_result.matcher := treat(l_result.matcher as ut_equal).exclude(a_items); - return l_result; - end; - - member procedure exclude(self in ut_expectation_compound, a_items varchar2) is - begin - if ut_utils.int_to_boolean(negated) then - self.not_to( treat(matcher as ut_equal).exclude(a_items) ); - else - self.to_( treat(matcher as ut_equal).exclude(a_items) ); - end if; - end; - - member procedure exclude(self in ut_expectation_compound, a_items ut_varchar2_list) is - begin - - if ut_utils.int_to_boolean(negated) then - self.not_to( treat(matcher as ut_equal).exclude(a_items) ); - else - self.to_( treat(matcher as ut_equal).exclude(a_items) ); - end if; - end; - - member function unordered return ut_expectation_compound is - l_result ut_expectation_compound; - begin - l_result := self; - l_result.matcher := treat(l_result.matcher as ut_equal).unordered; + l_result := ut_contain(a_expected); + l_result.expectation := self; return l_result; end; - member procedure unordered(self in ut_expectation_compound) is - begin - - if ut_utils.int_to_boolean(negated) then - self.not_to( treat(matcher as ut_equal).unordered ); - else - self.to_( treat(matcher as ut_equal).unordered ); - end if; - end; - - member function join_by(a_columns varchar2) return ut_expectation_compound is - l_result ut_expectation_compound; + member function not_to_contain(a_expected anydata) return ut_contain is + l_result ut_matcher; begin - l_result := self; - l_result.matcher := treat(l_result.matcher as ut_equal).join_by(a_columns); - return l_result; - end; - - member function join_by(a_columns ut_varchar2_list) return ut_expectation_compound is - l_result ut_expectation_compound; - begin - l_result := self; - l_result.matcher := treat(l_result.matcher as ut_equal).join_by(a_columns); - return l_result; - end; - - member procedure join_by(self in ut_expectation_compound, a_columns varchar2) is - begin - if ut_utils.int_to_boolean(negated) then - self.not_to( treat(matcher as ut_equal).join_by(a_columns) ); - else - self.to_( treat(matcher as ut_equal).join_by(a_columns) ); - end if; - end; - - member procedure join_by(self in ut_expectation_compound, a_columns ut_varchar2_list) is - begin - - if ut_utils.int_to_boolean(negated) then - self.not_to( treat(matcher as ut_equal).join_by(a_columns) ); - else - self.to_( treat(matcher as ut_equal).join_by(a_columns) ); - end if; + l_result := ut_contain(a_expected).negated(); + l_result.expectation := self; + return treat(l_result as ut_contain); end; end; diff --git a/source/expectations/ut_expectation_compound.tps b/source/expectations/ut_expectation_compound.tps index 529b8875d..46da23fea 100644 --- a/source/expectations/ut_expectation_compound.tps +++ b/source/expectations/ut_expectation_compound.tps @@ -1,7 +1,7 @@ create or replace type ut_expectation_compound under ut_expectation( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -16,33 +16,21 @@ create or replace type ut_expectation_compound under ut_expectation( limitations under the License. */ matcher ut_matcher, - negated integer, constructor function ut_expectation_compound(self in out nocopy ut_expectation_compound, a_actual_data ut_data_value, a_description varchar2) return self as result, - member procedure to_be_empty(self in ut_expectation_compound), - member procedure not_to_be_empty(self in ut_expectation_compound), member procedure to_have_count(self in ut_expectation_compound, a_expected integer), member procedure not_to_have_count(self in ut_expectation_compound, a_expected integer), - member function to_equal(a_expected anydata, a_nulls_are_equal boolean := null) return ut_expectation_compound, - member function to_equal(a_expected sys_refcursor, a_nulls_are_equal boolean := null) return ut_expectation_compound, - member function not_to_equal(a_expected anydata, a_nulls_are_equal boolean := null) return ut_expectation_compound, - member function not_to_equal(a_expected sys_refcursor, a_nulls_are_equal boolean := null) return ut_expectation_compound, - member function include(a_items varchar2) return ut_expectation_compound, - member function include(a_items ut_varchar2_list) return ut_expectation_compound, - member procedure include(self in ut_expectation_compound, a_items varchar2), - member procedure include(self in ut_expectation_compound, a_items ut_varchar2_list), - member function exclude(a_items varchar2) return ut_expectation_compound, - member function exclude(a_items ut_varchar2_list) return ut_expectation_compound, - member procedure exclude(self in ut_expectation_compound, a_items varchar2), - member procedure exclude(self in ut_expectation_compound, a_items ut_varchar2_list), - member function unordered return ut_expectation_compound, - member procedure unordered(self in ut_expectation_compound), - member function join_by(a_columns varchar2) return ut_expectation_compound, - member function join_by(a_columns ut_varchar2_list) return ut_expectation_compound, - member procedure join_by(self in ut_expectation_compound, a_columns varchar2), - member procedure join_by(self in ut_expectation_compound, a_columns ut_varchar2_list) + member function to_equal(a_expected anydata, a_nulls_are_equal boolean := null) return ut_equal, + member function not_to_equal(a_expected anydata, a_nulls_are_equal boolean := null) return ut_equal, + member function to_equal(a_expected sys_refcursor, a_nulls_are_equal boolean := null) return ut_equal, + member function not_to_equal(a_expected sys_refcursor, a_nulls_are_equal boolean := null) return ut_equal, + member function to_contain(a_expected sys_refcursor) return ut_contain, + member function not_to_contain(a_expected sys_refcursor) return ut_contain, + member function to_contain(a_expected anydata) return ut_contain, + member function not_to_contain(a_expected anydata) return ut_contain ) -final -/ \ No newline at end of file +/ + + diff --git a/source/expectations/ut_expectation_json.tpb b/source/expectations/ut_expectation_json.tpb new file mode 100644 index 000000000..b71e8ea83 --- /dev/null +++ b/source/expectations/ut_expectation_json.tpb @@ -0,0 +1,51 @@ +create or replace type body ut_expectation_json as + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + constructor function ut_expectation_json(self in out nocopy ut_expectation_json, a_actual_data ut_data_value, a_description varchar2) return self as result is + begin + self.actual_data := a_actual_data; + self.description := a_description; + return; + end; + + member function to_equal(a_expected json_element_t, a_nulls_are_equal boolean := null) return ut_expectation_json is + l_result ut_expectation_json := self; + begin + l_result.matcher := ut_equal(a_expected, a_nulls_are_equal); + return l_result; + end; + + member function not_to_equal(a_expected json_element_t, a_nulls_are_equal boolean := null) return ut_expectation_json is + l_result ut_expectation_json := self; + begin + l_result.matcher := ut_equal(a_expected, a_nulls_are_equal).negated(); + return l_result; + end; + + member procedure to_have_count(self in ut_expectation_json, a_expected integer) is + begin + self.to_( ut_have_count(a_expected) ); + end; + + member procedure not_to_have_count(self in ut_expectation_json, a_expected integer) is + begin + self.not_to( ut_have_count(a_expected) ); + end; + +end; +/ diff --git a/source/expectations/ut_expectation_json.tps b/source/expectations/ut_expectation_json.tps new file mode 100644 index 000000000..561c5d11f --- /dev/null +++ b/source/expectations/ut_expectation_json.tps @@ -0,0 +1,27 @@ +create or replace type ut_expectation_json under ut_expectation( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + */ + matcher ut_matcher, + + constructor function ut_expectation_json(self in out nocopy ut_expectation_json, a_actual_data ut_data_value, a_description varchar2) return self as result, + + member function to_equal(a_expected json_element_t , a_nulls_are_equal boolean := null) return ut_expectation_json, + member function not_to_equal(a_expected json_element_t , a_nulls_are_equal boolean := null) return ut_expectation_json, + member procedure to_have_count(self in ut_expectation_json, a_expected integer), + member procedure not_to_have_count(self in ut_expectation_json, a_expected integer) +) +/ \ No newline at end of file diff --git a/source/install.sql b/source/install.sql index 902b45aba..827213e6c 100644 --- a/source/install.sql +++ b/source/install.sql @@ -1,6 +1,6 @@ /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -31,9 +31,11 @@ prompt &&line_separator alter session set current_schema = &&ut3_owner; @@check_object_grants.sql -@@check_sys_grants.sql +@@check_sys_grants.sql "'CREATE TYPE','CREATE VIEW','CREATE SYNONYM','CREATE SEQUENCE','CREATE PROCEDURE','CREATE TABLE', 'CREATE CONTEXT'" --set define off +create or replace context &&ut3_owner._info using &&ut3_owner..ut_session_context; + --dbms_output buffer cache table @@install_component.sql 'core/ut_dbms_output_cache.sql' @@ -46,13 +48,22 @@ alter session set current_schema = &&ut3_owner; @@install_component.sql 'core/types/ut_object_names.tps' @@install_component.sql 'core/types/ut_key_value_pair.tps' @@install_component.sql 'core/types/ut_key_value_pairs.tps' +@@install_component.sql 'core/types/ut_reporter_info.tps' +@@install_component.sql 'core/types/ut_reporters_info.tps' +@@install_component.sql 'core/types/ut_stack.tps' +@@install_component.sql 'core/types/ut_stack.tpb' @@install_component.sql 'core/ut_utils.pks' @@install_component.sql 'core/ut_metadata.pks' +@@install_component.sql 'core/ut_savepoint_seq.sql' @@install_component.sql 'core/ut_utils.pkb' @@install_component.sql 'core/ut_metadata.pkb' @@install_component.sql 'reporters/ut_ansiconsole_helper.pks' @@install_component.sql 'reporters/ut_ansiconsole_helper.pkb' +@@install_component.sql 'api/ut_suite_item_info.tps' +@@install_component.sql 'api/ut_suite_item_info.tpb' +@@install_component.sql 'api/ut_suite_items_info.tps' + --event manager objects @@install_component.sql 'core/events/ut_event_item.tps' @@install_component.sql 'core/events/ut_event_listener.tps' @@ -60,6 +71,8 @@ alter session set current_schema = &&ut3_owner; @@install_component.sql 'core/events/ut_event_manager.pkb' --core types +@@install_component.sql 'core/types/ut_run_info.tps' +@@install_component.sql 'core/types/ut_run_info.tpb' @@install_component.sql 'core/types/ut_expectation_result.tps' @@install_component.sql 'core/types/ut_expectation_results.tps' @@install_component.sql 'core/types/ut_results_counter.tps' @@ -78,20 +91,45 @@ alter session set current_schema = &&ut3_owner; @@install_component.sql 'core/types/ut_run.tps' @@install_component.sql 'core/types/ut_reporter_base.tps' @@install_component.sql 'core/types/ut_reporters.tps' +@@install_component.sql 'core/types/ut_path_item.tps' +@@install_component.sql 'core/types/ut_path_items.tps' + +@@install_component.sql 'expectations/json_objects_specs.sql' +@@install_component.sql 'expectations/matchers/ut_matcher_options_items.tps' +@@install_component.sql 'expectations/matchers/ut_matcher_options.tps' +@@install_component.sql 'expectations/data_values/ut_data_value.tps' +@@install_component.sql 'expectations/data_values/ut_key_anyval_pair.tps' +@@install_component.sql 'expectations/data_values/ut_key_anyval_pairs.tps' +@@install_component.sql 'expectations/data_values/ut_key_anyvalues.tps' + +--session_context +@@install_component.sql 'core/session_context/ut_session_context.pks' +@@install_component.sql 'core/session_context/ut_session_context.pkb' +@@install_component.sql 'core/session_context/ut_session_info.tps' +@@install_component.sql 'core/session_context/ut_session_info.tpb' ---output buffer base api -@@install_component.sql 'core/output_buffers/ut_output_buffer_base.tps' --output buffer table @@install_component.sql 'core/output_buffers/ut_output_buffer_info_tmp.sql' @@install_component.sql 'core/output_buffers/ut_output_buffer_tmp.sql' -@@install_component.sql 'core/output_buffers/ut_message_id_seq.sql' +@@install_component.sql 'core/output_buffers/ut_output_clob_buffer_tmp.sql' +--output buffer base api +@@install_component.sql 'core/output_buffers/ut_output_data_row.tps' +@@install_component.sql 'core/output_buffers/ut_output_data_rows.tps' +@@install_component.sql 'core/output_buffers/ut_output_buffer_base.tps' +@@install_component.sql 'core/output_buffers/ut_output_buffer_base.tpb' --output buffer table api @@install_component.sql 'core/output_buffers/ut_output_table_buffer.tps' @@install_component.sql 'core/output_buffers/ut_output_table_buffer.tpb' +@@install_component.sql 'core/output_buffers/ut_output_clob_table_buffer.tps' +@@install_component.sql 'core/output_buffers/ut_output_clob_table_buffer.tpb' +@@install_component.sql 'core/output_buffers/ut_output_bulk_buffer.tps' +@@install_component.sql 'core/output_buffers/ut_output_bulk_buffer.tpb' @@install_component.sql 'core/types/ut_output_reporter_base.tps' ---annoations +--annotations +@@install_component.sql 'core/annotations/ut_trigger_check.pks' +@@install_component.sql 'core/annotations/ut_trigger_check.pkb' @@install_component.sql 'core/annotations/ut_annotation.tps' @@install_component.sql 'core/annotations/ut_annotations.tps' @@install_component.sql 'core/annotations/ut_annotated_object.tps' @@ -99,6 +137,7 @@ alter session set current_schema = &&ut3_owner; @@install_component.sql 'core/annotations/ut_annotation_obj_cache_info.tps' @@install_component.sql 'core/annotations/ut_annotation_objs_cache_info.tps' @@install_component.sql 'core/annotations/ut_annotation_cache_seq.sql' +@@install_component.sql 'core/annotations/ut_annotation_cache_schema.sql' @@install_component.sql 'core/annotations/ut_annotation_cache_info.sql' @@install_component.sql 'core/annotations/ut_annotation_cache.sql' @@install_component.sql 'core/annotations/ut_annotation_cache_manager.pks' @@ -109,6 +148,17 @@ alter session set current_schema = &&ut3_owner; @@install_component.sql 'core/annotations/ut_annotation_manager.pkb' --suite builder +@@install_component.sql 'core/types/ut_suite_cache_row.tps' +@@install_component.sql 'core/types/ut_suite_cache_rows.tps' +@@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_tag_filter.pks' +@@install_component.sql 'core/ut_suite_tag_filter.pkb' +@@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 @@ -122,9 +172,6 @@ alter session set current_schema = &&ut3_owner; prompt Installing PLSQL profiler objects into &&ut3_owner schema @@core/coverage/proftab.sql -prompt Installing PLSQL profiler objects into &&ut3_owner schema -@@core/coverage/proftab.sql - prompt Installing DBMSPLSQL Tables objects into &&ut3_owner schema @@core/coverage/dbms_plssqlcode.sql @@ -134,18 +181,19 @@ prompt Installing DBMSPLSQL Tables objects into &&ut3_owner schema --gathering coverage @@install_component.sql 'core/coverage/ut_coverage_sources_tmp.sql' +@@install_component.sql 'core/coverage/ut_coverage_runs.sql' @@install_component.sql 'core/coverage/ut_coverage_helper.pks' -@@install_above_12_1.sql 'core/coverage/ut_coverage_helper_block.pks' +@@install_component.sql 'core/coverage/ut_coverage_helper_block.pks' @@install_component.sql 'core/coverage/ut_coverage_helper_profiler.pks' @@install_component.sql 'core/coverage/ut_coverage.pks' -@@install_above_12_1.sql 'core/coverage/ut_coverage_block.pks' +@@install_component.sql 'core/coverage/ut_coverage_block.pks' @@install_component.sql 'core/coverage/ut_coverage_profiler.pks' @@install_component.sql 'core/coverage/ut_coverage_reporter_base.tps' @@install_component.sql 'core/coverage/ut_coverage_helper.pkb' -@@install_above_12_1.sql 'core/coverage/ut_coverage_helper_block.pkb' +@@install_component.sql 'core/coverage/ut_coverage_helper_block.pkb' @@install_component.sql 'core/coverage/ut_coverage_helper_profiler.pkb' @@install_component.sql 'core/coverage/ut_coverage.pkb' -@@install_above_12_1.sql 'core/coverage/ut_coverage_block.pkb' +@@install_component.sql 'core/coverage/ut_coverage_block.pkb' @@install_component.sql 'core/coverage/ut_coverage_profiler.pkb' @@install_component.sql 'core/coverage/ut_coverage_reporter_base.tpb' @@ -156,6 +204,7 @@ prompt Installing DBMSPLSQL Tables objects into &&ut3_owner schema @@install_component.sql 'core/types/ut_logical_suite.tpb' @@install_component.sql 'core/types/ut_suite.tpb' @@install_component.sql 'core/types/ut_suite_context.tpb' +@@install_component.sql 'core/types/ut_coverage_options.tpb' @@install_component.sql 'core/types/ut_run.tpb' @@install_component.sql 'core/types/ut_expectation_result.tpb' @@install_component.sql 'core/types/ut_reporter_base.tpb' @@ -165,15 +214,19 @@ prompt Installing DBMSPLSQL Tables objects into &&ut3_owner schema @@install_component.sql 'core/types/ut_executable_test.tpb' @@install_component.sql 'core/types/ut_console_reporter_base.tps' @@install_component.sql 'core/types/ut_console_reporter_base.tpb' +@@install_component.sql 'core/types/ut_path_item.tpb' --expectations and matchers @@install_component.sql 'expectations/data_values/ut_compound_data_tmp.sql' @@install_component.sql 'expectations/data_values/ut_compound_data_diff_tmp.sql' -@@install_component.sql 'expectations/data_values/ut_data_value.tps' +@@install_component.sql 'expectations/data_values/ut_json_data_diff_tmp.sql' @@install_component.sql 'expectations/data_values/ut_compound_data_value.tps' -@@install_component.sql 'expectations/data_values/ut_data_value_anydata.tps' -@@install_component.sql 'expectations/data_values/ut_data_value_collection.tps' -@@install_component.sql 'expectations/data_values/ut_data_value_object.tps' +@@install_component.sql 'expectations/data_values/ut_json_leaf.tps' +@@install_component.sql 'expectations/data_values/ut_json_leaf_tab.tps' +@@install_component.sql 'expectations/data_values/ut_json_tree_details.tps' +@@install_component.sql 'expectations/data_values/ut_cursor_column.tps' +@@install_component.sql 'expectations/data_values/ut_cursor_column_tab.tps' +@@install_component.sql 'expectations/data_values/ut_cursor_details.tps' @@install_component.sql 'expectations/data_values/ut_data_value_blob.tps' @@install_component.sql 'expectations/data_values/ut_data_value_boolean.tps' @@install_component.sql 'expectations/data_values/ut_data_value_clob.tps' @@ -181,18 +234,23 @@ prompt Installing DBMSPLSQL Tables objects into &&ut3_owner schema @@install_component.sql 'expectations/data_values/ut_data_value_dsinterval.tps' @@install_component.sql 'expectations/data_values/ut_data_value_number.tps' @@install_component.sql 'expectations/data_values/ut_data_value_refcursor.tps' +@@install_component.sql 'expectations/data_values/ut_data_value_anydata.tps' @@install_component.sql 'expectations/data_values/ut_data_value_timestamp.tps' @@install_component.sql 'expectations/data_values/ut_data_value_timestamp_tz.tps' @@install_component.sql 'expectations/data_values/ut_data_value_timestamp_ltz.tps' @@install_component.sql 'expectations/data_values/ut_data_value_varchar2.tps' @@install_component.sql 'expectations/data_values/ut_data_value_yminterval.tps' @@install_component.sql 'expectations/data_values/ut_data_value_xmltype.tps' -@@install_component.sql 'expectations/data_values/ut_key_anyval_pair.tps' -@@install_component.sql 'expectations/data_values/ut_key_anyval_pairs.tps' @@install_component.sql 'expectations/data_values/ut_compound_data_helper.pks' -@@install_component.sql 'expectations/data_values/ut_curr_usr_compound_helper.pks' +@@install_component.sql 'expectations/data_values/ut_data_value_json.tps' +@@install_component.sql 'expectations/matchers/ut_matcher_base.tps' +@@install_component.sql 'expectations/ut_expectation_base.tps' @@install_component.sql 'expectations/matchers/ut_matcher.tps' @@install_component.sql 'expectations/matchers/ut_comparison_matcher.tps' +@@install_component.sql 'expectations/matchers/ut_be_within_pct.tps' +@@install_component.sql 'expectations/matchers/ut_be_within.tps' +@@install_component.sql 'expectations/matchers/ut_be_within_helper.pks' +@@install_component.sql 'expectations/ut_expectation.tps' @@install_component.sql 'expectations/matchers/ut_be_false.tps' @@install_component.sql 'expectations/matchers/ut_be_greater_or_equal.tps' @@install_component.sql 'expectations/matchers/ut_be_greater_than.tps' @@ -203,19 +261,23 @@ prompt Installing DBMSPLSQL Tables objects into &&ut3_owner schema @@install_component.sql 'expectations/matchers/ut_be_null.tps' @@install_component.sql 'expectations/matchers/ut_be_true.tps' @@install_component.sql 'expectations/matchers/ut_equal.tps' +@@install_component.sql 'expectations/matchers/ut_contain.tps' @@install_component.sql 'expectations/matchers/ut_have_count.tps' @@install_component.sql 'expectations/matchers/ut_be_between.tps' @@install_component.sql 'expectations/matchers/ut_be_empty.tps' @@install_component.sql 'expectations/matchers/ut_match.tps' -@@install_component.sql 'expectations/ut_expectation.tps' +@@install_component.sql 'expectations/data_values/ut_json_leaf.tpb' +@@install_component.sql 'expectations/data_values/ut_json_tree_details.tpb' +@@install_component.sql 'expectations/data_values/ut_cursor_column.tpb' +@@install_component.sql 'expectations/data_values/ut_cursor_details.tpb' @@install_component.sql 'expectations/ut_expectation_compound.tps' +@@install_component.sql 'expectations/ut_expectation_json.tps' + +@@install_component.sql 'expectations/matchers/ut_matcher_options_items.tpb' +@@install_component.sql 'expectations/matchers/ut_matcher_options.tpb' @@install_component.sql 'expectations/data_values/ut_data_value.tpb' @@install_component.sql 'expectations/data_values/ut_compound_data_value.tpb' @@install_component.sql 'expectations/data_values/ut_compound_data_helper.pkb' -@@install_component.sql 'expectations/data_values/ut_curr_usr_compound_helper.pkb' -@@install_component.sql 'expectations/data_values/ut_data_value_anydata.tpb' -@@install_component.sql 'expectations/data_values/ut_data_value_object.tpb' -@@install_component.sql 'expectations/data_values/ut_data_value_collection.tpb' @@install_component.sql 'expectations/data_values/ut_data_value_blob.tpb' @@install_component.sql 'expectations/data_values/ut_data_value_boolean.tpb' @@install_component.sql 'expectations/data_values/ut_data_value_clob.tpb' @@ -223,12 +285,14 @@ prompt Installing DBMSPLSQL Tables objects into &&ut3_owner schema @@install_component.sql 'expectations/data_values/ut_data_value_dsinterval.tpb' @@install_component.sql 'expectations/data_values/ut_data_value_number.tpb' @@install_component.sql 'expectations/data_values/ut_data_value_refcursor.tpb' +@@install_component.sql 'expectations/data_values/ut_data_value_anydata.tpb' @@install_component.sql 'expectations/data_values/ut_data_value_timestamp.tpb' @@install_component.sql 'expectations/data_values/ut_data_value_timestamp_tz.tpb' @@install_component.sql 'expectations/data_values/ut_data_value_timestamp_ltz.tpb' @@install_component.sql 'expectations/data_values/ut_data_value_varchar2.tpb' @@install_component.sql 'expectations/data_values/ut_data_value_yminterval.tpb' @@install_component.sql 'expectations/data_values/ut_data_value_xmltype.tpb' +@@install_component.sql 'expectations/data_values/ut_data_value_json.tpb' @@install_component.sql 'expectations/matchers/ut_matcher.tpb' @@install_component.sql 'expectations/matchers/ut_comparison_matcher.tpb' @@install_component.sql 'expectations/matchers/ut_be_false.tpb' @@ -241,12 +305,19 @@ prompt Installing DBMSPLSQL Tables objects into &&ut3_owner schema @@install_component.sql 'expectations/matchers/ut_be_null.tpb' @@install_component.sql 'expectations/matchers/ut_be_true.tpb' @@install_component.sql 'expectations/matchers/ut_equal.tpb' +@@install_component.sql 'expectations/matchers/ut_be_within_pct.tpb' +@@install_component.sql 'expectations/matchers/ut_be_within.tpb' +@@install_component.sql 'expectations/matchers/ut_be_within_helper.pkb' +@@install_component.sql 'expectations/matchers/ut_contain.tpb' @@install_component.sql 'expectations/matchers/ut_have_count.tpb' @@install_component.sql 'expectations/matchers/ut_be_between.tpb' @@install_component.sql 'expectations/matchers/ut_be_empty.tpb' @@install_component.sql 'expectations/matchers/ut_match.tpb' +@@install_component.sql 'expectations/ut_expectation_base.tpb' @@install_component.sql 'expectations/ut_expectation.tpb' @@install_component.sql 'expectations/ut_expectation_compound.tpb' +@@install_component.sql 'expectations/ut_expectation_json.tpb' +@@install_component.sql 'expectations/data_values/ut_key_anyvalues.tpb' --core reporter @@install_component.sql 'reporters/ut_documentation_reporter.tps' @@ -261,6 +332,8 @@ prompt Installing DBMSPLSQL Tables objects into &&ut3_owner schema @@install_component.sql 'api/ut.pkb' --additional reporters +@@install_component.sql 'reporters/ut_debug_reporter.tps' +@@install_component.sql 'reporters/ut_debug_reporter.tpb' @@install_component.sql 'reporters/ut_teamcity_reporter.tps' @@install_component.sql 'reporters/ut_teamcity_reporter_helper.pks' @@install_component.sql 'reporters/ut_teamcity_reporter_helper.pkb' @@ -284,6 +357,8 @@ prompt Installing DBMSPLSQL Tables objects into &&ut3_owner schema @@install_component.sql 'reporters/ut_coveralls_reporter.tpb' @@install_component.sql 'reporters/ut_coverage_cobertura_reporter.tps' @@install_component.sql 'reporters/ut_coverage_cobertura_reporter.tpb' +@@install_component.sql 'reporters/ut_realtime_reporter.tps' +@@install_component.sql 'reporters/ut_realtime_reporter.tpb' @@install_component.sql 'api/be_between.syn' @@install_component.sql 'api/be_empty.syn' @@ -296,9 +371,12 @@ prompt Installing DBMSPLSQL Tables objects into &&ut3_owner schema @@install_component.sql 'api/be_not_null.syn' @@install_component.sql 'api/be_null.syn' @@install_component.sql 'api/be_true.syn' +@@install_component.sql 'api/be_within_pct.syn' +@@install_component.sql 'api/be_within.syn' @@install_component.sql 'api/equal.syn' @@install_component.sql 'api/have_count.syn' @@install_component.sql 'api/match.syn' +@@install_component.sql 'api/contain.syn' set linesize 200 set define on diff --git a/source/install_component.sql b/source/install_component.sql index 16c4cd8a0..373c85c54 100644 --- a/source/install_component.sql +++ b/source/install_component.sql @@ -1,6 +1,6 @@ /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/install_ddl_trigger.sql b/source/install_ddl_trigger.sql new file mode 100644 index 000000000..bc147c2be --- /dev/null +++ b/source/install_ddl_trigger.sql @@ -0,0 +1,24 @@ +/* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. +*/ + +@@define_ut3_owner_param.sql + +@@check_sys_grants.sql "'ADMINISTER DATABASE TRIGGER','CREATE TRIGGER'" + +grant administer database trigger to &&ut3_owner; +@@install_component.sql 'core/annotations/ut_trigger_annotation_parsing.trg' +revoke administer database trigger from &&ut3_owner; diff --git a/source/install_headless.sql b/source/install_headless.sql index 8acc080fa..183262675 100644 --- a/source/install_headless.sql +++ b/source/install_headless.sql @@ -1,6 +1,6 @@ /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -14,25 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -set echo off -set verify off -column 1 new_value 1 noprint -column 2 new_value 2 noprint -column 3 new_value 3 noprint -select null as "1", null as "2" , null as "3" from dual where 1=0; -column sep new_value sep noprint -select '--------------------------------------------------------------' as sep from dual; - -spool params.sql.tmp - -column ut3_owner new_value ut3_owner noprint -column ut3_password new_value ut3_password noprint -column ut3_tablespace new_value ut3_tablespace noprint - -select coalesce('&&1','UT3') ut3_owner, - coalesce('&&2','XNtxj8eEgA6X6b6f') ut3_password, - coalesce('&&3','users') ut3_tablespace from dual; +@@set_install_params.sql @@create_utplsql_owner.sql &&ut3_owner &&ut3_password &&ut3_tablespace @@install.sql &&ut3_owner diff --git a/source/install_headless_with_trigger.sql b/source/install_headless_with_trigger.sql new file mode 100644 index 000000000..76ae48ccb --- /dev/null +++ b/source/install_headless_with_trigger.sql @@ -0,0 +1,26 @@ +/* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. +*/ + +@@set_install_params.sql + +@@create_utplsql_owner.sql &&ut3_owner &&ut3_password &&ut3_tablespace +@@install.sql &&ut3_owner +@@create_synonyms_and_grants_for_public.sql &&ut3_owner + +@@install_ddl_trigger.sql &&ut3_owner + +exit diff --git a/source/reporters/ut_ansiconsole_helper.pkb b/source/reporters/ut_ansiconsole_helper.pkb index ceb0cf53f..53e6bc6aa 100644 --- a/source/reporters/ut_ansiconsole_helper.pkb +++ b/source/reporters/ut_ansiconsole_helper.pkb @@ -1,7 +1,7 @@ create or replace package body ut_ansiconsole_helper as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -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..217d36a49 100644 --- a/source/reporters/ut_ansiconsole_helper.pks +++ b/source/reporters/ut_ansiconsole_helper.pks @@ -1,7 +1,7 @@ create or replace package ut_ansiconsole_helper as /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -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..d833ac0aa 100644 --- a/source/reporters/ut_coverage_cobertura_reporter.tpb +++ b/source/reporters/ut_coverage_cobertura_reporter.tpb @@ -1,157 +1,191 @@ -create or replace type body ut_coverage_cobertura_reporter 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. - */ - - constructor function ut_coverage_cobertura_reporter( - self in out nocopy ut_coverage_cobertura_reporter - ) return self as result is - begin - self.init($$plsql_unit); - return; - end; - - - overriding member procedure after_calling_run(self in out nocopy ut_coverage_cobertura_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 - l_file_part varchar2(32767); - l_result clob; - l_line_no binary_integer; - l_pct 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); - 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); - else - l_file_part := ''||chr(10); - end if; - ut_utils.append_to_clob(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; - 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_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); - 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); - - --write header - l_file_part:= ''; - ut_utils.append_to_clob(l_result, l_file_part); - - - --Write sources - l_unit := a_coverage_data.objects.first; - l_file_part := ''||CHR(10); - ut_utils.append_to_clob(l_result, l_file_part); - - 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); - l_unit := a_coverage_data.objects.next(l_unit); - end loop; - ut_utils.append_to_clob(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); - - 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); - - l_file_part := ''||CHR(10); - ut_utils.append_to_clob(l_result, l_file_part); - - 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_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); - - 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); - 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 as ut_reporter_base).after_calling_run(a_run); - end; - - overriding member function get_description return varchar2 as - begin - return 'Generates a Cobertura coverage report providing information on code coverage with line numbers.' || chr(10) || - 'Designed for Jenkins and TFS to report coverage. ' || chr(10) || - 'Cobertura Document Type Definition can be found: http://cobertura.sourceforge.net/xml/coverage-04.dtd.'|| chr(10) || - 'Sample file: https://github.com/leobalter/testing-examples/blob/master/solutions/3/report/cobertura-coverage.xml.'; - end; - -end; -/ +create or replace type body ut_coverage_cobertura_reporter is + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + constructor function ut_coverage_cobertura_reporter( + self in out nocopy ut_coverage_cobertura_reporter + ) return self as result is + begin + self.init($$plsql_unit,ut_output_bulk_buffer()); + return; + end; + + + overriding member procedure after_calling_run(self in out nocopy ut_coverage_cobertura_reporter, a_run in ut_run) as + l_report_lines ut_varchar2_list; + l_coverage_data ut_coverage.t_coverage; + + function get_line_rate(a_lines_covered in integer, a_lines_hit in integer) return varchar2 is + begin + return to_char(round((case a_lines_covered when 0 then 0 else a_lines_covered/a_lines_hit end), 17), rpad('FM0.0',20,'9') , 'NLS_NUMERIC_CHARACTERS=''. '''); + end; + + procedure get_lines_xml(a_unit_coverage ut_coverage.t_unit_coverage, + a_lines_result in out nocopy clob, a_lines_hits out number, a_lines_total out number) is + l_file_part varchar2(32767); + l_result clob; + l_line_no binary_integer; + l_pct integer; + l_lines_hits integer := 0; + l_lines_total integer := 0; + 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 + ut_utils.append_to_clob(l_result, ''||chr(10)); + end loop; + l_lines_hits:=0; + l_lines_total:= a_unit_coverage.total_lines; + 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); + else + l_lines_hits:= l_lines_hits+1; + l_file_part := ''||chr(10); + end if; + ut_utils.append_to_clob(l_result, l_file_part); + l_line_no := a_unit_coverage.lines.next(l_line_no); + l_lines_total := l_lines_total + 1; + end loop; + end if; + a_lines_result := l_result; + a_lines_hits :=l_lines_hits; + a_lines_total := l_lines_total; + end; + + function get_coverage_xml( + a_coverage_data ut_coverage.t_coverage, + a_run ut_run + ) return ut_varchar2_rows is + + l_file_part varchar2(32767); + l_lines_xml clob; + l_result ut_varchar2_rows := ut_varchar2_rows(); + l_unit ut_coverage.t_object_name; + l_obj_name ut_coverage.t_object_name; + c_coverage_def constant varchar2(200) := ''; + c_file_footer constant varchar2(30) := ''; + c_coverage_footer constant varchar2(30) := ''; + 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_classes_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; + l_lines_valid integer := a_coverage_data.covered_lines + a_coverage_data.uncovered_lines; + l_line_hits integer; + l_line_total integer; + begin + + 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 + ut_utils.append_to_list( + l_result, + '' + ); + + + --Write sources + l_unit := a_coverage_data.objects.first; + ut_utils.append_to_list( l_result, '' ); + + while l_unit is not null loop + 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_list(l_result, c_sources_footer); + + --write packages + l_unit := a_coverage_data.objects.first; + ut_utils.append_to_list(l_result, ''); + + while l_unit is not null loop + l_obj_name := a_coverage_data.objects(l_unit).name; + dbms_lob.createtemporary(l_lines_xml, true); + get_lines_xml(a_coverage_data.objects(l_unit),l_lines_xml,l_line_hits,l_line_total); + + ut_utils.append_to_list( + l_result, + '' + ); + + ut_utils.append_to_list( + l_result, + '' + ); + + ut_utils.append_to_list( + l_result, + '' + ); + + ut_utils.append_to_list(l_result, ''); + ut_utils.append_to_list( l_result,l_lines_xml); + dbms_lob.freetemporary(l_lines_xml); + + 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_classes_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_list(l_result, c_packages_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_text_lines( get_coverage_xml( l_coverage_data, a_run ) ); + + (self as ut_reporter_base).after_calling_run(a_run); + end; + + overriding member function get_description return varchar2 as + begin + return 'Generates a Cobertura coverage report providing information on code coverage with line numbers.' || chr(10) || + 'Designed for Jenkins and TFS to report coverage. ' || chr(10) || + 'Cobertura Document Type Definition can be found: http://cobertura.sourceforge.net/xml/coverage-04.dtd.'|| chr(10) || + 'Sample file: https://github.com/leobalter/testing-examples/blob/master/solutions/3/report/cobertura-coverage.xml.'; + end; + +end; +/ diff --git a/source/reporters/ut_coverage_cobertura_reporter.tps b/source/reporters/ut_coverage_cobertura_reporter.tps index 6bfd60892..1292e60fb 100644 --- a/source/reporters/ut_coverage_cobertura_reporter.tps +++ b/source/reporters/ut_coverage_cobertura_reporter.tps @@ -1,7 +1,7 @@ create or replace type ut_coverage_cobertura_reporter under ut_coverage_reporter_base( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/reporters/ut_coverage_html_reporter.tpb b/source/reporters/ut_coverage_html_reporter.tpb index a6b5b4517..b1f9f6651 100644 --- a/source/reporters/ut_coverage_html_reporter.tpb +++ b/source/reporters/ut_coverage_html_reporter.tpb @@ -1,7 +1,7 @@ create or replace type body ut_coverage_html_reporter is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -22,20 +22,19 @@ create or replace type body ut_coverage_html_reporter is a_html_report_assets_path varchar2 := null ) return self as result is begin - self.init($$plsql_unit); + self.init($$plsql_unit,ut_output_bulk_buffer()); self.project_name := a_project_name; assets_path := nvl(a_html_report_assets_path, ut_coverage_report_html_helper.get_default_html_assets_path()); return; 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_html_reporter.tps b/source/reporters/ut_coverage_html_reporter.tps index 11984ac58..42f2fd4e3 100644 --- a/source/reporters/ut_coverage_html_reporter.tps +++ b/source/reporters/ut_coverage_html_reporter.tps @@ -1,7 +1,7 @@ create or replace type ut_coverage_html_reporter under ut_coverage_reporter_base( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/reporters/ut_coverage_report_html_helper.pkb b/source/reporters/ut_coverage_report_html_helper.pkb index 725a232f2..f7e0b5ed0 100644 --- a/source/reporters/ut_coverage_report_html_helper.pkb +++ b/source/reporters/ut_coverage_report_html_helper.pkb @@ -1,7 +1,7 @@ create or replace package body ut_coverage_report_html_helper is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -90,7 +90,7 @@ create or replace package body ut_coverage_report_html_helper is function object_id(a_object_full_name varchar2) return varchar2 is begin - return rawtohex(utl_raw.cast_to_raw(dbms_obfuscation_toolkit.md5(input_string => a_object_full_name))); + return rawtohex(dbms_crypto.hash(src => utl_raw.cast_to_raw(a_object_full_name), typ => dbms_crypto.hash_md5)); end; function link_to_source_file(a_object_full_name varchar2) return varchar2 is @@ -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,16 @@ 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); - l_coverage_block_pct number(5, 2); - l_hits varchar2(30); - l_blocks varchar2(30); + 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_hits varchar2(30); + l_blocks varchar2(30); + l_line_text varchar2(32767); + e_buffer_too_small exception; + pragma exception_init ( e_buffer_too_small, -19011 ); begin - dbms_lob.createtemporary(l_result, true); l_coverage_pct := coverage_pct(a_coverage_unit.covered_lines, a_coverage_unit.uncovered_lines); @@ -145,13 +147,19 @@ 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 + begin + l_line_text := dbms_xmlgen.convert(a_source_code(line_no)); + exception + when e_buffer_too_small then + l_line_text := dbms_xmlgen.convert(to_clob(a_source_code(line_no))); + end; if not a_coverage_unit.lines.exists(line_no) then l_file_part := '
  1. - ' || (dbms_xmlgen.convert(a_source_code(line_no))) || + ' || l_line_text || '
  2. '; else l_hits := to_char(a_coverage_unit.lines(line_no).executions); @@ -188,25 +196,23 @@ function get_details_file_content(a_object_id varchar2, a_unit ut_object_name, a ''; end if; l_file_part := l_file_part || ' - ' || (dbms_xmlgen.convert(a_source_code(line_no))) || + ' || l_line_text || ''; 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 +226,17 @@ 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 +254,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 +269,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,15 +286,15 @@ 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); l_using varchar2(1000); - l_unit ut_coverage.t_full_name; + l_unit ut_coverage.t_object_name; l_charset varchar2(1000); begin l_charset := coalesce(upper(a_charset),'UTF-8'); @@ -302,8 +305,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 +324,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..42a59c123 100644 --- a/source/reporters/ut_coverage_report_html_helper.pks +++ b/source/reporters/ut_coverage_report_html_helper.pks @@ -1,7 +1,7 @@ create or replace package ut_coverage_report_html_helper authid current_user is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -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..1861a9be3 100644 --- a/source/reporters/ut_coverage_sonar_reporter.tpb +++ b/source/reporters/ut_coverage_sonar_reporter.tpb @@ -1,7 +1,7 @@ create or replace type body ut_coverage_sonar_reporter is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -20,86 +20,92 @@ create or replace type body ut_coverage_sonar_reporter is self in out nocopy ut_coverage_sonar_reporter ) return self as result is begin - self.init($$plsql_unit); + self.init($$plsql_unit,ut_output_bulk_buffer()); return; end; 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; - l_unit ut_coverage.t_full_name; - c_coverage_header constant varchar2(30) := ''||chr(10); - c_file_footer constant varchar2(30) := ''||chr(10); + ) return ut_varchar2_rows is + l_result ut_varchar2_rows := ut_varchar2_rows(); + l_unit ut_coverage.t_object_name; + 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 +-- execute immediate 'alter session set statistics_level=all'; +-- dbms_hprof.start_profiling( +-- location => 'PLSHPROF_DIR' +-- , filename => 'profiler_utPLSQL_run_on_'||$$plsql_unit||'_'||rawtohex(self.id)||'.txt' +-- ); +-- 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 + ) + ); +-- dbms_hprof.stop_profiling; end; overriding member function get_description return varchar2 as begin - return 'Generates a JSON coverage report providing information on code coverage with line numbers.' || chr(10) || - 'Designed for [SonarQube](https://about.sonarqube.com/) to report coverage.' || chr(10) || - 'JSON format returned conforms with the Sonar specification: https://docs.sonarqube.org/display/SONAR/Generic+Test+Data'; + return 'Generates a XML coverage report providing information on code coverage with line numbers.' || chr(10) || + 'Designed for [SonarQube](https://www.sonarqube.org/) to report coverage.' || chr(10) || + 'XML format returned conforms with the Sonar specification: https://docs.sonarqube.org/latest/analysis/generic-test/'; end; end; diff --git a/source/reporters/ut_coverage_sonar_reporter.tps b/source/reporters/ut_coverage_sonar_reporter.tps index af52f1675..715bdefd2 100644 --- a/source/reporters/ut_coverage_sonar_reporter.tps +++ b/source/reporters/ut_coverage_sonar_reporter.tps @@ -1,7 +1,7 @@ create or replace type ut_coverage_sonar_reporter under ut_coverage_reporter_base( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ create or replace type ut_coverage_sonar_reporter under ut_coverage_reporter_bas /** * Builds a coverage XML report that follows rules described in - * https://docs.sonarqube.org/display/SONAR/Generic+Test+Data + * https://docs.sonarqube.org/latest/analysis/generic-test/ */ constructor function ut_coverage_sonar_reporter( self in out nocopy ut_coverage_sonar_reporter diff --git a/source/reporters/ut_coveralls_reporter.tpb b/source/reporters/ut_coveralls_reporter.tpb index 3681147f3..14672303e 100644 --- a/source/reporters/ut_coveralls_reporter.tpb +++ b/source/reporters/ut_coveralls_reporter.tpb @@ -1,7 +1,7 @@ create or replace type body ut_coveralls_reporter is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -20,27 +20,24 @@ create or replace type body ut_coveralls_reporter is self in out nocopy ut_coveralls_reporter ) return self as result is begin - self.init($$plsql_unit); + self.init($$plsql_unit,ut_output_bulk_buffer()); return; 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; - 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); + ) return ut_varchar2_rows is + l_result ut_varchar2_rows := ut_varchar2_rows(); + l_unit ut_coverage.t_object_name; + 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_coveralls_reporter.tps b/source/reporters/ut_coveralls_reporter.tps index b5c1e1f28..74363b751 100644 --- a/source/reporters/ut_coveralls_reporter.tps +++ b/source/reporters/ut_coveralls_reporter.tps @@ -1,7 +1,7 @@ create or replace type ut_coveralls_reporter under ut_coverage_reporter_base( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ create or replace type ut_coveralls_reporter under ut_coverage_reporter_base( /** * Builds a coverage XML report that follows rules described in - * https://docs.sonarqube.org/display/SONAR/Generic+Test+Data + * https://docs.coveralls.io/api-introduction */ constructor function ut_coveralls_reporter( self in out nocopy ut_coveralls_reporter diff --git a/source/reporters/ut_debug_reporter.tpb b/source/reporters/ut_debug_reporter.tpb new file mode 100644 index 000000000..879725172 --- /dev/null +++ b/source/reporters/ut_debug_reporter.tpb @@ -0,0 +1,79 @@ +create or replace type body ut_debug_reporter is + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + constructor function ut_debug_reporter(self in out nocopy ut_debug_reporter) return self as result is + begin + self.init($$plsql_unit,ut_output_clob_table_buffer()); + self.start_time := current_timestamp(); + self.event_time := current_timestamp(); + return; + end; + + overriding member function get_supported_events return ut_varchar2_list is + begin + return ut_varchar2_list(ut_event_manager.gc_all); + end; + + overriding member procedure on_event( self in out nocopy ut_debug_reporter, a_event_name varchar2, a_event_item ut_event_item) is + c_time constant timestamp := current_timestamp(); + c_time_from_start constant interval day(0) to second(6) := (c_time - self.start_time); + c_time_from_prev constant interval day(0) to second(6) := (c_time - self.event_time); + l_stack varchar2(32767) := dbms_utility.format_call_stack(); + begin + l_stack := regexp_replace( + substr( l_stack, instr( l_stack, chr(10), 1, 6 ) +1 ), + '[0-9abcdefx]+ +([0-9]+) +(package |type )?(body )?(.*)','at "\4", line \1'); + + if a_event_name = ut_event_manager.gc_initialize then + self.on_initialize(null); + self.print_text('', ut_event_manager.gc_debug); + end if; + self.print_text('', ut_event_manager.gc_debug); + self.print_text( + ' ' || ut_utils.to_string(c_time) || '' || chr(10) + || ' ' || c_time_from_start || '' || chr(10) + || ' ' || c_time_from_prev || '' || chr(10) + || ' ' || a_event_name || '', + ut_event_manager.gc_debug + ); + self.print_text( ' ' || l_stack || '', ut_event_manager.gc_debug); + if a_event_item is not null then + self.print_text_lines( + ut_utils.convert_collection( + ut_utils.clob_to_table( event_item_to_clob(a_event_item), ut_utils.gc_max_storage_varchar2_len ) + ), + ut_event_manager.gc_debug + ); + end if; + self.print_text('', ut_event_manager.gc_debug); + if a_event_name = ut_event_manager.gc_finalize then + self.print_text('', ut_event_manager.gc_debug); + self.on_finalize(null); + end if; + self.event_time := current_timestamp(); + end; + + member function event_item_to_clob(a_event_item ut_event_item) return clob is + l_clob clob; + begin + select /*+ no_parallel */ xmlserialize( content deletexml(xmltype(a_event_item),'/*/ITEMS|/*/ALL_EXPECTATIONS|/*/FAILED_EXPECTATIONS') as clob indent size = 2 ) into l_clob from dual; + return l_clob; + end; + +end; +/ \ No newline at end of file diff --git a/source/reporters/ut_debug_reporter.tps b/source/reporters/ut_debug_reporter.tps new file mode 100644 index 000000000..2123f19cc --- /dev/null +++ b/source/reporters/ut_debug_reporter.tps @@ -0,0 +1,34 @@ +create or replace type ut_debug_reporter under ut_output_reporter_base( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + start_time timestamp, + event_time timestamp, + constructor function ut_debug_reporter(self in out nocopy ut_debug_reporter) return self as result, + /** + * Returns the list of events that are supported by particular implementation of the reporter + */ + overriding member function get_supported_events return ut_varchar2_list, + + /** + * Delegates execution of event into individual reporting procedures + */ + overriding member procedure on_event( self in out nocopy ut_debug_reporter, a_event_name varchar2, a_event_item ut_event_item), + + member function event_item_to_clob(a_event_item ut_event_item) return clob + +) +/ \ No newline at end of file diff --git a/source/reporters/ut_documentation_reporter.tpb b/source/reporters/ut_documentation_reporter.tpb index 73ac3bf1a..e8c0a4e31 100644 --- a/source/reporters/ut_documentation_reporter.tpb +++ b/source/reporters/ut_documentation_reporter.tpb @@ -1,7 +1,7 @@ create or replace type body ut_documentation_reporter is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -29,13 +29,28 @@ create or replace type body ut_documentation_reporter is return rpad(' ', self.lvl * 2); end tab; - overriding member procedure print_text(self in out nocopy ut_documentation_reporter, a_text varchar2) is + overriding member procedure print_clob(self in out nocopy ut_documentation_reporter, a_clob clob, a_item_type varchar2 := null) is + l_lines ut_varchar2_list; + l_out_lines ut_varchar2_rows := ut_varchar2_rows(); + begin + if a_clob is not null and dbms_lob.getlength(a_clob) > 0 then + l_lines := ut_utils.clob_to_table(a_clob, ut_utils.gc_max_storage_varchar2_len - length(nvl(tab(),0))); + for i in 1 .. l_lines.count loop + if l_lines(i) is not null then + ut_utils.append_to_list(l_out_lines, tab() || l_lines(i) ); + end if; + end loop; + (self as ut_output_reporter_base).print_text_lines(l_out_lines, a_item_type); + end if; + end; + + overriding member procedure print_text(self in out nocopy ut_documentation_reporter, a_text varchar2, a_item_type varchar2 := null) is l_lines ut_varchar2_list; begin if a_text is not null then l_lines := ut_utils.string_to_table(a_text); for i in 1 .. l_lines.count loop - (self as ut_output_reporter_base).print_text(tab || l_lines(i)); + (self as ut_output_reporter_base).print_text(tab || l_lines(i), a_item_type); end loop; end if; end; @@ -53,7 +68,11 @@ create or replace type body ut_documentation_reporter is l_message := coalesce(a_test.description, a_test.name)||' ['||round(a_test.execution_time,3)||' sec]'; --if test failed, then add it to the failures list, print failure with number if a_test.result = ut_utils.gc_disabled then - self.print_yellow_text(l_message || ' (DISABLED)'); + self.print_yellow_text(l_message || ' (DISABLED'|| + case when a_test.disabled_reason is not null + then ' - '||a_test.disabled_reason + else null + end || ')'); elsif a_test.result = ut_utils.gc_success then self.print_green_text(l_message); elsif a_test.result > ut_utils.gc_success then @@ -183,7 +202,7 @@ create or replace type body ut_documentation_reporter is begin print_failures_details(a_run); print_warnings(a_run); - self.print_text('Finished in ' || a_run.execution_time || ' seconds'); + self.print_text('Finished in ' || ut_utils.interval_to_text(numtodsinterval(a_run.execution_time,'second')) ); l_summary_text := a_run.results_count.total_count || ' tests, ' @@ -194,6 +213,9 @@ create or replace type body ut_documentation_reporter is else self.print_green_text(l_summary_text); end if; + if a_run.random_test_order_seed is not null then + self.print_text('Tests were executed with random order seed '''||a_run.random_test_order_seed||'''.'); + end if; self.print_text(' '); (self as ut_reporter_base).after_calling_run(a_run); end; diff --git a/source/reporters/ut_documentation_reporter.tps b/source/reporters/ut_documentation_reporter.tps index 717ab3cd7..422225117 100644 --- a/source/reporters/ut_documentation_reporter.tps +++ b/source/reporters/ut_documentation_reporter.tps @@ -1,7 +1,7 @@ create or replace type ut_documentation_reporter under ut_console_reporter_base( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -20,7 +20,8 @@ create or replace type ut_documentation_reporter under ut_console_reporter_base( constructor function ut_documentation_reporter(self in out nocopy ut_documentation_reporter) return self as result, member function tab(self in ut_documentation_reporter) return varchar2, - overriding member procedure print_text(self in out nocopy ut_documentation_reporter, a_text varchar2), + overriding member procedure print_clob(self in out nocopy ut_documentation_reporter, a_clob clob, a_item_type varchar2 := null), + overriding member procedure print_text(self in out nocopy ut_documentation_reporter, a_text varchar2, a_item_type varchar2 := null), overriding member procedure before_calling_suite(self in out nocopy ut_documentation_reporter, a_suite ut_logical_suite), overriding member procedure after_calling_test(self in out nocopy ut_documentation_reporter, a_test ut_test), overriding member procedure after_calling_after_all (self in out nocopy ut_documentation_reporter, a_executable in ut_executable), diff --git a/source/reporters/ut_junit_reporter.tpb b/source/reporters/ut_junit_reporter.tpb index 63d256aab..3bceb52a4 100644 --- a/source/reporters/ut_junit_reporter.tpb +++ b/source/reporters/ut_junit_reporter.tpb @@ -1,7 +1,7 @@ create or replace type body ut_junit_reporter is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -18,13 +18,11 @@ create or replace type body ut_junit_reporter is constructor function ut_junit_reporter(self in out nocopy ut_junit_reporter) return self as result is begin - self.init($$plsql_unit); + self.init($$plsql_unit,ut_output_bulk_buffer()); return; end; overriding member procedure after_calling_run(self in out nocopy ut_junit_reporter, a_run in ut_run) is - c_cddata_tag_start constant varchar2(30) := ''; l_suite_id integer := 0; l_tests_count integer := a_run.results_count.disabled_count + a_run.results_count.success_count + a_run.results_count.failure_count + a_run.results_count.errored_count; @@ -35,60 +33,60 @@ 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_output clob; + l_results ut_varchar2_rows := ut_varchar2_rows(); + 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(''); + if a_test.disabled_reason is not null then + ut_utils.append_to_list( l_results, '' ); + ut_utils.append_to_list( l_results, ut_utils.to_cdata( a_test.disabled_reason ) ); + ut_utils.append_to_list( l_results, '' ); + else + ut_utils.append_to_list( l_results, '' ); + end if; 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, ut_utils.to_cdata( ut_utils.convert_collection( a_test.get_error_stack_traces() ) ) ); + ut_utils.append_to_list( l_results, ''); elsif a_test.result > ut_utils.gc_success then - self.print_text(''); - 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))); - end loop; - self.print_text(dbms_xmlgen.convert(a_test.failed_expectations(i).caller_info)); - end loop; - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ut_utils.to_cdata( a_test.get_failed_expectation_lines() ) ); + 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, ut_utils.to_cdata( a_test.get_serveroutputs() ) ); + 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 - l_tests_count integer := a_suite.results_count.disabled_count + a_suite.results_count.success_count + + l_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_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 a_suite_id := a_suite_id + 1; - self.print_text(''); -- Becasue testsuites have to appear before test we capture test and leave it for later. @@ -110,29 +108,28 @@ create or replace type body ut_junit_reporter is l_suite := treat(a_suite as ut_suite); 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(''); + if l_data is not null then + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ut_utils.to_cdata( l_data ) ); + 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, ut_utils.to_cdata( ut_utils.convert_collection( l_errors ) ) ); + 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_junit_reporter.tps b/source/reporters/ut_junit_reporter.tps index 051358c59..6cdaff1b9 100644 --- a/source/reporters/ut_junit_reporter.tps +++ b/source/reporters/ut_junit_reporter.tps @@ -1,7 +1,7 @@ create or replace type ut_junit_reporter force under ut_output_reporter_base( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/reporters/ut_realtime_reporter.tpb b/source/reporters/ut_realtime_reporter.tpb new file mode 100644 index 000000000..9c2af57ec --- /dev/null +++ b/source/reporters/ut_realtime_reporter.tpb @@ -0,0 +1,288 @@ +create or replace type body ut_realtime_reporter is + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + constructor function ut_realtime_reporter( + self in out nocopy ut_realtime_reporter + ) return self as result is + begin + self.init($$plsql_unit,ut_output_clob_table_buffer()); + total_number_of_tests := 0; + current_test_number := 0; + current_indent := 0; + print_buffer := ut_varchar2_rows(); + return; + end; + + overriding member procedure before_calling_run( + self in out nocopy ut_realtime_reporter, + a_run in ut_run + ) is + procedure print_test_elements( + a_test in ut_test + ) is + begin + total_number_of_tests := total_number_of_tests + 1; + self.print_start_node('test', 'id', a_test.path); + self.print_node('executableType', a_test.item.executable_type); + self.print_node('ownerName', a_test.item.owner_name); + self.print_node('objectName', a_test.item.object_name); + self.print_node('procedureName', a_test.item.procedure_name); + self.print_node('disabled', case when a_test.get_disabled_flag() then 'true' else 'false' end); + self.print_node('disabledReason', a_test.disabled_reason); + self.print_node('name', a_test.name); + self.print_node('description', a_test.description); + self.print_node('testNumber', to_char(total_number_of_tests)); + self.print_end_node('test'); + end print_test_elements; + + procedure print_suite_elements( + a_suite in ut_logical_suite + ) is + begin + self.print_start_node('suite', 'id', a_suite.path); + self.print_node('name', a_suite.name); + self.print_node('description', a_suite.description); + <> + self.print_start_node('items'); + for i in 1 .. a_suite.items.count loop + if a_suite.items(i) is of(ut_test) then + print_test_elements(treat(a_suite.items(i) as ut_test)); + elsif a_suite.items(i) is of(ut_logical_suite) then + print_suite_elements(treat(a_suite.items(i) as ut_logical_suite)); + end if; + end loop suite_elements; + self.print_end_node('items'); + self.print_end_node('suite'); + end print_suite_elements; + begin + xml_header := ut_utils.get_xml_header(a_run.client_character_set); + self.print_xml_fragment(xml_header); + self.print_start_node('event', 'type', 'pre-run'); + self.print_start_node('items'); + <> + for i in 1 .. a_run.items.count loop + print_suite_elements(treat(a_run.items(i) as ut_logical_suite)); + end loop items; + self.print_end_node('items'); + self.print_node('totalNumberOfTests', to_char(total_number_of_tests)); + self.print_end_node('event'); + self.flush_print_buffer('pre-run'); + end before_calling_run; + + overriding member procedure after_calling_run( + self in out nocopy ut_realtime_reporter, + a_run in ut_run + ) is + begin + self.print_xml_fragment(xml_header); + self.print_start_node('event', 'type', 'post-run'); + self.print_start_node('run'); + self.print_node('startTime', to_char(a_run.start_time, 'YYYY-MM-DD"T"HH24:MI:SS.FF6')); + self.print_node('endTime', to_char(a_run.end_time, 'YYYY-MM-DD"T"HH24:MI:SS.FF6')); + self.print_node('executionTime', ut_utils.to_xml_number_format(a_run.execution_time())); + self.print_start_node('counter'); + self.print_node('disabled', to_char(a_run.results_count.disabled_count)); + self.print_node('success', to_char(a_run.results_count.success_count)); + self.print_node('failure', to_char(a_run.results_count.failure_count)); + self.print_node('error', to_char(a_run.results_count.errored_count)); + self.print_node('warning', to_char(a_run.results_count.warnings_count)); + self.print_end_node('counter'); + self.print_cdata_node('errorStack', ut_utils.table_to_clob(a_run.get_error_stack_traces(), chr(10)||chr(10))); + self.print_cdata_node('serverOutput', a_run.get_serveroutputs()); + self.print_end_node('run'); + self.print_end_node('event'); + self.flush_print_buffer('post-run'); + end after_calling_run; + + overriding member procedure before_calling_suite( + self in out nocopy ut_realtime_reporter, + a_suite in ut_logical_suite + ) is + begin + self.print_xml_fragment(xml_header); + self.print_start_node('event', 'type', 'pre-suite'); + self.print_start_node('suite', 'id', a_suite.path); + self.print_end_node('suite'); + self.print_end_node('event'); + self.flush_print_buffer('pre-suite'); + end before_calling_suite; + + overriding member procedure after_calling_suite( + self in out nocopy ut_realtime_reporter, + a_suite in ut_logical_suite + ) is + begin + self.print_xml_fragment(xml_header); + self.print_start_node('event', 'type', 'post-suite'); + self.print_start_node('suite', 'id', a_suite.path); + self.print_node('startTime', to_char(a_suite.start_time, 'YYYY-MM-DD"T"HH24:MI:SS.FF6')); + self.print_node('endTime', to_char(a_suite.end_time, 'YYYY-MM-DD"T"HH24:MI:SS.FF6')); + self.print_node('executionTime', ut_utils.to_xml_number_format(a_suite.execution_time())); + self.print_start_node('counter'); + self.print_node('disabled', to_char(a_suite.results_count.disabled_count)); + self.print_node('success', to_char(a_suite.results_count.success_count)); + self.print_node('failure', to_char(a_suite.results_count.failure_count)); + self.print_node('error', to_char(a_suite.results_count.errored_count)); + self.print_node('warning', to_char(a_suite.results_count.warnings_count)); + self.print_end_node('counter'); + self.print_cdata_node('errorStack', ut_utils.table_to_clob(a_suite.get_error_stack_traces(), chr(10)||chr(10))); + self.print_cdata_node('serverOutput', a_suite.get_serveroutputs()); + self.print_cdata_node('warnings', ut_utils.table_to_clob(a_suite.warnings, chr(10)||chr(10))); + self.print_end_node('suite'); + self.print_end_node('event'); + self.flush_print_buffer('post-suite'); + end after_calling_suite; + + overriding member procedure before_calling_test( + self in out nocopy ut_realtime_reporter, + a_test in ut_test + ) is + begin + current_test_number := current_test_number + 1; + self.print_xml_fragment(xml_header); + self.print_start_node('event', 'type', 'pre-test'); + self.print_start_node('test', 'id', a_test.path); + self.print_node('testNumber', to_char(current_test_number)); + self.print_node('totalNumberOfTests', to_char(total_number_of_tests)); + self.print_end_node('test'); + self.print_end_node('event'); + self.flush_print_buffer('pre-test'); + end before_calling_test; + + overriding member procedure after_calling_test( + self in out nocopy ut_realtime_reporter, + a_test in ut_test + ) is + begin + self.print_xml_fragment(xml_header); + self.print_start_node('event', 'type', 'post-test'); + self.print_start_node('test', 'id', a_test.path); + self.print_node('testNumber', to_char(current_test_number)); + self.print_node('totalNumberOfTests', to_char(total_number_of_tests)); + self.print_node('startTime', to_char(a_test.start_time, 'YYYY-MM-DD"T"HH24:MI:SS.FF6')); + self.print_node('endTime', to_char(a_test.end_time, 'YYYY-MM-DD"T"HH24:MI:SS.FF6')); + self.print_node('executionTime', ut_utils.to_xml_number_format(a_test.execution_time())); + self.print_start_node('counter'); + self.print_node('disabled', to_char(a_test.results_count.disabled_count)); + self.print_node('success', to_char(a_test.results_count.success_count)); + self.print_node('failure', to_char(a_test.results_count.failure_count)); + self.print_node('error', to_char(a_test.results_count.errored_count)); + self.print_node('warning', to_char(a_test.results_count.warnings_count)); + self.print_end_node('counter'); + self.print_cdata_node('errorStack', ut_utils.table_to_clob(a_test.get_error_stack_traces(), chr(10)||chr(10))); + self.print_cdata_node('serverOutput', a_test.get_serveroutputs()); + if a_test.failed_expectations.count > 0 then + self.print_start_node('failedExpectations'); + <> + for i in 1 .. a_test.failed_expectations.count loop + self.print_start_node('expectation'); + self.print_node('description', a_test.failed_expectations(i).description); + self.print_cdata_node('message', a_test.failed_expectations(i).message); + self.print_cdata_node('caller', a_test.failed_expectations(i).caller_info); + self.print_end_node('expectation'); + end loop expectations; + self.print_end_node('failedExpectations'); + end if; + self.print_cdata_node('warnings', ut_utils.table_to_clob(a_test.warnings, chr(10)||chr(10))); + self.print_end_node('test'); + self.print_end_node('event'); + self.flush_print_buffer('post-test'); + end after_calling_test; + + overriding member function get_description return varchar2 is + begin + return 'Provides test results in a XML format, for clients such as SQL Developer interested in showing progressing details.'; + end get_description; + + member procedure print_start_node( + self in out nocopy ut_realtime_reporter, + a_node_name in varchar2, + a_attr_name in varchar2 default null, + a_attr_value in varchar2 default null + ) is + begin + self.print_xml_fragment( + '<' || a_node_name + || case + when a_attr_name is not null and a_attr_value is not null then + ' ' || a_attr_name || '="' || dbms_xmlgen.convert(a_attr_value) || '"' + end + || '>', + 0, 1 + ); + end print_start_node; + + member procedure print_end_node( + self in out nocopy ut_realtime_reporter, + a_name in varchar2 + ) is + begin + self.print_xml_fragment('', -1); + end print_end_node; + + member procedure print_node( + self in out nocopy ut_realtime_reporter, + a_name in varchar2, + a_content in clob + ) is + begin + if a_content is not null then + self.print_xml_fragment('<' || a_name || '>' || dbms_xmlgen.convert(a_content) || ''); + end if; + end print_node; + + member procedure print_cdata_node( + self in out nocopy ut_realtime_reporter, + a_name in varchar2, + a_content in clob + ) is + begin + if a_content is not null then + self.print_xml_fragment('<' || a_name || '>' || ut_utils.to_cdata(a_content) || ''); + end if; + end print_cdata_node; + + member procedure print_xml_fragment( + self in out nocopy ut_realtime_reporter, + a_fragment in clob, + a_indent_summand_before in integer default 0, + a_indent_summand_after in integer default 0 + ) is + begin + current_indent := current_indent + a_indent_summand_before; + ut_utils.append_to_list(print_buffer, lpad(' ', 2 * current_indent) || a_fragment); + current_indent := current_indent + a_indent_summand_after; + end print_xml_fragment; + + member procedure flush_print_buffer( + self in out nocopy ut_realtime_reporter, + a_item_type in varchar2 + ) is + l_doc clob; + l_rows integer := print_buffer.count; + begin + for i in 1 .. l_rows loop + ut_utils.append_to_clob(l_doc, print_buffer(i)); + ut_utils.append_to_clob(l_doc, chr(10)); + end loop; + self.print_clob(l_doc, a_item_type); + print_buffer.delete; + end flush_print_buffer; + +end; +/ diff --git a/source/reporters/ut_realtime_reporter.tps b/source/reporters/ut_realtime_reporter.tps new file mode 100644 index 000000000..0501006e4 --- /dev/null +++ b/source/reporters/ut_realtime_reporter.tps @@ -0,0 +1,163 @@ +create or replace type ut_realtime_reporter force under ut_output_reporter_base( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. + */ + + /** + * Cached XML header to be used for every XML document + */ + xml_header varchar2(4000), + + /** + * Total number of all tests in the run (incl. disabled tests). + */ + total_number_of_tests integer, + + /** + * Currently executed test number. + */ + current_test_number integer, + + /** + * Current indentation in logical tabs. + */ + current_indent integer, + + /** + * Buffers lines to be printed. + */ + print_buffer ut_varchar2_rows, + + /** + * The realtime reporter. + * Provides test results in a XML format, for clients such as SQL Developer interested in showing progressing details. + */ + constructor function ut_realtime_reporter( + self in out nocopy ut_realtime_reporter + ) return self as result, + + /** + * Provides meta data of complete run in advance. + */ + overriding member procedure before_calling_run( + self in out nocopy ut_realtime_reporter, + a_run in ut_run + ), + + /** + * Provides meta data of a completed run. + */ + overriding member procedure after_calling_run( + self in out nocopy ut_realtime_reporter, + a_run in ut_run + ), + + /** + * Indicates the start of a test suite execution. + */ + overriding member procedure before_calling_suite( + self in out nocopy ut_realtime_reporter, + a_suite in ut_logical_suite + ), + + /** + * Provides meta data of completed test suite. + */ + overriding member procedure after_calling_suite( + self in out nocopy ut_realtime_reporter, + a_suite in ut_logical_suite + ), + + /** + * Indicates the start of a test. + */ + overriding member procedure before_calling_test( + self in out nocopy ut_realtime_reporter, + a_test in ut_test + ), + + /** + * Provides meta data of a completed test. + */ + overriding member procedure after_calling_test( + self in out nocopy ut_realtime_reporter, + a_test in ut_test + ), + + /** + * Provides the description of this reporter. + */ + overriding member function get_description return varchar2, + + /** + * Prints the start tag of a XML node with an optional attribute. + */ + member procedure print_start_node( + self in out nocopy ut_realtime_reporter, + a_node_name in varchar2, + a_attr_name in varchar2 default null, + a_attr_value in varchar2 default null + ), + + /** + * Prints the end tag of a XML node. + */ + member procedure print_end_node( + self in out nocopy ut_realtime_reporter, + a_name in varchar2 + ), + + /** + * Prints a child node with content. Special characters are encoded. + */ + member procedure print_node( + self in out nocopy ut_realtime_reporter, + a_name in varchar2, + a_content in clob + ), + + /** + * Prints a child node with content. Content is passed 1:1 using CDATA. + */ + member procedure print_cdata_node( + self in out nocopy ut_realtime_reporter, + a_name in varchar2, + a_content in clob + ), + + /** + * Prints a line of the resulting XML document using the current indentation. + * a_indent_summand_before is added before printing a line. + * a_indent_summand_after is added after printing a line. + * All output is produced through this function. + */ + member procedure print_xml_fragment( + self in out nocopy ut_realtime_reporter, + a_fragment in clob, + a_indent_summand_before in integer default 0, + a_indent_summand_after in integer default 0 + ), + + /** + * Flushes the local print buffer to the output buffer. + */ + member procedure flush_print_buffer( + self in out nocopy ut_realtime_reporter, + a_item_type in varchar2 + ) +) +not final +/ diff --git a/source/reporters/ut_sonar_test_reporter.tpb b/source/reporters/ut_sonar_test_reporter.tpb index 913ae8b50..7c46879d2 100644 --- a/source/reporters/ut_sonar_test_reporter.tpb +++ b/source/reporters/ut_sonar_test_reporter.tpb @@ -1,7 +1,7 @@ create or replace type body ut_sonar_test_reporter is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ create or replace type body ut_sonar_test_reporter is self in out nocopy ut_sonar_test_reporter ) return self as result is begin - self.init($$plsql_unit); + self.init($$plsql_unit,ut_output_bulk_buffer()); return; end; @@ -43,28 +43,23 @@ 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(); 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.to_cdata( ut_utils.convert_collection( a_test.get_error_stack_traces() ) ) ); + ut_utils.append_to_list( l_results, ''); elsif a_test.result > ut_utils.gc_success then - self.print_text(''); - 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))); - end loop; - end loop; - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ut_utils.to_cdata( a_test.get_failed_expectation_lines() ) ); + 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 @@ -111,9 +106,9 @@ create or replace type body ut_sonar_test_reporter is overriding member function get_description return varchar2 as begin - return 'Generates a JSON report providing detailed information on test execution.' || chr(10) || - 'Designed for [SonarQube](https://about.sonarqube.com/) to report test execution.' || chr(10) || - 'JSON format returned conforms with the Sonar specification: https://docs.sonarqube.org/display/SONAR/Generic+Test+Data'; + return 'Generates a XML report providing detailed information on test execution.' || chr(10) || + 'Designed for [SonarQube](https://www.sonarqube.org/) to report test execution.' || chr(10) || + 'XML format returned conforms with the Sonar specification: https://docs.sonarqube.org/latest/analysis/generic-test/'; end; end; diff --git a/source/reporters/ut_sonar_test_reporter.tps b/source/reporters/ut_sonar_test_reporter.tps index 353edbf0d..ac3b16bd1 100644 --- a/source/reporters/ut_sonar_test_reporter.tps +++ b/source/reporters/ut_sonar_test_reporter.tps @@ -1,7 +1,7 @@ create or replace type ut_sonar_test_reporter under ut_output_reporter_base( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/reporters/ut_teamcity_reporter.tpb b/source/reporters/ut_teamcity_reporter.tpb index 086775254..e05dc994f 100644 --- a/source/reporters/ut_teamcity_reporter.tpb +++ b/source/reporters/ut_teamcity_reporter.tpb @@ -1,7 +1,7 @@ create or replace type body ut_teamcity_reporter is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -57,68 +57,96 @@ 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).get_error_stack_trace(), 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,a_test.disabled_reason)); 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; + 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.get_error_stack_trace(), '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) + ) + ); + for i in 1 .. a_test.failed_expectations.count loop + 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(i).description, + a_details => a_test.failed_expectations(i).message ) + ); 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)); 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 )); + for i in 1 .. a_test.failed_expectations.count loop + 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(i).description, + a_details => a_test.failed_expectations(i).message ) + ); + end loop; 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_teamcity_reporter.tps b/source/reporters/ut_teamcity_reporter.tps index 7f61e2b6e..e03fa3643 100644 --- a/source/reporters/ut_teamcity_reporter.tps +++ b/source/reporters/ut_teamcity_reporter.tps @@ -1,7 +1,7 @@ create or replace type ut_teamcity_reporter under ut_output_reporter_base( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/reporters/ut_teamcity_reporter_helper.pkb b/source/reporters/ut_teamcity_reporter_helper.pkb index f5167fbb8..1633d10aa 100644 --- a/source/reporters/ut_teamcity_reporter_helper.pkb +++ b/source/reporters/ut_teamcity_reporter_helper.pkb @@ -1,7 +1,7 @@ create or replace package body ut_teamcity_reporter_helper is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -73,8 +73,6 @@ create or replace package body ut_teamcity_reporter_helper is 'true' when false then 'false' - else - null end; l_props('flowId') := a_flow_id; return message('testStarted', l_props); @@ -89,10 +87,13 @@ create or replace package body ut_teamcity_reporter_helper is return message('testFinished', l_props); end; - function test_disabled(a_test_name varchar2, a_flow_id varchar2 default null) return varchar2 is + function test_disabled(a_test_name varchar2,a_msg varchar2 default null, a_flow_id varchar2 default null) return varchar2 is l_props t_props; begin l_props('name') := a_test_name; + if a_msg is not null then + l_props('message') := a_msg; + end if; l_props('flowId') := a_flow_id; return message('testIgnored', l_props); end; diff --git a/source/reporters/ut_teamcity_reporter_helper.pks b/source/reporters/ut_teamcity_reporter_helper.pks index 6bab87367..d7fa86cdc 100644 --- a/source/reporters/ut_teamcity_reporter_helper.pks +++ b/source/reporters/ut_teamcity_reporter_helper.pks @@ -1,7 +1,7 @@ create or replace package ut_teamcity_reporter_helper is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ create or replace package ut_teamcity_reporter_helper is function test_started(a_test_name varchar2, a_capture_standard_output boolean default null, a_flow_id varchar2 default null) return varchar2; function test_finished(a_test_name varchar2, a_test_duration_milisec number default null, a_flow_id varchar2 default null) return varchar2; - function test_disabled(a_test_name varchar2, a_flow_id varchar2 default null) return varchar2; + function test_disabled(a_test_name varchar2,a_msg varchar2 default null, a_flow_id varchar2 default null) return varchar2; function test_failed(a_test_name varchar2, a_msg in varchar2 default null, a_details varchar2 default null, a_flow_id varchar2 default null, a_actual varchar2 default null, a_expected varchar2 default null) return varchar2; function test_std_err(a_test_name varchar2, a_out in varchar2, a_flow_id in varchar2 default null) return varchar2; diff --git a/source/reporters/ut_tfs_junit_reporter.tpb b/source/reporters/ut_tfs_junit_reporter.tpb index d3edd1208..5e36aad17 100644 --- a/source/reporters/ut_tfs_junit_reporter.tpb +++ b/source/reporters/ut_tfs_junit_reporter.tpb @@ -1,7 +1,7 @@ create or replace type body ut_tfs_junit_reporter is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ create or replace type body ut_tfs_junit_reporter is constructor function ut_tfs_junit_reporter(self in out nocopy ut_tfs_junit_reporter) return self as result is begin - self.init($$plsql_unit); + self.init($$plsql_unit,ut_output_bulk_buffer()); return; end; @@ -29,9 +29,7 @@ create or replace type body ut_tfs_junit_reporter is member procedure junit_version_one(self in out nocopy ut_tfs_junit_reporter,a_run in ut_run) is l_suite_id integer := 0; - l_tests_count integer := a_run.results_count.disabled_count + a_run.results_count.success_count + - a_run.results_count.failure_count + a_run.results_count.errored_count; - + function get_common_suite_attributes(a_item ut_suite_item) return varchar2 is begin return ' errors="' ||a_item.results_count.errored_count || '"' || @@ -53,12 +51,12 @@ create or replace type body ut_tfs_junit_reporter is return regexp_substr(a_path_with_name, '(.*)\.' ||a_name||'$',subexpression=>1); end; - procedure print_test_results(a_test ut_test) is - l_lines ut_varchar2_list; - l_output clob; + function add_test_results(a_test ut_test) return ut_varchar2_rows is + l_results ut_varchar2_rows := ut_varchar2_rows(); begin - self.print_text(''); + /* According to specs : - A failure is a test which the code has explicitly failed by using the mechanisms for that purpose. @@ -68,83 +66,105 @@ 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.to_cdata( ut_utils.convert_collection( a_test.get_error_stack_traces() ) ) ); + ut_utils.append_to_list( l_results, ''); -- Do not count error as failure + elsif a_test.result = ut_utils.gc_disabled then + if a_test.disabled_reason is not null then + ut_utils.append_to_list( l_results, ''); + else + ut_utils.append_to_list( l_results, '' ); + end if; elsif a_test.result = ut_utils.gc_failure then - self.print_text(''); - 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))); - end loop; - self.print_text(dbms_xmlgen.convert(a_test.failed_expectations(i).caller_info)); - end loop; - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ut_utils.to_cdata( a_test.get_failed_expectation_lines() ) ); + ut_utils.append_to_list( l_results, ''); end if; - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + + return l_results; end; - procedure print_suite_results(a_suite ut_logical_suite, a_suite_id in out nocopy integer) is + procedure print_suite_results(a_suite ut_logical_suite, a_suite_id in out nocopy integer, a_nested_tests in out nocopy ut_varchar2_rows) 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; - begin - + l_tests ut_varchar2_list; + begin for i in 1 .. a_suite.items.count loop - if a_suite.items(i) is of(ut_logical_suite) then - print_suite_results(treat(a_suite.items(i) as ut_logical_suite), a_suite_id); + if a_suite.items(i) is of(ut_suite_context) then + print_suite_results(treat(a_suite.items(i) as ut_suite_context), a_suite_id, a_nested_tests); + elsif a_suite.items(i) is of(ut_suite) then + print_suite_results(treat(a_suite.items(i) as ut_suite), a_suite_id, a_nested_tests); + elsif a_suite.items(i) is of(ut_logical_suite) then + print_suite_results(treat(a_suite.items(i) as ut_logical_suite), a_suite_id, a_nested_tests); end if; end loop; - - if a_suite is of(ut_suite) then - a_suite_id := a_suite_id + 1; - self.print_text(''); - self.print_text(''); - for i in 1 .. a_suite.items.count loop - if a_suite.items(i) is of(ut_test) then - print_test_results(treat(a_suite.items(i) as ut_test)); - end if; - end loop; - 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(''); - else - self.print_text(''); + --Due to fact tha TFS and junit5 accepts only flat structure we have to report in suite level only. + if a_suite is of(ut_suite_context) then + for i in 1 .. a_suite.items.count loop + if a_suite.items(i) is of(ut_test) then + ut_utils.append_to_list( a_nested_tests,(add_test_results(treat(a_suite.items(i) as ut_test)))); + end if; + end loop; + elsif a_suite is of(ut_suite) then + for i in 1 .. a_suite.items.count loop + if a_suite.items(i) is of(ut_test) then + ut_utils.append_to_list( a_nested_tests,(add_test_results(treat(a_suite.items(i) as ut_test)))); + end if; + end loop; + --TFS doesnt report on empty test suites, however all we want to make sure is that we dont pring parents suites + -- showing test count but not tests. + if (a_nested_tests.count > 0 and l_tests_count > 0) or (a_nested_tests.count = 0 and l_tests_count = 0) then + a_suite_id := a_suite_id + 1; + ut_utils.append_to_list( l_results,''); + ut_utils.append_to_list( l_results,''); + ut_utils.append_to_list(l_results,a_nested_tests); + 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 + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ut_utils.to_cdata( l_suite.get_serveroutputs() ) ); + ut_utils.append_to_list( l_results, ''); + else + ut_utils.append_to_list( l_results, ''); + end if; + + l_errors := l_suite.get_error_stack_traces(); + if l_errors is not empty then + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ut_utils.to_cdata( ut_utils.convert_collection( l_errors ) ) ); + ut_utils.append_to_list( l_results, ''); + else + ut_utils.append_to_list( l_results, ''); + end if; + ut_utils.append_to_list( l_results, ''); + + self.print_text_lines(l_results); + --We have resolved a context and we now reset value. + a_nested_tests := ut_varchar2_rows(); 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(''); - else - self.print_text(''); - end if; - self.print_text(''); end if; - end; + end; + + procedure get_suite_results(a_suite ut_logical_suite, a_suite_id in out nocopy integer) is + l_nested_tests ut_varchar2_rows:= ut_varchar2_rows(); + begin + print_suite_results(a_suite, l_suite_id,l_nested_tests); + end; begin l_suite_id := 0; self.print_text(ut_utils.get_xml_header(a_run.client_character_set)); self.print_text(''); for i in 1 .. a_run.items.count loop - print_suite_results(treat(a_run.items(i) as ut_logical_suite), l_suite_id); + get_suite_results(treat(a_run.items(i) as ut_logical_suite), l_suite_id); end loop; self.print_text(''); end; diff --git a/source/reporters/ut_tfs_junit_reporter.tps b/source/reporters/ut_tfs_junit_reporter.tps index 9e7a90e0a..61cbc3fd8 100644 --- a/source/reporters/ut_tfs_junit_reporter.tps +++ b/source/reporters/ut_tfs_junit_reporter.tps @@ -1,7 +1,7 @@ create or replace type ut_tfs_junit_reporter under ut_output_reporter_base( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/reporters/ut_xunit_reporter.tpb b/source/reporters/ut_xunit_reporter.tpb index e2deb22ce..4612fb640 100644 --- a/source/reporters/ut_xunit_reporter.tpb +++ b/source/reporters/ut_xunit_reporter.tpb @@ -1,7 +1,7 @@ create or replace type body ut_xunit_reporter is /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ create or replace type body ut_xunit_reporter is constructor function ut_xunit_reporter(self in out nocopy ut_xunit_reporter) return self as result is begin - self.init($$plsql_unit); + self.init($$plsql_unit,ut_output_bulk_buffer()); return; end; diff --git a/source/reporters/ut_xunit_reporter.tps b/source/reporters/ut_xunit_reporter.tps index 81fa19e5b..6c530fee4 100644 --- a/source/reporters/ut_xunit_reporter.tps +++ b/source/reporters/ut_xunit_reporter.tps @@ -1,7 +1,7 @@ create or replace type ut_xunit_reporter under ut_junit_reporter( /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/set_install_params.sql b/source/set_install_params.sql new file mode 100644 index 000000000..34a23dc93 --- /dev/null +++ b/source/set_install_params.sql @@ -0,0 +1,34 @@ +/* + utPLSQL - Version 3 + Copyright 2016 - 2021 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. +*/ + +set echo off +set verify off +column 1 new_value 1 noprint; +column 2 new_value 2 noprint; +column 3 new_value 3 noprint; +select null as "1", null as "2" , null as "3" from dual where 1=0; +column sep new_value sep noprint +select '--------------------------------------------------------------' as sep from dual; + +column ut3_owner new_value ut3_owner noprint +column ut3_password new_value ut3_password noprint +column ut3_tablespace new_value ut3_tablespace noprint + +select coalesce('&&1','UT3') ut3_owner, + coalesce('&&2','XNtxj8eEgA6X6b6f') ut3_password, + coalesce('&&3','users') ut3_tablespace + from dual; diff --git a/source/uninstall.sql b/source/uninstall.sql index 7b927e91d..ced7b8dc4 100644 --- a/source/uninstall.sql +++ b/source/uninstall.sql @@ -1,6 +1,6 @@ /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/uninstall_all.sql b/source/uninstall_all.sql index 8d2bf0222..cfaaaa29f 100644 --- a/source/uninstall_all.sql +++ b/source/uninstall_all.sql @@ -1,6 +1,6 @@ /* utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project + Copyright 2016 - 2021 utPLSQL Project Licensed under the Apache License, Version 2.0 (the "License"): you may not use this file except in compliance with the License. diff --git a/source/uninstall_coverage_tables.sql b/source/uninstall_coverage_tables.sql index 8de75b51e..890aa7090 100644 --- a/source/uninstall_coverage_tables.sql +++ b/source/uninstall_coverage_tables.sql @@ -11,7 +11,7 @@ begin and owner = sys_context( 'USERENV', 'CURRENT_SCHEMA' ) ) loop - execute immediate 'drop table '||to_be_dopped.table_name||' cascade constraints'; + execute immediate 'drop table '||to_be_dopped.table_name||' cascade constraints purge'; dbms_output.put_line('Table '||to_be_dopped.table_name||' dropped'); end loop; end; diff --git a/source/uninstall_objects.sql b/source/uninstall_objects.sql index cf8b3905f..dde9a824f 100644 --- a/source/uninstall_objects.sql +++ b/source/uninstall_objects.sql @@ -1,10 +1,36 @@ +set echo off +declare + procedure drop_if_exists(a_object_type varchar2, a_object_name varchar2) is + l_count integer; + begin + select count(1) + into l_count + from all_objects + where owner = sys_context('USERENV','CURRENT_SCHEMA') + and object_type = a_object_type + and object_name = a_object_name; + if l_count > 0 then + execute immediate 'drop '||a_object_type||' '||a_object_name; + dbms_output.put_line(initcap(a_object_type)||' '||a_object_name||' dropped.'); + else + dbms_output.put_line(initcap(a_object_type)||' '||a_object_name||' was not dropped, '||lower(a_object_type)||' does not exist.'); + end if; + end; +begin + drop_if_exists('TRIGGER', 'UT_TRIGGER_ANNOTATION_PARSING'); + drop_if_exists('SYNONYM','UT3_TRIGGER_ALIVE'); +end; +/ set echo on + drop synonym be_between; drop synonym have_count; drop synonym match; +drop synonym contain; + drop synonym be_false; drop synonym be_empty; @@ -27,6 +53,10 @@ drop synonym be_true; drop synonym equal; +drop synonym be_within; + +drop synonym be_within_pct; + drop type ut_coveralls_reporter force; drop type ut_coverage_sonar_reporter force; @@ -39,28 +69,56 @@ drop type ut_coverage_html_reporter force; drop type ut_sonar_test_reporter force; +drop type ut_realtime_reporter force; + drop package ut_coverage; drop package ut_coverage_helper; -drop view ut_coverage_sources_tmp; +drop table ut_coverage_sources_tmp purge; -drop table ut_coverage_sources_tmp$; +drop table ut_coverage_runs purge; 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 type ut_path_items force; + +drop type ut_path_item force; + drop package ut_suite_manager; drop package ut_suite_builder; +drop package ut_suite_tag_filter; + +drop package ut_suite_cache_manager; + +drop table ut_suite_cache purge; + +drop type ut_suite_cache_rows force; + +drop type ut_suite_cache_row force; + +drop sequence ut_suite_cache_seq; + +drop table ut_suite_cache_package purge; + +drop table ut_suite_cache_schema purge; + drop package ut; -drop table ut_dbms_output_cache; +drop table ut_dbms_output_cache purge; drop type ut_expectation_compound force; +drop type ut_expectation_json force; + drop type ut_expectation force; drop package ut_expectation_processor; @@ -69,6 +127,8 @@ drop type ut_match force; drop type ut_be_between force; +drop type ut_contain force; + drop type ut_equal force; drop type ut_be_true force; @@ -91,10 +151,20 @@ drop type ut_be_less_than force; drop type ut_be_false force; +drop type ut_be_within_pct force; + +drop type ut_be_within force; + +drop package ut_be_within_helper; + drop type ut_comparison_matcher force; drop type ut_matcher force; +drop type ut_expectation_base force; + +drop type ut_matcher_base force; + drop type ut_data_value_yminterval force; drop type ut_data_value_varchar2 force; @@ -109,6 +179,8 @@ drop type ut_data_value_number force; drop type ut_data_value_refcursor force; +drop type ut_data_value_json force; + drop type ut_data_value_dsinterval force; drop type ut_data_value_date force; @@ -119,19 +191,33 @@ drop type ut_data_value_boolean force; drop type ut_data_value_blob force; -drop type ut_data_value_object force; - -drop type ut_data_value_collection force; - drop type ut_data_value_anydata force; drop type ut_data_value_xmltype force; drop type ut_data_value force; -drop table ut_compound_data_tmp; +drop type ut_matcher_options force; + +drop type ut_matcher_options_items force; + +drop type ut_json_tree_details force; + +drop type ut_json_leaf_tab force; + +drop type ut_json_leaf; + +drop type ut_cursor_details force; + +drop type ut_cursor_column_tab force; + +drop type ut_cursor_column force; -drop table ut_compound_data_diff_tmp; +drop table ut_compound_data_tmp purge; + +drop table ut_compound_data_diff_tmp purge; + +drop table ut_json_data_diff_tmp purge; drop package ut_annotation_manager; @@ -139,9 +225,11 @@ drop package ut_annotation_parser; drop package ut_annotation_cache_manager; -drop table ut_annotation_cache cascade constraints; +drop table ut_annotation_cache cascade constraints purge; -drop table ut_annotation_cache_info cascade constraints; +drop table ut_annotation_cache_info cascade constraints purge; + +drop table ut_annotation_cache_schema cascade constraints purge; drop sequence ut_annotation_cache_seq; @@ -157,16 +245,38 @@ drop type ut_annotations force; drop type ut_annotation force; +drop package ut_trigger_check; + drop package ut_file_mapper; drop package ut_metadata; drop package ut_ansiconsole_helper; +begin + null; + $if dbms_db_version.version < 21 $then + begin execute immediate 'drop type json force'; exception when others then null; end; + $end + $if dbms_db_version.version = 12 and dbms_db_version.release = 1 or dbms_db_version.version < 12 $then + begin execute immediate 'drop type json_element_t force'; exception when others then null; end; + begin execute immediate 'drop type json_object_t force'; exception when others then null; end; + begin execute immediate 'drop type json_array_t force'; exception when others then null; end; + begin execute immediate 'drop type json_key_list force'; exception when others then null; end; + $end +end; +/ + drop package ut_utils; +drop type ut_stack force; + +drop sequence ut_savepoint_seq; + drop type ut_documentation_reporter force; +drop type ut_debug_reporter force; + drop type ut_teamcity_reporter force; drop type ut_xunit_reporter force; @@ -215,20 +325,34 @@ drop type ut_suite_item force; drop type ut_output_table_buffer force; +drop type ut_output_clob_table_buffer force; + +drop type ut_output_bulk_buffer force; + drop type ut_output_buffer_base force; -drop view ut_output_buffer_tmp; +drop table ut_output_buffer_tmp purge; + +drop sequence ut_output_buffer_tmp_seq; + +drop table ut_output_clob_buffer_tmp purge; -drop table ut_output_buffer_tmp$ purge; +drop sequence ut_output_clob_buffer_tmp_seq; -drop view ut_output_buffer_info_tmp; +drop table ut_output_buffer_info_tmp purge; -drop table ut_output_buffer_info_tmp$; +drop package ut_session_context; -drop sequence ut_message_id_seq; +drop type ut_session_info force; + +drop type ut_output_data_rows force; + +drop type ut_output_data_row force; drop type ut_results_counter force; +drop type ut_run_info force; + drop type ut_expectation_results force; drop type ut_expectation_result force; @@ -237,6 +361,10 @@ drop package ut_event_manager; drop type ut_event_item force; +drop type ut_reporters_info force; + +drop type ut_reporter_info force; + drop type ut_key_anyval_pair force; drop type ut_key_anyval_pairs force; @@ -245,6 +373,8 @@ drop type ut_key_value_pairs force; drop type ut_key_value_pair force; +drop type ut_key_anyvalues force; + drop type ut_object_names force; drop type ut_object_name force; @@ -259,8 +389,6 @@ drop package ut_coverage_profiler; drop package ut_compound_data_helper; -drop package ut_curr_usr_compound_helper; - drop package ut_coverage_helper_profiler; drop type ut_have_count; diff --git a/source/uninstall_synonyms.sql b/source/uninstall_synonyms.sql index 569e5057d..2c96c03a4 100644 --- a/source/uninstall_synonyms.sql +++ b/source/uninstall_synonyms.sql @@ -15,10 +15,10 @@ begin and not exists (select 1 from all_objects o where o.owner = s.table_owner and o.object_name = s.table_name) ) loop - i := i + 1; begin execute immediate 'drop '||syn.syn_name; dbms_output.put_line('Dropped '||syn.syn_name||' for object '||syn.for_object); + i := i + 1; exception when others then dbms_output.put_line('FAILED to drop '||syn.syn_name||' for object '||syn.for_object); diff --git a/test/api/test_ut_run.pkb b/test/api/test_ut_run.pkb deleted file mode 100644 index 704627ac9..000000000 --- a/test/api/test_ut_run.pkb +++ /dev/null @@ -1,724 +0,0 @@ -create or replace package body test_ut_run is - - --%test(ut.version() returns version of the framework) - procedure ut_version is - begin - ut.expect(ut3.ut.version()).to_match('^v\d+\.\d+\.\d+\.\d+(-\w+)?$'); - end; - - --%test(ut.fail() marks test as failed) - procedure ut_fail is - begin - --Act - ut3.ut.fail('Testing failure message'); - --Assert - ut.expect( - xmltype(anydata.convertCollection(ut3.ut_expectation_processor.get_failed_expectations())).getClobVal() - ).to_be_like('%2%Testing failure message%'); - --Cleanup - ut3.ut_expectation_processor.clear_expectations(); - end; - - - function get_dbms_output_as_clob return clob is - l_status number; - l_line varchar2(32767); - l_result clob; - begin - - dbms_output.get_line(line => l_line, status => l_status); - if l_status != 1 then - dbms_lob.createtemporary(l_result, true, dur => dbms_lob.session); - end if; - while l_status != 1 loop - if l_line is not null then - ut3.ut_utils.append_to_clob(l_result, l_line||chr(10)); - end if; - dbms_output.get_line(line => l_line, status => l_status); - end loop; - return l_result; - end; - - procedure create_ut3$user#_tests is - pragma autonomous_transaction; - begin - execute immediate q'[create or replace package ut3$user#.test_package_1 is - --%suite - --%suitepath(tests) - - --%test(Test1 from test package 1) - procedure test1; - - --%test(Test2 from test package 1) - procedure test2; - - procedure run(a_reporter ut3.ut_reporter_base := null); - procedure run(a_test_files ut3.ut_varchar2_list, a_reporter ut3.ut_reporter_base); - procedure run(a_path varchar2, a_reporter ut3.ut_reporter_base := null); - procedure run(a_path varchar2, a_test_files ut3.ut_varchar2_list, a_reporter ut3.ut_reporter_base); - procedure run(a_paths ut3.ut_varchar2_list, a_reporter ut3.ut_reporter_base := null); - procedure run(a_paths ut3.ut_varchar2_list, a_test_files ut3.ut_varchar2_list, a_reporter ut3.ut_reporter_base); - function run(a_reporter ut3.ut_reporter_base := null) return ut3.ut_varchar2_list; - function run(a_test_files ut3.ut_varchar2_list, a_reporter ut3.ut_reporter_base) return ut3.ut_varchar2_list; - function run(a_path varchar2, a_reporter ut3.ut_reporter_base := null) return ut3.ut_varchar2_list; - function run(a_path varchar2, a_test_files ut3.ut_varchar2_list, a_reporter ut3.ut_reporter_base) return ut3.ut_varchar2_list; - function run(a_paths ut3.ut_varchar2_list, a_reporter ut3.ut_reporter_base := null) return ut3.ut_varchar2_list; - function run(a_paths ut3.ut_varchar2_list, a_test_files ut3.ut_varchar2_list, a_reporter ut3.ut_reporter_base) return ut3.ut_varchar2_list; - - end test_package_1; - ]'; - execute immediate q'[create or replace package body ut3$user#.test_package_1 is - procedure test1 is - begin - dbms_output.put_line('test_package_1.test1 executed'); - end; - procedure test2 is - begin - dbms_output.put_line('test_package_1.test2 executed'); - end; - - procedure run(a_reporter ut3.ut_reporter_base := null) is - begin - ut3.ut.run(a_reporter); - end; - procedure run(a_test_files ut3.ut_varchar2_list, a_reporter ut3.ut_reporter_base) is - begin - ut3.ut.run( - a_reporter, a_source_files => ut3.ut_varchar2_list(), - a_test_files => a_test_files - ); - end; - procedure run(a_path varchar2, a_reporter ut3.ut_reporter_base := null) is - begin - ut3.ut.run(a_path, a_reporter); - end; - procedure run(a_path varchar2, a_test_files ut3.ut_varchar2_list, a_reporter ut3.ut_reporter_base) is - begin - ut3.ut.run( - a_path, - a_reporter, a_source_files => ut3.ut_varchar2_list(), - a_test_files => a_test_files - ); - end; - procedure run(a_paths ut3.ut_varchar2_list, a_reporter ut3.ut_reporter_base := null) is - begin - ut3.ut.run(a_paths, a_reporter); - end; - procedure run(a_paths ut3.ut_varchar2_list, a_test_files ut3.ut_varchar2_list, a_reporter ut3.ut_reporter_base) is - begin - ut3.ut.run( - a_paths, - a_reporter, a_source_files => ut3.ut_varchar2_list(), - a_test_files => a_test_files - ); - end; - - function run(a_reporter ut3.ut_reporter_base := null) return ut3.ut_varchar2_list is - l_results ut3.ut_varchar2_list; - begin - select * bulk collect into l_results from table (ut3.ut.run(a_reporter)); - return l_results; - end; - function run(a_test_files ut3.ut_varchar2_list, a_reporter ut3.ut_reporter_base) return ut3.ut_varchar2_list is - l_results ut3.ut_varchar2_list; - begin - select * bulk collect into l_results from table ( - ut3.ut.run( - a_reporter, a_source_files => ut3.ut_varchar2_list(), - a_test_files => a_test_files - )); - return l_results; - end; - function run(a_path varchar2, a_reporter ut3.ut_reporter_base := null) return ut3.ut_varchar2_list is - l_results ut3.ut_varchar2_list; - begin - select * bulk collect into l_results from table (ut3.ut.run(a_path, a_reporter)); - return l_results; - end; - function run(a_path varchar2, a_test_files ut3.ut_varchar2_list, a_reporter ut3.ut_reporter_base) return ut3.ut_varchar2_list is - l_results ut3.ut_varchar2_list; - begin - select * bulk collect into l_results from table ( - ut3.ut.run( - a_path, - a_reporter, a_source_files => ut3.ut_varchar2_list(), - a_test_files => a_test_files - )); - return l_results; - end; - function run(a_paths ut3.ut_varchar2_list, a_reporter ut3.ut_reporter_base := null) return ut3.ut_varchar2_list is - l_results ut3.ut_varchar2_list; - begin - select * bulk collect into l_results from table (ut3.ut.run(a_paths, a_reporter)); - return l_results; - end; - function run(a_paths ut3.ut_varchar2_list, a_test_files ut3.ut_varchar2_list, a_reporter ut3.ut_reporter_base) return ut3.ut_varchar2_list is - l_results ut3.ut_varchar2_list; - begin - select * bulk collect into l_results from table ( - ut3.ut.run( - a_paths, - a_reporter, a_source_files => ut3.ut_varchar2_list(), - a_test_files => a_test_files - )); - return l_results; - end; - end test_package_1; - ]'; - - execute immediate q'[create or replace package ut3$user#.test_package_2 is - --%suite - --%suitepath(tests.test_package_1) - - --%test - procedure test1; - - --%test - procedure test2; - - end test_package_2; - ]'; - execute immediate q'[create or replace package body ut3$user#.test_package_2 is - procedure test1 is - begin - dbms_output.put_line('test_package_2.test1 executed'); - end; - procedure test2 is - begin - dbms_output.put_line('test_package_2.test2 executed'); - end; - end test_package_2; - ]'; - - execute immediate q'[create or replace package ut3$user#.test_package_3 is - --%suite - --%suitepath(tests2) - - --%test - procedure test1; - - --%test - procedure test2; - - end test_package_3; - ]'; - execute immediate q'[create or replace package body ut3$user#.test_package_3 is - procedure test1 is - begin - dbms_output.put_line('test_package_3.test1 executed'); - end; - procedure test2 is - begin - dbms_output.put_line('test_package_3.test2 executed'); - end; - end test_package_3; - ]'; - end; - - procedure drop_ut3$user#_tests is - pragma autonomous_transaction; - begin - execute immediate q'[drop package ut3$user#.test_package_1]'; - execute immediate q'[drop package ut3$user#.test_package_2]'; - execute immediate q'[drop package ut3$user#.test_package_3]'; - end; - - procedure run_proc_no_params is - l_results clob; - begin - execute immediate 'begin ut3$user#.test_package_1.run(); end;'; - l_results := get_dbms_output_as_clob(); - --Assert - ut.expect( l_results ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); - end; - - procedure run_proc_specific_reporter is - l_results clob; - begin - --Act - execute immediate 'begin ut3$user#.test_package_1.run(:a_reporter); end;' - using in ut3.ut_documentation_reporter(); - l_results := get_dbms_output_as_clob(); - --Assert - ut.expect( l_results ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); - end; - - procedure run_proc_cov_file_list is - l_results clob; - begin - --Act - execute immediate 'begin ut3$user#.test_package_1.run(a_test_files=>:a_test_files, a_reporter=>:a_reporter); end;' - using - in ut3.ut_varchar2_list('tests/ut3$user#.test_package_1.pkb','tests/ut3$user#.test_package_2.pkb','tests/ut3$user#.test_package_3.pkb'), - in ut3.ut_sonar_test_reporter(); - l_results := get_dbms_output_as_clob(); - --Assert - ut.expect( l_results ).to_be_like( '%tests/ut3$user#.test_package_2.pkb%tests/ut3$user#.test_package_1.pkb%tests/ut3$user#.test_package_3.pkb%' ); - end; - - procedure run_proc_pkg_name is - l_results clob; - begin - execute immediate 'begin ut3$user#.test_package_1.run(:a_path); end;' - using in 'test_package_1'; - l_results := get_dbms_output_as_clob(); - --Assert - ut.expect( l_results ).to_be_like( '%test_package_1%' ); - ut.expect( l_results ).not_to_be_like( '%test_package_2%' ); - ut.expect( l_results ).not_to_be_like( '%test_package_3%' ); - end; - - procedure run_proc_pkg_name_file_list is - l_results clob; - begin - execute immediate 'begin ut3$user#.test_package_1.run(:a_path, :a_test_files, :a_reporter); end;' - using - in 'test_package_3', - in ut3.ut_varchar2_list('tests/ut3$user#.test_package_1.pkb','tests/ut3$user#.test_package_2.pkb','tests/ut3$user#.test_package_3.pkb'), - in ut3.ut_sonar_test_reporter(); - l_results := get_dbms_output_as_clob(); - --Assert - ut.expect( l_results ).to_be_like( '%tests/ut3$user#.test_package_3.pkb%' ); - ut.expect( l_results ).not_to_be_like( '%tests/ut3$user#.test_package_1.pkb%' ); - ut.expect( l_results ).not_to_be_like( '%tests/ut3$user#.test_package_2.pkb%' ); - end; - - procedure run_proc_path_list is - l_results clob; - begin - execute immediate 'begin ut3$user#.test_package_1.run(:a_paths); end;' - using in ut3.ut_varchar2_list(':tests.test_package_1',':tests'); - l_results := get_dbms_output_as_clob(); - --Assert - ut.expect( l_results ).to_be_like( '%test_package_1%' ); - ut.expect( l_results ).to_be_like( '%test_package_2%' ); - ut.expect( l_results ).not_to_be_like( '%test_package_3%' ); - end; - - procedure run_proc_path_list_file_list is - l_results clob; - begin - execute immediate 'begin ut3$user#.test_package_1.run(:a_paths, :a_test_files, :a_reporter); end;' - using - in ut3.ut_varchar2_list(':tests.test_package_1',':tests'), - in ut3.ut_varchar2_list('tests/ut3$user#.test_package_1.pkb','tests/ut3$user#.test_package_2.pkb','tests/ut3$user#.test_package_3.pkb'), - in ut3.ut_sonar_test_reporter(); - l_results := get_dbms_output_as_clob(); - --Assert - ut.expect( l_results ).to_be_like( '%tests/ut3$user#.test_package_1.pkb%' ); - ut.expect( l_results ).to_be_like( '%tests/ut3$user#.test_package_2.pkb%' ); - ut.expect( l_results ).not_to_be_like( '%tests/ut3$user#.test_package_3.pkb%' ); - end; - - procedure run_proc_null_reporter is - l_results clob; - begin - --Act - execute immediate 'begin ut3$user#.test_package_1.run(:a_reporter); end;' - using in cast(null as ut3.ut_reporter_base); - l_results := get_dbms_output_as_clob(); - --Assert - ut.expect( l_results ).to_be_like( '%tests%test_package_1%test_package_2%tests2%test_package_3%' ); - end; - - procedure run_proc_null_path is - l_results clob; - begin - --Act - execute immediate 'begin ut3$user#.test_package_1.run(:a_path); end;' - using in cast(null as varchar2); - l_results := get_dbms_output_as_clob(); - --Assert - ut.expect( l_results ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); - end; - - procedure run_proc_null_path_list is - l_results clob; - l_paths ut3.ut_varchar2_list; - begin - --Act - execute immediate 'begin ut3$user#.test_package_1.run(:a_paths); end;' - using in l_paths; - l_results := get_dbms_output_as_clob(); - --Assert - ut.expect( l_results ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); - end; - - procedure run_proc_empty_path_list is - l_results clob; - begin - --Act - execute immediate 'begin ut3$user#.test_package_1.run(:a_paths); end;' - using in ut3.ut_varchar2_list(); - l_results := get_dbms_output_as_clob(); - --Assert - ut.expect( l_results ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); - end; - - procedure run_func_no_params is - l_results ut3.ut_varchar2_list; - begin - execute immediate 'begin :l_results := ut3$user#.test_package_1.run(); end;' using out l_results; - --Assert - ut.expect( ut3.ut_utils.table_to_clob(l_results) ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); - end; - - procedure run_func_specific_reporter is - l_results ut3.ut_varchar2_list; - begin - --Act - execute immediate 'begin :l_results := ut3$user#.test_package_1.run(:a_reporter); end;' - using out l_results, in ut3.ut_documentation_reporter(); - --Assert - ut.expect( ut3.ut_utils.table_to_clob(l_results) ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); - end; - - procedure run_func_cov_file_list is - l_results ut3.ut_varchar2_list; - begin - --Act - execute immediate 'begin :l_results := ut3$user#.test_package_1.run(a_test_files=>:a_test_files, a_reporter=>:a_reporter); end;' - using out l_results, - in ut3.ut_varchar2_list('tests/ut3$user#.test_package_1.pkb','tests/ut3$user#.test_package_2.pkb','tests/ut3$user#.test_package_3.pkb'), - in ut3.ut_sonar_test_reporter(); - --Assert - ut.expect( ut3.ut_utils.table_to_clob(l_results) ).to_be_like( '%tests/ut3$user#.test_package_2.pkb%tests/ut3$user#.test_package_1.pkb%tests/ut3$user#.test_package_3.pkb%' ); - end; - - procedure run_func_pkg_name is - l_results ut3.ut_varchar2_list; - begin - 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) ).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; - - procedure run_func_pkg_name_file_list is - l_results ut3.ut_varchar2_list; - begin - execute immediate 'begin :l_results := ut3$user#.test_package_1.run(:a_path, :a_test_files, :a_reporter); end;' - using out l_results, - in 'test_package_3', - in ut3.ut_varchar2_list('tests/ut3$user#.test_package_1.pkb','tests/ut3$user#.test_package_2.pkb','tests/ut3$user#.test_package_3.pkb'), - in ut3.ut_sonar_test_reporter(); - --Assert - ut.expect( ut3.ut_utils.table_to_clob(l_results) ).to_be_like( '%tests/ut3$user#.test_package_3.pkb%' ); - ut.expect( ut3.ut_utils.table_to_clob(l_results) ).not_to_be_like( '%tests/ut3$user#.test_package_1.pkb%' ); - ut.expect( ut3.ut_utils.table_to_clob(l_results) ).not_to_be_like( '%tests/ut3$user#.test_package_2.pkb%' ); - end; - - procedure run_func_path_list is - l_results ut3.ut_varchar2_list; - begin - execute immediate 'begin :l_results := ut3$user#.test_package_1.run(:a_paths); end;' - using out l_results, in ut3.ut_varchar2_list(':tests.test_package_1',':tests'); - --Assert - 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) ).to_be_like( '%test_package_2%' ); - ut.expect( ut3.ut_utils.table_to_clob(l_results) ).not_to_be_like( '%test_package_3%' ); - end; - - procedure run_func_path_list_file_list is - l_results ut3.ut_varchar2_list; - begin - execute immediate 'begin :l_results := ut3$user#.test_package_1.run(:a_paths, :a_test_files, :a_reporter); end;' - using out l_results, - in ut3.ut_varchar2_list(':tests.test_package_1',':tests'), - in ut3.ut_varchar2_list('tests/ut3$user#.test_package_1.pkb','tests/ut3$user#.test_package_2.pkb','tests/ut3$user#.test_package_3.pkb'), - in ut3.ut_sonar_test_reporter(); - --Assert - ut.expect( ut3.ut_utils.table_to_clob(l_results) ).to_be_like( '%tests/ut3$user#.test_package_1.pkb%' ); - ut.expect( ut3.ut_utils.table_to_clob(l_results) ).to_be_like( '%tests/ut3$user#.test_package_2.pkb%' ); - ut.expect( ut3.ut_utils.table_to_clob(l_results) ).not_to_be_like( '%tests/ut3$user#.test_package_3.pkb%' ); - end; - - procedure run_func_null_reporter is - l_results ut3.ut_varchar2_list; - begin - --Act - execute immediate 'begin :l_results := ut3$user#.test_package_1.run(:a_reporter); end;' - using out l_results, in cast(null as ut3.ut_reporter_base); - --Assert - ut.expect( ut3.ut_utils.table_to_clob(l_results) ).to_be_like( '%tests%test_package_1%test_package_2%tests2%test_package_3%' ); - end; - - procedure run_func_null_path is - l_results ut3.ut_varchar2_list; - begin - --Act - execute immediate 'begin :l_results := ut3$user#.test_package_1.run(:a_path); end;' - using out l_results, in cast(null as varchar2); - --Assert - ut.expect( ut3.ut_utils.table_to_clob(l_results) ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); - end; - - procedure run_func_null_path_list is - l_results ut3.ut_varchar2_list; - l_paths ut3.ut_varchar2_list; - begin - --Act - execute immediate 'begin :l_results := ut3$user#.test_package_1.run(:a_paths); end;' - using out l_results, in l_paths; - --Assert - ut.expect( ut3.ut_utils.table_to_clob(l_results) ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); - end; - - procedure run_func_empty_path_list is - l_results ut3.ut_varchar2_list; - begin - --Act - execute immediate 'begin :l_results := ut3$user#.test_package_1.run(:a_paths); end;' - using out l_results, in ut3.ut_varchar2_list(); - --Assert - ut.expect( ut3.ut_utils.table_to_clob(l_results) ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); - end; - - procedure run_func_cov_file_lst_null_rep is - l_results ut3.ut_varchar2_list; - begin - --Act - execute immediate 'begin :l_results := ut3$user#.test_package_1.run(a_test_files=>:a_test_files, a_reporter=>:a_reporter); end;' - using out l_results, - in ut3.ut_varchar2_list('tests/ut3$user#.test_package_1.pkb','tests/ut3$user#.test_package_2.pkb','tests/ut3$user#.test_package_3.pkb'), - in cast(null as ut3.ut_reporter_base); - --Assert - ut.expect( ut3.ut_utils.table_to_clob(l_results) ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); - end; - - procedure run_func_empty_suite is - l_results ut3.ut_varchar2_list; - l_expected varchar2(32767); - pragma autonomous_transaction; - begin - --Arrange - execute immediate q'[create or replace package empty_suite as - -- %suite - - procedure not_a_test; - end;]'; - execute immediate q'[create or replace package body empty_suite as - procedure not_a_test is begin null; end; - end;]'; - l_expected := '%empty_suite%0 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'; - --Act - select * bulk collect into l_results from table(ut3.ut.run('empty_suite')); - - --Assert - ut.expect( ut3.ut_utils.table_to_clob(l_results) ).to_be_like( l_expected ); - - --Cleanup - execute immediate q'[drop package empty_suite]'; - end; - - procedure create_test_suite is - l_service_name varchar2(100); - pragma autonomous_transaction; - begin - select global_name into l_service_name from global_name; - execute immediate - 'create public database link db_loopback connect to ut3_tester identified by ut3 - using ''(DESCRIPTION= - (ADDRESS=(PROTOCOL=TCP) - (HOST='||sys_context('userenv','SERVER_HOST')||') - (PORT=1521) - ) - (CONNECT_DATA=(SERVICE_NAME='||l_service_name||')))'''; - execute immediate q'[ - create or replace package stateful_package as - function get_state return varchar2; - end; - ]'; - execute immediate q'[ - create or replace package body stateful_package as - g_state varchar2(1) := 'A'; - function get_state return varchar2 is begin return g_state; end; - end; - ]'; - execute immediate q'[ - create or replace package test_stateful as - --%suite - --%suitepath(test_state) - - --%test - --%beforetest(acquire_state_via_db_link,rebuild_stateful_package) - procedure failing_stateful_test; - - procedure rebuild_stateful_package; - procedure acquire_state_via_db_link; - - end; - ]'; - execute immediate q'{ - create or replace package body test_stateful as - - procedure failing_stateful_test is - begin - ut3.ut.expect(stateful_package.get_state@db_loopback).to_equal('abc'); - end; - - procedure rebuild_stateful_package is - pragma autonomous_transaction; - begin - execute immediate q'[ - create or replace package body stateful_package as - g_state varchar2(3) := 'abc'; - function get_state return varchar2 is begin return g_state; end; - end; - ]'; - end; - - procedure acquire_state_via_db_link is - begin - dbms_output.put_line('stateful_package.get_state@db_loopback='||stateful_package.get_state@db_loopback); - end; - end; - }'; - - end; - - procedure raise_in_invalid_state is - l_results ut3.ut_varchar2_list; - l_expected varchar2(32767); - begin - --Arrange - l_expected := 'test_state - test_stateful - failing_stateful_test [% sec] (FAILED - 1)% -Failures:% - 1) failing_stateful_test - ORA-04068: existing state of packages (DB_LOOPBACK) has been discarded - ORA-04061: existing state of package body "UT3_TESTER.STATEFUL_PACKAGE" has been invalidated - ORA-04065: not executed, altered or dropped package body "UT3_TESTER.STATEFUL_PACKAGE"% - ORA-06512: at line 6% -1 tests, 0 failed, 1 errored, 0 disabled, 0 warning(s)%'; - - --Act - select * bulk collect into l_results from table(ut3.ut.run('test_stateful')); - - --Assert - ut.expect( ut3.ut_utils.table_to_clob(l_results) ).to_be_like( l_expected ); - ut.fail('Expected exception but nothing was raised'); - exception - when others then - ut.expect( ut3.ut_utils.table_to_clob(l_results) ).to_be_like( l_expected ); - ut.expect(sqlcode).to_equal(-4068); - end; - - procedure drop_test_suite is - pragma autonomous_transaction; - begin - execute immediate 'drop package stateful_package'; - execute immediate 'drop package test_stateful'; - begin execute immediate 'drop public database link db_loopback'; exception when others then null; end; - end; - - procedure run_in_invalid_state is - l_results ut3.ut_varchar2_list; - l_actual clob; - l_expected varchar2(32767); - begin - select * bulk collect into l_results from table(ut3.ut.run('failing_invalid_spec')); - - l_actual := ut3.ut_utils.table_to_clob(l_results); - ut.expect(l_actual).to_be_like('%Call params for % are not valid: package does not exist or is invalid: %FAILING_INVALID_SPEC%'); - - end; - - procedure compile_invalid_package is - ex_compilation_error exception; - pragma exception_init(ex_compilation_error,-24344); - pragma autonomous_transaction; - begin - begin - execute immediate q'[ - create or replace package failing_invalid_spec as - --%suite - gv_glob_val non_existing_table.id%type := 0; - - --%test - procedure test1; - end;]'; - exception when ex_compilation_error then null; - end; - begin - execute immediate q'[ - create or replace package body failing_invalid_spec as - procedure test1 is begin ut.expect(1).to_equal(1); end; - end;]'; - exception when ex_compilation_error then null; - end; - end; - procedure drop_invalid_package is - pragma autonomous_transaction; - begin - execute immediate 'drop package failing_invalid_spec'; - end; - - procedure run_and_revalidate_specs is - l_results ut3.ut_varchar2_list; - l_actual clob; - l_is_invalid number; - begin - execute immediate q'[select count(1) from all_objects o where o.owner = :object_owner and o.object_type = 'PACKAGE' - and o.status = 'INVALID' and o.object_name= :object_name]' into l_is_invalid - using user,'INVALID_PCKAG_THAT_REVALIDATES'; - - select * bulk collect into l_results from table(ut3.ut.run('invalid_pckag_that_revalidates')); - - l_actual := ut3.ut_utils.table_to_clob(l_results); - ut.expect(1).to_equal(l_is_invalid); - ut.expect(l_actual).to_be_like('%invalid_pckag_that_revalidates%invalidspecs [% sec]% -%Finished in % seconds% -%1 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'); - - end; - - procedure generate_invalid_spec is - ex_compilation_error exception; - pragma exception_init(ex_compilation_error,-24344); - pragma autonomous_transaction; - begin - - execute immediate q'[ - create or replace package parent_specs as - c_test constant varchar2(1) := 'Y'; - end;]'; - - execute immediate q'[ - create or replace package invalid_pckag_that_revalidates as - --%suite - g_var varchar2(1) := parent_specs.c_test; - - --%test(invalidspecs) - procedure test1; - end;]'; - - execute immediate q'[ - create or replace package body invalid_pckag_that_revalidates as - procedure test1 is begin ut.expect('Y').to_equal(g_var); end; - end;]'; - - -- That should invalidate test package and we can then revers - execute immediate q'[ - create or replace package parent_specs as - c_test_error constant varchar2(1) := 'Y'; - end;]'; - - execute immediate q'[ - create or replace package parent_specs as - c_test constant varchar2(1) := 'Y'; - end;]'; - - end; - procedure drop_invalid_spec is - pragma autonomous_transaction; - begin - execute immediate 'drop package invalid_pckag_that_revalidates'; - execute immediate 'drop package parent_specs'; - end; - -end; -/ diff --git a/test/api/test_ut_run.pks b/test/api/test_ut_run.pks deleted file mode 100644 index cfc06c80d..000000000 --- a/test/api/test_ut_run.pks +++ /dev/null @@ -1,107 +0,0 @@ -create or replace package test_ut_run is - --%suite(ut.run) - --%suitepath(utplsql.api) - - - --%test(ut.version() returns version of the framework) - procedure ut_version; - - --%test(ut.fail() marks test as failed) - procedure ut_fail; - - procedure create_ut3$user#_tests; - procedure drop_ut3$user#_tests; - - --%context(ut_run_procedure) - --%displayname(ut.run() procedure options) - --%beforeall(create_ut3$user#_tests) - --%afterall(drop_ut3$user#_tests) - - --%test(Runs all tests in current schema with default reporter when no parameters given) - procedure run_proc_no_params; - --%test(Runs all tests in current schema with specified reporter) - procedure run_proc_specific_reporter; - --%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) - procedure run_proc_pkg_name_file_list; - --%test(Runs tests from given paths only with paths list) - procedure run_proc_path_list; - --%test(Runs tests from given paths only with paths list and coverage file list) - procedure run_proc_path_list_file_list; - --%test(Runs all tests in current schema using default reporter when null reporter given) - procedure run_proc_null_reporter; - --%test(Runs all tests in current schema with null path provided) - procedure run_proc_null_path; - --%test(Runs all tests in current schema with null path list given) - procedure run_proc_null_path_list; - --%test(Runs all tests in current schema with empty path list given) - procedure run_proc_empty_path_list; - - --%endcontext - - - --%context(ut_run_function) - --%displayname(ut.run() function options) - --%beforeall(create_ut3$user#_tests) - --%afterall(drop_ut3$user#_tests) - - --%test(Runs all tests in current schema with default reporter when no parameters given) - procedure run_func_no_params; - --%test(Runs all tests in current schema with specified reporter) - procedure run_func_specific_reporter; - --%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) - procedure run_func_pkg_name_file_list; - --%test(Runs tests from given paths with paths list) - procedure run_func_path_list; - --%test(Runs tests from given paths with paths list and coverage file list) - procedure run_func_path_list_file_list; - --%test(Runs all tests in current schema using default reporter when null reporter given) - procedure run_func_null_reporter; - --%test(Runs all tests in current schema with null path provided) - procedure run_func_null_path; - --%test(Runs all tests in current schema with null path list given) - procedure run_func_null_path_list; - --%test(Runs all tests in current schema with empty path list given) - procedure run_func_empty_path_list; - --%test(Runs all tests in current schema with coverage file list and default reporter) - procedure run_func_cov_file_lst_null_rep; - --%test(Executes successfully an empty suite) - procedure run_func_empty_suite; - - --disabled(Makes session wait for lock on 18.1 due to library cache pin wait) - --%test(ut.run - raises after completing all tests if a test fails with ORA-04068 or ORA-04061) - --%beforetest(create_test_suite) - --%aftertest(drop_test_suite) - procedure raise_in_invalid_state; - procedure create_test_suite; - procedure drop_test_suite; - - --%test(ut.run - Does not execute suite when specified package is not valid) - --%beforetest(compile_invalid_package) - --%aftertest(drop_invalid_package) - procedure run_in_invalid_state; - procedure compile_invalid_package; - procedure drop_invalid_package; - - --%test(Invalidate package specs via rebuild but still execute package) - --%beforetest(generate_invalid_spec) - --%aftertest(drop_invalid_spec) - procedure run_and_revalidate_specs; - procedure generate_invalid_spec; - procedure drop_invalid_spec; - - --%endcontext - -end; -/ diff --git a/test/api/test_ut_runner.pkb b/test/api/test_ut_runner.pkb deleted file mode 100644 index 3a8f6f670..000000000 --- a/test/api/test_ut_runner.pkb +++ /dev/null @@ -1,535 +0,0 @@ -create or replace package body test_ut_runner is - - procedure setup_cache_objects is - pragma autonomous_transaction; - begin - execute immediate q'[create or replace package dummy_test_package as - --%suite(dummy_test_suite) - --%rollback(manual) - - --%test(dummy_test) - --%beforetest(some_procedure) - procedure some_dummy_test_procedure; - end;]'; - execute immediate q'[create or replace procedure dummy_test_procedure as - --%some_annotation(some_text) - --%rollback(manual) - begin - null; - end;]'; - execute immediate q'[create or replace procedure ut3.dummy_test_procedure as - --%some_annotation(some_text) - --%rollback(manual) - begin - null; - end;]'; - end; - - procedure setup_cache is - pragma autonomous_transaction; - begin - setup_cache_objects(); - ut3.ut_annotation_manager.rebuild_annotation_cache(user,'PACKAGE'); - ut3.ut_annotation_manager.rebuild_annotation_cache(user,'PROCEDURE'); - ut3.ut_annotation_manager.rebuild_annotation_cache('UT3','PROCEDURE'); - end; - - procedure cleanup_cache is - pragma autonomous_transaction; - begin - delete from ut3.ut_annotation_cache_info - where object_type = 'PROCEDURE' and object_owner in ('UT3',user) - or object_type = 'PACKAGE' and object_owner = user and object_name = 'DUMMY_TEST_PACKAGE'; - execute immediate q'[drop package dummy_test_package]'; - execute immediate q'[drop procedure dummy_test_procedure]'; - execute immediate q'[drop procedure ut3.dummy_test_procedure]'; - end; - - procedure create_test_spec - as - pragma autonomous_transaction; - begin - execute immediate q'[create or replace package test_cache as - --%suite - - --%test - procedure failing_test; -end; -]'; - end; - - procedure create_test_body(a_number integer) - as - pragma autonomous_transaction; - begin - execute immediate 'create or replace package body test_cache as - procedure failing_test is - begin - ut3.ut.expect('||a_number||').to_be_null; - end; -end;'; - end; - - procedure drop_test_package - as - pragma autonomous_transaction; - begin - execute immediate 'drop package test_cache'; - end; - - - - procedure keep_an_open_transaction is - l_expected varchar2(300); - l_output_data dbms_output.chararr; - l_num_lines integer := 100000; - begin - --Arrange - create_test_spec(); - create_test_body(0); - l_expected := dbms_transaction.local_transaction_id(true); - --Act - ut3.ut.run('test_cache'); - dbms_output.get_lines( l_output_data, l_num_lines); - --Assert - ut.expect(dbms_transaction.local_transaction_id()).to_equal(l_expected); - drop_test_package(); - end; - - procedure close_newly_opened_transaction is - l_output_data dbms_output.chararr; - l_num_lines integer := 100000; - begin - --Arrange - create_test_spec(); - create_test_body(0); - rollback; - --Act - ut3.ut.run('test_cache'); - dbms_output.get_lines( l_output_data, l_num_lines); - --Assert - ut.expect(dbms_transaction.local_transaction_id()).to_be_null(); - drop_test_package(); - end; - - procedure version_comp_check_compare is - begin - ut.expect( ut3.ut_runner.version_compatibility_check('v3.0.0.0','v3.0.0.0') ).to_equal(1); - ut.expect( ut3.ut_runner.version_compatibility_check('v3.0.0.0','v3.0.123.0') ).to_equal(1); - ut.expect( ut3.ut_runner.version_compatibility_check('v3.0.0.0','v3.123.0.0') ).to_equal(1); - ut.expect( ut3.ut_runner.version_compatibility_check('v3.0.0.0','v3.13.31.0') ).to_equal(1); - ut.expect( ut3.ut_runner.version_compatibility_check('v3.0.1.0','v3.0.0.0') ).to_equal(0); - ut.expect( ut3.ut_runner.version_compatibility_check('v3.1.0.0','v3.0.0.0') ).to_equal(0); - ut.expect( ut3.ut_runner.version_compatibility_check('v3.0.0.0','v2.0.0.0') ).to_equal(0); - ut.expect( ut3.ut_runner.version_compatibility_check('v3.0.0.0','v4.0.0.0') ).to_equal(0); - end; - - procedure version_comp_check_ignore is - begin - ut.expect( ut3.ut_runner.version_compatibility_check('v3.0.0.123','v3.0.0.0') ).to_equal(1); - ut.expect( ut3.ut_runner.version_compatibility_check('v3.0.0.0','v3.0.0.123') ).to_equal(1); - ut.expect( ut3.ut_runner.version_compatibility_check('v3.0.0','v3.0.0.0') ).to_equal(1); - end; - - procedure version_comp_check_short is - begin - ut.expect( ut3.ut_runner.version_compatibility_check('v3.0.0','v3.0.0.0') ).to_equal(1); - ut.expect( ut3.ut_runner.version_compatibility_check('v3.0','v3.0.123.0') ).to_equal(1); - ut.expect( ut3.ut_runner.version_compatibility_check('v3','v3.123.0.0') ).to_equal(1); - end; - - procedure version_comp_check_exception is - procedure throws(a_requested varchar2, a_current varchar2) is - l_compatible integer; - begin - l_compatible := ut3.ut_runner.version_compatibility_check(a_requested,a_current); - ut.fail('Expected exception but nothing was raised'); - exception - when others then - ut.expect(sqlcode).to_equal(-20214); - end; - begin - throws('bad_ver','v3.0.0.0'); - throws('v3.0.0.0','bad_ver'); - end; - - procedure run_reset_package_body_cache is - l_results ut3.ut_varchar2_list; - l_expected clob; - l_actual clob; - begin - --Arrange - create_test_spec(); - create_test_body(0); - select * - bulk collect into l_results - from table(ut3.ut.run('test_cache')); - - --Act - create_test_body(1); - select * - bulk collect into l_results - from table(ut3.ut.run('test_cache')); - --Assert - l_actual := ut3.ut_utils.table_to_clob(l_results); - l_expected := '%ut3.ut.expect(1).to_be_null;%'; - ut.expect(l_actual).to_be_like(l_expected); - drop_test_package(); - end; - - procedure run_keep_dbms_output_buffer is - l_expected dbmsoutput_linesarray; - l_actual dbmsoutput_linesarray; - l_results ut3.ut_varchar2_list; - l_lines number := 10000; - begin - --Arrange - create_test_spec(); - create_test_body(0); - - l_expected := dbmsoutput_linesarray( - 'A text placed into DBMS_OUTPUT', - 'Another line', - lpad('A very long line',10000,'a') - ); - for i in 1 .. 300 loop - l_expected.extend; - l_expected(l_expected.last) := 'line '||i; - end loop; - - for i in 1 .. l_expected.count loop - dbms_output.put_line(l_expected(i)); - end loop; - - --Act - select * - bulk collect into l_results - from table(ut3.ut.run('test_cache')); - - --Assert - dbms_output.get_lines(lines => l_actual, numlines => l_lines); - for i in 1 .. l_lines loop - ut.expect(l_actual(i)).to_equal(l_expected(i)); - end loop; - drop_test_package(); - end; - - procedure test_purge_cache_schema_type is - l_actual sys_refcursor; - begin - - open l_actual for - select * from ut3.ut_annotation_cache_info - where object_owner = user and object_type = 'PROCEDURE'; - ut.expect(l_actual).not_to_be_empty(); - - --Act - ut3.ut_runner.purge_cache(user,'PROCEDURE'); - - --Assert - open l_actual for - select * from ut3.ut_annotation_cache_info - where object_owner = user and object_type = 'PROCEDURE'; - --Cache purged for object owner/type - ut.expect(l_actual).to_be_empty(); - open l_actual for - select * from ut3.ut_annotation_cache_info - where object_owner = user and object_type = 'PACKAGE'; - --Cache not purged for other types - ut.expect(l_actual).not_to_be_empty(); - open l_actual for - select * from ut3.ut_annotation_cache_info - where object_owner = 'UT3' and object_type = 'PROCEDURE'; - --Cache not purged for other owners - ut.expect(l_actual).not_to_be_empty(); - - end; - - procedure test_rebuild_cache_schema_type is - l_actual integer; - begin - --Act - ut3.ut_annotation_manager.rebuild_annotation_cache(user,'PACKAGE'); - --Assert - select count(1) into l_actual - from ut3.ut_annotation_cache_info i - join ut3.ut_annotation_cache c on c.cache_id = i.cache_id - where object_owner = user and object_type = 'PACKAGE' and object_name = 'DUMMY_TEST_PACKAGE'; - --Rebuild cache for user/packages - ut.expect(l_actual).to_equal(4); - - select count(1) into l_actual - from ut3.ut_annotation_cache_info i - join ut3.ut_annotation_cache c on c.cache_id = i.cache_id - where object_owner = 'UT3' and object_type = 'PROCEDURE'; - - --Did not rebuild cache for ut3/procedures - ut.expect(l_actual).to_equal(0); - end; - - procedure test_get_unit_test_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 - 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; - --Act - open l_actual for select * from table(ut3.ut_runner.get_unit_test_info('UT3_TESTER','DUMMY_TEST_PACKAGE')); - --Assert - ut.expect(l_actual).to_equal(l_expected); - end; - - procedure test_get_reporters_list is - l_expected sys_refcursor; - l_actual sys_refcursor; - begin - --Arrange - open l_expected for - select 'UT3.UT_COVERAGE_COBERTURA_REPORTER' reporter_object_name, 'Y' is_output_reporter from dual union all - select 'UT3.UT_COVERAGE_HTML_REPORTER', 'Y' from dual union all - select 'UT3.UT_COVERAGE_SONAR_REPORTER', 'Y' from dual union all - select 'UT3.UT_COVERALLS_REPORTER', 'Y' from dual union all - select 'UT3.UT_DOCUMENTATION_REPORTER', 'Y' from dual union all - select 'UT3.UT_JUNIT_REPORTER', 'Y' from dual union all - select 'UT3.UT_SONAR_TEST_REPORTER', 'Y' from dual union all - select 'UT3.UT_TEAMCITY_REPORTER', 'Y' from dual union all - select 'UT3.UT_TFS_JUNIT_REPORTER', 'Y' from dual union all - select 'UT3.UT_XUNIT_REPORTER', 'Y' from dual; - --Act - open l_actual for select * from table(ut3.ut_runner.GET_REPORTERS_LIST()) order by 1; - --Assert - ut.expect(l_actual).to_equal(l_expected); - end; - - procedure db_link_cleanup is - begin - begin execute immediate 'drop public database link db_loopback'; exception when others then null; end; - begin execute immediate 'drop package test_db_link'; exception when others then null; end; - end; - - procedure db_link_setup is - l_service_name varchar2(100); - begin - select global_name into l_service_name from global_name; - execute immediate - 'create public database link db_loopback connect to ut3_tester identified by ut3 - using ''(DESCRIPTION= - (ADDRESS=(PROTOCOL=TCP) - (HOST='||sys_context('userenv','SERVER_HOST')||') - (PORT=1521) - ) - (CONNECT_DATA=(SERVICE_NAME='||l_service_name||')))'''; - execute immediate q'[ - create or replace package test_db_link is - --%suite - - --%test - procedure runs_with_db_link; - end;]'; - - execute immediate q'[ - create or replace package body test_db_link is - procedure runs_with_db_link is - a_value integer; - begin - select 1 into a_value - from dual@db_loopback; - ut3.ut.expect(a_value).to_be_null(); - end; - end;]'; - - end; - - procedure raises_20213_on_fail_link is - l_reporter ut3.ut_documentation_reporter := ut3.ut_documentation_reporter(); - l_lines ut3.ut_varchar2_list; - begin - --Arrange - --Act - ut3.ut_runner.run(ut3.ut_varchar2_list('test_db_link'), ut3.ut_reporters(l_reporter), a_fail_on_errors=> true); - ut.fail('Expected exception but nothing was raised'); - exception - when others then - --Assert - ut.expect(sqlcode).to_equal(-20213); - ut.expect(dbms_utility.format_error_stack||dbms_utility.format_error_backtrace).not_to_be_like('%ORA-02055%'); - end; - - procedure create_test_csl_packages is - pragma autonomous_transaction; - begin - execute immediate q'[ - create or replace package test_csl_names1 as - --%suite - --%suitepath(test_csl_names) - - --%test - procedure one_is_one; - - --%test - procedure two_is_two; - - end; - ]'; - - execute immediate q'{ - create or replace package body test_csl_names1 as - - procedure one_is_one is - begin - ut3.ut.expect(1).to_equal(1); - end; - - procedure two_is_two is - begin - ut3.ut.expect(2).to_equal(2); - end; - - end; - }'; - - execute immediate q'[ - create or replace package test_csl_names2 as - --%suite - --%suitepath(test_csl_names) - - --%test - procedure one_is_one; - - --%test - procedure two_is_two; - - end; - ]'; - - execute immediate q'{ - create or replace package body test_csl_names2 as - - procedure one_is_one is - begin - ut3.ut.expect(1).to_equal(1); - end; - - procedure two_is_two is - begin - ut3.ut.expect(2).to_equal(2); - end; - - end; - }'; - - end; - - procedure drop_test_csl_packages is - pragma autonomous_transaction; - begin - execute immediate 'drop package test_csl_names1'; - execute immediate 'drop package test_csl_names2'; - end; - - procedure pass_varchar2_name_list is - l_results ut3.ut_varchar2_list; - l_actual clob; - begin - select * - bulk collect into l_results - from table(ut3.ut.run(ut3.ut_varchar2_list('test_csl_names1','test_csl_names2'))); - - l_actual := ut3.ut_utils.table_to_clob(l_results); - ut.expect(l_actual).to_be_like('%Finished in % seconds -%4 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'); - end; - - procedure pass_varchar2_name is - l_results ut3.ut_varchar2_list; - l_actual clob; - begin - select * - bulk collect into l_results - from table(ut3.ut.run('test_csl_names1')); - - l_actual := ut3.ut_utils.table_to_clob(l_results); - ut.expect(l_actual).to_be_like('%Finished in % seconds -%2 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'); - end; - - procedure pass_varchar2_suite_csl is - l_results ut3.ut_varchar2_list; - l_actual clob; - begin - select * - bulk collect into l_results - from table(ut3.ut.run('test_csl_names1,test_csl_names2')); - - l_actual := ut3.ut_utils.table_to_clob(l_results); - ut.expect(l_actual).to_be_like('%Finished in % seconds -%4 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'); - end; - - procedure pass_varchar2_test_csl is - l_results ut3.ut_varchar2_list; - l_actual clob; - begin - select * - bulk collect into l_results - from table(ut3.ut.run('test_csl_names1.one_is_one,test_csl_names2.one_is_one')); - - l_actual := ut3.ut_utils.table_to_clob(l_results); - ut.expect(l_actual).to_be_like('%Finished in % seconds -%2 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'); - end; - - procedure pass_varch_test_csl_spc is - l_results ut3.ut_varchar2_list; - l_actual clob; - begin - select * - bulk collect into l_results - from table(ut3.ut.run('test_csl_names1.one_is_one, test_csl_names2.one_is_one')); - - l_actual := ut3.ut_utils.table_to_clob(l_results); - ut.expect(l_actual).to_be_like('%Finished in % seconds -%2 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'); - end; - - procedure pass_csl_with_srcfile is - l_results ut3.ut_varchar2_list; - l_actual clob; - begin - - select * - bulk collect into l_results - from table( - ut3.ut.run( - a_path => 'test_csl_names1.one_is_one,test_csl_names2.one_is_one', - a_source_files => ut3.ut_varchar2_list('ut3.ut'), - a_test_files => ut3.ut_varchar2_list('ut3_tester.test_csl_names2') - ) - ); - - l_actual := ut3.ut_utils.table_to_clob(l_results); - ut.expect(l_actual).to_be_like('%Finished in % seconds -%2 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'); - end; - - procedure pass_csl_within_var2list is - l_results ut3.ut_varchar2_list; - l_actual clob; - begin - select * - bulk collect into l_results - from table(ut3.ut.run(ut3.ut_varchar2_list('test_csl_names1.one_is_one,test_csl_names2.one_is_one'))); - - l_actual := ut3.ut_utils.table_to_clob(l_results); - ut.expect(l_actual).to_be_like('%Finished in % seconds -%2 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'); - end; - -end; -/ diff --git a/test/common_helper/utplsql.pkb b/test/common_helper/utplsql.pkb new file mode 100644 index 000000000..c752caa41 --- /dev/null +++ b/test/common_helper/utplsql.pkb @@ -0,0 +1,11 @@ +create or replace package body utplsql is + + procedure global_setup is + begin + --we need to have dbms_output enable for our tests + --TODO - move this to utPLSQL-cli once cli has support for it. + dbms_output.enable(null); + end; + +end; +/ diff --git a/test/common_helper/utplsql.pks b/test/common_helper/utplsql.pks new file mode 100644 index 000000000..51adbb117 --- /dev/null +++ b/test/common_helper/utplsql.pks @@ -0,0 +1,9 @@ +create or replace package utplsql is + + --%suite + + --%beforeall + procedure global_setup; + +end; +/ diff --git a/test/core.pkb b/test/core.pkb deleted file mode 100644 index 7ace9f7ce..000000000 --- a/test/core.pkb +++ /dev/null @@ -1,73 +0,0 @@ -create or replace package body core is - - procedure global_setup is - begin - ut3.ut_coverage.set_develop_mode(true); - --improve performance of test execution by disabling all compiler optimizations - execute_autonomous('ALTER SESSION SET PLSQL_OPTIMIZE_LEVEL=0'); - - execute_autonomous( - q'[create or replace package ut_transaction_control as - function count_rows(a_val varchar2) return number; - procedure setup; - procedure test; - procedure test_failure; - end;]' - ); - execute_autonomous( - q'[create or replace package body ut_transaction_control - as - - function count_rows(a_val varchar2) return number is - l_cnt number; - begin - select count(*) into l_cnt from ut$test_table t where t.val = a_val; - return l_cnt; - end; - procedure setup is begin - insert into ut$test_table values ('s'); - end; - procedure test is - begin - insert into ut$test_table values ('t'); - end; - procedure test_failure is - begin - insert into ut$test_table values ('t'); - --raise no_data_found; - raise_application_error(-20001,'Error'); - end; - end;]' - ); - end; - - procedure global_cleanup is - begin - execute_autonomous('drop package ut_transaction_control'); - end; - - procedure execute_autonomous(a_sql varchar2) is - pragma autonomous_transaction; - begin - if a_sql is not null then - execute immediate a_sql; - end if; - commit; - end; - - function run_test(a_path varchar2) return clob is - l_lines ut3.ut_varchar2_list; - begin - select * bulk collect into l_lines from table(ut3.ut.run(a_path)); - return ut3.ut_utils.table_to_clob(l_lines); - end; - - function get_value(a_variable varchar2) return integer is - l_glob_val integer; - begin - execute immediate 'begin :l_glob_val := '||a_variable||'; end;' using out l_glob_val; - return l_glob_val; - end; - -end; -/ diff --git a/test/core.pks b/test/core.pks deleted file mode 100644 index 92285c4bf..000000000 --- a/test/core.pks +++ /dev/null @@ -1,21 +0,0 @@ -create or replace package core is - - --%suite - --%suitepath(utplsql) - - --%beforeall - procedure global_setup; - - --%afterall - procedure global_cleanup; - - procedure execute_autonomous(a_sql varchar2); - - function run_test(a_path varchar2) return clob; - - function get_value(a_variable varchar2) return integer; - - - -end; -/ diff --git a/test/core/annotations/test_annot_throws_exception.pkb b/test/core/annotations/test_annot_throws_exception.pkb deleted file mode 100644 index 2c8c3be2c..000000000 --- a/test/core/annotations/test_annot_throws_exception.pkb +++ /dev/null @@ -1,375 +0,0 @@ -create or replace package body test_annot_throws_exception -is - g_tests_results clob; - - procedure recollect_tests_results is - pragma autonomous_transaction; - - l_package_spec varchar2(32737); - l_package_body varchar2(32737); - l_exception_spec varchar2(32737); - l_test_results ut3.ut_varchar2_list; - begin - l_exception_spec := q'[ - create or replace package exc_pkg is - c_e_single_exc constant number := -20200; - c_e_dummy constant varchar2(10) := 'dummy'; - c_e_varch_exc constant varchar2(10) := '-20201'; - c_e_list_1 number := -20202; - c_e_list_2 constant number := -20203; - c_e_diff_exc constant number := -20204; - c_e_mix_list constant number := -20205; - c_e_mix_missin constant number := -20206; - - e_some_exception exception; - pragma exception_init(e_some_exception, -20207); - - end;]'; - - l_package_spec := ' - create package annotated_package_with_throws is - --%suite(Dummy package to test annotation throws) - - --%test(Throws same annotated exception) - --%throws(-20145) - procedure raised_same_exception; - - --%test(Throws one of the listed exceptions) - --%throws(-20145,-20146, -20189 ,-20563) - procedure raised_one_listed_exception; - - --%test(Leading zero is ignored in exception list) - --%throws(-01476) - procedure leading_0_exception_no; - - --%test(Throws diff exception) - --%throws(-20144) - procedure raised_diff_exception; - - --%test(Throws empty) - --%throws() - procedure empty_throws; - - --%test(Ignores annotation and fails when exception was thrown) - --%throws(hello,784#,0-=234,,u1234) - procedure bad_paramters_with_except; - - --%test(Ignores annotation and succeeds when no exception thrown) - --%throws(hello,784#,0-=234,,u1234) - procedure bad_paramters_without_except; - - --%test(Detects a valid exception number within many invalid ones) - --%throws(7894562, operaqk, -=1, -1, pow74d, posdfk3) - procedure one_valid_exception_number; - - --%test(Gives failure when a exception is expected and nothing is thrown) - --%throws(-20459, -20136, -20145) - procedure nothing_thrown; - - --%test(Single exception defined as a constant number in package) - --%throws(exc_pkg.c_e_single_exc) - procedure single_exc_const_pkg; - - --%test(Gives success when one of annotated exception using constant is thrown) - --%throws(exc_pkg.c_e_list_1,exc_pkg.c_e_list_2) - procedure list_of_exc_constant; - - --%test(Gives failure when the raised exception is different that the annotated one using variable) - --%throws(exc_pkg.c_e_diff_exc) - procedure fail_not_match_exc; - - --%test(Success when one of exception from mixed list of number and constant is thrown) - --%throws(exc_pkg.c_e_mix_list,-20105) - procedure mixed_exc_list; - - --%test(Success when match exception even if other variable on list dont exists) - --%throws(exc_pkg.c_e_mix_missin,utter_rubbish) - procedure mixed_list_notexi; - - --%test(Success resolve and match named exception defined in pragma exception init) - --%throws(exc_pkg.e_some_exception) - procedure named_exc_pragma; - - --%test(Success resolve and match oracle named exception) - --%throws(NO_DATA_FOUND) - procedure named_exc_ora; - - --%test(Success resolve and match oracle named exception dup val index) - --%throws(DUP_VAL_ON_INDEX) - procedure named_exc_ora_dup_ind; - - --%test(Success map no data 100 to -1403) - --%throws(-1403) - procedure nodata_exc_ora; - - --%test(Success for exception defined as varchar) - --%throws(exc_pkg.c_e_varch_exc) - procedure defined_varchar_exc; - - --%test(Non existing constant exception) - --%throws(dummy.c_dummy); - procedure non_existing_const; - - --%test(Bad exception constant) - --%throws(exc_pkg.c_e_dummy); - procedure bad_exc_const; - - end; - '; - - l_package_body := ' - create package body annotated_package_with_throws is - procedure raised_same_exception is - begin - raise_application_error(-20145, ''Test error''); - end; - - procedure raised_one_listed_exception is - begin - raise_application_error(-20189, ''Test error''); - end; - - procedure leading_0_exception_no is - x integer; - begin - x := 1 / 0; - end; - - procedure raised_diff_exception is - begin - raise_application_error(-20143, ''Test error''); - end; - - procedure empty_throws is - begin - raise_application_error(-20143, ''Test error''); - end; - - procedure bad_paramters_with_except is - begin - raise_application_error(-20143, ''Test error''); - end; - - procedure bad_paramters_without_except is - begin - null; - end; - - procedure one_valid_exception_number is - begin - raise dup_val_on_index; - end; - - procedure nothing_thrown is - begin - null; - end; - - procedure single_exc_const_pkg is - begin - raise_application_error(exc_pkg.c_e_single_exc,''Test''); - end; - - procedure list_of_exc_constant is - begin - raise_application_error(exc_pkg.c_e_list_1,''Test''); - end; - - procedure fail_not_match_exc is - begin - raise NO_DATA_FOUND; - end; - - procedure mixed_exc_list is - begin - raise_application_error(exc_pkg.c_e_mix_list,''Test''); - end; - - procedure mixed_list_notexi is - begin - raise_application_error(exc_pkg.c_e_mix_missin,''Test''); - end; - - procedure named_exc_pragma is - begin - raise exc_pkg.e_some_exception; - end; - - procedure named_exc_ora is - begin - raise NO_DATA_FOUND; - end; - - procedure named_exc_ora_dup_ind is - begin - raise DUP_VAL_ON_INDEX; - end; - - procedure nodata_exc_ora is - begin - raise NO_DATA_FOUND; - end; - - procedure defined_varchar_exc is - begin - raise_application_error(exc_pkg.c_e_varch_exc,''Test''); - end; - - procedure non_existing_const is - begin - raise_application_error(-20143, ''Test error''); - end; - - procedure bad_exc_const is - begin - raise_application_error(-20143, ''Test error''); - end; - - end; - '; - - execute immediate l_exception_spec; - execute immediate l_package_spec; - execute immediate l_package_body; - - - select * bulk collect into l_test_results from table(ut3.ut.run(('annotated_package_with_throws'))); - - g_tests_results := ut3.ut_utils.table_to_clob(l_test_results); - end; - - procedure throws_same_annotated_except is - begin - ut.expect(g_tests_results).to_match('^\s*Throws same annotated exception \[[\.0-9]+ sec\]\s*$','m'); - ut.expect(g_tests_results).not_to_match('raised_same_exception'); - end; - - procedure throws_one_of_annotated_excpt is - begin - ut.expect(g_tests_results).to_match('^\s*Throws one of the listed exceptions \[[\.0-9]+ sec\]\s*$','m'); - ut.expect(g_tests_results).not_to_match('raised_one_listed_exception'); - end; - - procedure throws_with_leading_zero is - begin - ut.expect(g_tests_results).to_match('^\s*Leading zero is ignored in exception list \[[\.0-9]+ sec\]\s*$','m'); - ut.expect(g_tests_results).not_to_match('leading_0_exception_no'); - end; - - procedure throws_diff_annotated_except is - begin - ut.expect(g_tests_results).to_match('^\s*Throws diff exception \[[\.0-9]+ sec\] \(FAILED - [0-9]+\)\s*$','m'); - ut.expect(g_tests_results).to_match('raised_diff_exception\s+Actual: -20143 was expected to equal: -20144\s+ORA-20143: Test error\s+ORA-06512: at "UT3_TESTER.ANNOTATED_PACKAGE_WITH_THROWS"'); - end; - - procedure throws_empty is - begin - ut.expect(g_tests_results).to_match('^\s*Throws empty \[[\.0-9]+ sec\] \(FAILED - [0-9]+\)\s*$','m'); - ut.expect(g_tests_results).to_match('empty_throws\s*ORA-20143: Test error\s*ORA-06512: at "UT3_TESTER.ANNOTATED_PACKAGE_WITH_THROWS"'); - end; - - procedure bad_paramters_with_except is - begin - ut.expect(g_tests_results).to_match('^\s*Ignores annotation and fails when exception was thrown \[[\.0-9]+ sec\] \(FAILED - [0-9]+\)\s*$','m'); - ut.expect(g_tests_results).to_match('bad_paramters_with_except\s*ORA-20143: Test error\s*ORA-06512: at "UT3_TESTER.ANNOTATED_PACKAGE_WITH_THROWS"'); - end; - - procedure bad_paramters_without_except is - begin - ut.expect(g_tests_results).to_match('^\s*Ignores annotation and succeeds when no exception thrown \[[\.0-9]+ sec\]\s*$','m'); - ut.expect(g_tests_results).not_to_match('bad_paramters_without_except'); - end; - - procedure one_valid_exception_number is - begin - ut.expect(g_tests_results).to_match('^\s*Detects a valid exception number within many invalid ones \[[\.0-9]+ sec\]\s*$','m'); - ut.expect(g_tests_results).not_to_match('one_valid_exception_number'); - end; - - procedure nothing_thrown is - begin - ut.expect(g_tests_results).to_match('^\s*Gives failure when a exception is expected and nothing is thrown \[[\.0-9]+ sec\] \(FAILED - [0-9]+\)\s*$','m'); - ut.expect(g_tests_results).to_match('nothing_thrown\s*Expected one of exceptions \(-20459, -20136, -20145\) but nothing was raised.'); - end; - - procedure single_exc_const_pkg is - begin - ut.expect(g_tests_results).to_match('^\s*Single exception defined as a constant number in package \[[\.0-9]+ sec\]\s*$','m'); - ut.expect(g_tests_results).not_to_match('single_exc_const_pkg'); - end; - - procedure list_of_exc_constant is - begin - ut.expect(g_tests_results).to_match('^\s*Gives success when one of annotated exception using constant is thrown \[[\.0-9]+ sec\]\s*$','m'); - ut.expect(g_tests_results).not_to_match('list_of_exc_constant'); - end; - - procedure fail_not_match_exc is - begin - ut.expect(g_tests_results).to_match('^\s*Gives failure when the raised exception is different that the annotated one using variable \[[\.0-9]+ sec\] \(FAILED - [0-9]+\)\s*$','m'); - ut.expect(g_tests_results).to_match('fail_not_match_exc\s+Actual: -1403 was expected to equal: -20204\s+ORA-01403: no data found\s+ORA-06512: at "UT3_TESTER.ANNOTATED_PACKAGE_WITH_THROWS"'); - end; - - procedure mixed_exc_list is - begin - ut.expect(g_tests_results).to_match('^\s*Success when one of exception from mixed list of number and constant is thrown \[[\.0-9]+ sec\]\s*$','m'); - ut.expect(g_tests_results).not_to_match('mixed_exc_list'); - end; - - procedure mixed_list_notexi is - begin - ut.expect(g_tests_results).to_match('^\s*Success when match exception even if other variable on list dont exists \[[\.0-9]+ sec\]\s*$','m'); - ut.expect(g_tests_results).not_to_match('mixed_list_notexi'); - end; - - procedure named_exc_pragma is - begin - ut.expect(g_tests_results).to_match('^\s*Success resolve and match named exception defined in pragma exception init \[[\.0-9]+ sec\]\s*$','m'); - ut.expect(g_tests_results).not_to_match('mixed_list_notexi'); - end; - - procedure named_exc_ora is - begin - ut.expect(g_tests_results).to_match('^\s*Success resolve and match oracle named exception \[[\.0-9]+ sec\]\s*$','m'); - ut.expect(g_tests_results).not_to_match('named_exc_ora'); - end; - - procedure named_exc_ora_dup_ind is - begin - ut.expect(g_tests_results).to_match('^\s*Success resolve and match oracle named exception dup val index \[[\.0-9]+ sec\]\s*$','m'); - ut.expect(g_tests_results).not_to_match('named_exc_ora_dup_ind'); - end; - - procedure nodata_exc_ora is - begin - ut.expect(g_tests_results).to_match('^\s*Success map no data 100 to -1403 \[[\.0-9]+ sec\]\s*$','m'); - ut.expect(g_tests_results).not_to_match('nodata_exc_ora'); - end; - - procedure defined_varchar_exc is - begin - ut.expect(g_tests_results).to_match('^\s*Success for exception defined as varchar \[[\.0-9]+ sec\]\s*$','m'); - ut.expect(g_tests_results).not_to_match('defined_varchar_exc'); - end; - - procedure non_existing_const is - begin - ut.expect(g_tests_results).to_match('^\s*Non existing constant exception \[[\.0-9]+ sec\] \(FAILED - [0-9]+\)\s*$','m'); - ut.expect(g_tests_results).to_match('non_existing_const\s*ORA-20143: Test error\s*ORA-06512: at "UT3_TESTER.ANNOTATED_PACKAGE_WITH_THROWS"'); - end; - - procedure bad_exc_const is - begin - ut.expect(g_tests_results).to_match('^\s*Bad exception constant \[[\.0-9]+ sec\] \(FAILED - [0-9]+\)\s*$','m'); - ut.expect(g_tests_results).to_match('bad_exc_const\s*ORA-20143: Test error\s*ORA-06512: at "UT3_TESTER.ANNOTATED_PACKAGE_WITH_THROWS"'); - end; - - procedure drop_test_package is - pragma autonomous_transaction; - begin - execute immediate 'drop package annotated_package_with_throws'; - execute immediate 'drop package exc_pkg'; - end; - -end; -/ diff --git a/test/core/annotations/test_annotation_manager.pkb b/test/core/annotations/test_annotation_manager.pkb deleted file mode 100644 index 98bea7452..000000000 --- a/test/core/annotations/test_annotation_manager.pkb +++ /dev/null @@ -1,256 +0,0 @@ -create or replace package body test_annotation_manager is - - procedure create_dummy_package is - pragma autonomous_transaction; - begin - execute immediate q'[create or replace package dummy_package as - procedure some_dummy_procedure; - end;]'; - end; - - procedure drop_dummy_package is - pragma autonomous_transaction; - begin - execute immediate q'[drop package dummy_package]'; - end; - - procedure recompile_dummy_package is - pragma autonomous_transaction; - begin - execute immediate q'[alter package dummy_package compile]'; - end; - - procedure create_dummy_test_package is - pragma autonomous_transaction; - begin - execute immediate q'[create or replace package dummy_test_package as - --%suite(dummy_test_suite) - --%rollback(manual) - - --%test(dummy_test) - --%beforetest(some_procedure) - procedure some_dummy_test_procedure; - end;]'; - end; - - procedure modify_dummy_test_package is - pragma autonomous_transaction; - begin - execute immediate q'[create or replace package dummy_test_package as - --%suite(dummy_test_suite) - - --%test(dummy_test) - procedure some_dummy_test_procedure; - end;]'; - end; - - procedure drop_dummy_test_package is - pragma autonomous_transaction; - begin - execute immediate q'[drop package dummy_test_package]'; - end; - - procedure recompile_dummy_test_package is - pragma autonomous_transaction; - begin - execute immediate q'[alter package dummy_test_package compile]'; - end; - - procedure cleanup_annotation_cache is - pragma autonomous_transaction; - begin - delete from ut3.ut_annotation_cache_info - where object_owner = user and object_type = 'PACKAGE' and object_name in ('DUMMY_PACKAGE','DUMMY_TEST_PACKAGE'); - commit; - end; - - - procedure add_new_package is - l_actual_cache_id integer; - l_actual integer; - l_start_date date; - begin - --Act - l_start_date := sysdate; - ut3.ut_annotation_manager.rebuild_annotation_cache(user,'PACKAGE'); - --Assert - select max(cache_id) - into l_actual_cache_id - from ut3.ut_annotation_cache_info - where object_owner = user and object_type = 'PACKAGE' and object_name = 'DUMMY_PACKAGE' - and parse_time >= l_start_date; - - ut.expect(l_actual_cache_id).to_be_not_null; - - select count(1) - into l_actual - from ut3.ut_annotation_cache - where cache_id = l_actual_cache_id; - - ut.expect(l_actual).to_equal(0); - - end; - - procedure update_modified_package is - l_actual_cache_id integer; - l_actual integer; - l_start_date date; - begin - --Arrange - l_start_date := sysdate; - ut3.ut_annotation_manager.rebuild_annotation_cache(user,'PACKAGE'); - recompile_dummy_package(); - l_start_date := sysdate; - dbms_lock.sleep(1); - --Act - ut3.ut_annotation_manager.rebuild_annotation_cache(user,'PACKAGE'); - --Assert - select max(cache_id) - into l_actual_cache_id - from ut3.ut_annotation_cache_info - where object_owner = user and object_type = 'PACKAGE' and object_name = 'DUMMY_PACKAGE' - and parse_time >= l_start_date; - - ut.expect(l_actual_cache_id).to_be_not_null; - - select count(1) - into l_actual - from ut3.ut_annotation_cache - where cache_id = l_actual_cache_id; - - ut.expect(l_actual).to_equal(0); - end; - - - procedure add_new_test_package is - l_actual_cache_id integer; - l_actual sys_refcursor; - l_expected sys_refcursor; - l_start_date date; - begin - --Arrange - l_start_date := sysdate; - --Act - ut3.ut_annotation_manager.rebuild_annotation_cache(user,'PACKAGE'); - --Assert - select max(cache_id) - into l_actual_cache_id - from ut3.ut_annotation_cache_info - 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; - - open l_actual for - select annotation_position, annotation_name, annotation_text, subobject_name - from ut3.ut_annotation_cache where cache_id = l_actual_cache_id - order by annotation_position; - - open l_expected for - select 2 as annotation_position, 'suite' as annotation_name, - 'dummy_test_suite' as annotation_text, '' as subobject_name - from dual union all - select 3, 'rollback' , 'manual', '' as subobject_name - from dual union all - select 5, 'test' , 'dummy_test', 'some_dummy_test_procedure' as subobject_name - from dual union all - select 6, 'beforetest' , 'some_procedure', 'some_dummy_test_procedure' as subobject_name - from dual; - - ut.expect(l_actual).to_equal(l_expected); - end; - - - procedure update_modified_test_package is - l_actual_cache_id 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; - modify_dummy_test_package(); - --Act - ut3.ut_annotation_manager.rebuild_annotation_cache(user,'PACKAGE'); - --Assert - select max(cache_id) - into l_actual_cache_id - from ut3.ut_annotation_cache_info - 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; - - open l_actual for - select annotation_position, annotation_name, annotation_text, subobject_name - from ut3.ut_annotation_cache where cache_id = l_actual_cache_id - order by annotation_position; - - open l_expected for - select 2 as annotation_position, 'suite' as annotation_name, - 'dummy_test_suite' as annotation_text, to_char(null) as subobject_name - from dual union all - select 4, 'test' , 'dummy_test', 'some_dummy_test_procedure' as subobject_name - from dual; - - ut.expect(l_actual).to_equal(l_expected); - end; - - - procedure keep_dropped_data_in_cache is - l_actual_cache_id 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 max(cache_id) - into l_actual_cache_id - from ut3.ut_annotation_cache_info - 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; - - open l_actual for - select annotation_position, annotation_name, annotation_text, subobject_name - from ut3.ut_annotation_cache where cache_id = l_actual_cache_id - order by annotation_position; - - open l_expected for - select 2 as annotation_position, 'suite' as annotation_name, - 'dummy_test_suite' as annotation_text, '' as subobject_name - from dual union all - select 3, 'rollback' , 'manual', '' as subobject_name - from dual union all - select 5, 'test' , 'dummy_test', 'some_dummy_test_procedure' as subobject_name - from dual union all - select 6, 'beforetest' , 'some_procedure', 'some_dummy_test_procedure' as subobject_name - from dual; - - ut.expect(l_actual).to_equal(l_expected); - end; - - procedure no_data_for_dropped_object is - l_actual sys_refcursor; - begin - --Arrange - ut3.ut_annotation_manager.rebuild_annotation_cache(user,'PACKAGE'); - drop_dummy_test_package(); - --Act - open l_actual for - select * from table(ut3.ut_annotation_manager.get_annotated_objects(user,'PACKAGE')) - where object_name = 'DUMMY_TEST_PACKAGE'; - --Assert - ut.expect(l_actual).to_be_empty(); - end; - -end test_annotation_manager; -/ diff --git a/test/core/annotations/test_annotation_manager.pks b/test/core/annotations/test_annotation_manager.pks deleted file mode 100644 index fb5e0299d..000000000 --- a/test/core/annotations/test_annotation_manager.pks +++ /dev/null @@ -1,46 +0,0 @@ -create or replace package test_annotation_manager is - - --%suite(ut_annotation_manager) - --%suitepath(utplsql.core.annotations) - - --%aftereach - procedure cleanup_annotation_cache; - - procedure create_dummy_package; - - procedure drop_dummy_package; - - procedure create_dummy_test_package; - - procedure drop_dummy_test_package; - - --%test(Adds new package to annotation cache info) - --%beforetest(create_dummy_package) - --%aftertest(drop_dummy_package) - procedure add_new_package; - - --%test(Updates annotation cache info for modified package) - --%beforetest(create_dummy_package) - --%aftertest(drop_dummy_package) - procedure update_modified_package; - - --%test(Adds annotations to cache for unit test package) - --%beforetest(create_dummy_test_package) - --%aftertest(drop_dummy_test_package) - procedure add_new_test_package; - - --%test(Updates annotations in cache for modified test package) - --%beforetest(create_dummy_test_package) - --%aftertest(drop_dummy_test_package) - procedure update_modified_test_package; - - --%test(Keeps annotations in cache after object was removed) - --%beforetest(create_dummy_test_package) - 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; - -end test_annotation_manager; -/ diff --git a/test/core/annotations/test_annotation_parser.pkb b/test/core/annotations/test_annotation_parser.pkb deleted file mode 100644 index 6f7bdbf59..000000000 --- a/test/core/annotations/test_annotation_parser.pkb +++ /dev/null @@ -1,419 +0,0 @@ -create or replace package body test_annotation_parser is - - procedure test_proc_comments is - l_source clob; - l_actual ut3.ut_annotations; - l_expected ut3.ut_annotations; - - begin - l_source := 'PACKAGE test_tt AS - -- %suite - -- %displayname(Name of suite) - -- %suitepath(all.globaltests) - - -- %ann1(Name of suite) - -- wrong line - -- %ann2(some_value) - procedure foo; - END;'; - - --Act - l_actual := ut3.ut_annotation_parser.parse_object_annotations(l_source); - - --Assert - - l_expected := ut3.ut_annotations( - ut3.ut_annotation(2,'suite',null, null), - ut3.ut_annotation(3,'displayname','Name of suite',null), - ut3.ut_annotation(4,'suitepath','all.globaltests',null), - ut3.ut_annotation(6,'ann1','Name of suite',null), - ut3.ut_annotation(8,'ann2','some_value','foo') - ); - - ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); - end; - - procedure include_floating_annotations is - l_source clob; - l_actual ut3.ut_annotations; - l_expected ut3.ut_annotations; - begin - l_source := 'PACKAGE test_tt AS - -- %suite - -- %displayname(Name of suite) - -- %suitepath(all.globaltests) - - -- %ann1(Name of suite) - -- %ann2(all.globaltests) - - --%test - procedure foo; - - -- %ann3(Name of suite) - -- %ann4(all.globaltests) - - --%test - procedure bar; - END;'; - - --Act - l_actual := ut3.ut_annotation_parser.parse_object_annotations(l_source); - - --Assert - l_expected := ut3.ut_annotations( - ut3.ut_annotation( 2, 'suite', null, null ), - ut3.ut_annotation( 3, 'displayname', 'Name of suite', null ), - ut3.ut_annotation( 4, 'suitepath', 'all.globaltests', null ), - ut3.ut_annotation( 6, 'ann1', 'Name of suite', null ), - ut3.ut_annotation( 7, 'ann2', 'all.globaltests', null ), - ut3.ut_annotation( 9, 'test', null, 'foo'), - ut3.ut_annotation( 12, 'ann3', 'Name of suite', null ), - ut3.ut_annotation( 13, 'ann4', 'all.globaltests', null ), - ut3.ut_annotation( 15, 'test', null, 'bar') - ); - - ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); - - end; - - procedure parse_complex_with_functions is - l_source clob; - l_actual ut3.ut_annotations; - l_expected ut3.ut_annotations; - - begin - l_source := 'PACKAGE test_tt AS - -- %suite - -- %displayname(Name of suite) - -- %suitepath(all.globaltests) - - --%test - procedure foo; - - - --%beforeeach - procedure foo2; - - --test comment - -- wrong comment - - - /* - describtion of the procedure - */ - --%beforeeach(key=testval) - PROCEDURE foo3(a_value number default null); - - --%all - function foo4(a_val number default null - , a_par varchar2 default := ''asdf''); - END;'; - - --Act - l_actual := ut3.ut_annotation_parser.parse_object_annotations(l_source); - - --Assert - l_expected := ut3.ut_annotations( - ut3.ut_annotation( 2, 'suite', null, null ), - ut3.ut_annotation( 3, 'displayname', 'Name of suite', null ), - ut3.ut_annotation( 4, 'suitepath', 'all.globaltests', null ), - ut3.ut_annotation( 6, 'test', null, 'foo' ), - ut3.ut_annotation( 10, 'beforeeach', null,'foo2' ), - ut3.ut_annotation( 20, 'beforeeach', 'key=testval','foo3' ), - ut3.ut_annotation( 23, 'all', null,'foo4' ) - ); - - ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); - - end; - - procedure no_procedure_annotation is - l_source clob; - l_actual ut3.ut_annotations; - l_expected ut3.ut_annotations; - - begin - l_source := 'PACKAGE test_tt AS - -- %suite - -- %displayname(Name of suite) - -- %suitepath(all.globaltests) - - procedure foo; - END;'; - - --Act - l_actual := ut3.ut_annotation_parser.parse_object_annotations(l_source); - - --Assert - l_expected := ut3.ut_annotations( - ut3.ut_annotation( 2, 'suite', null, null ), - ut3.ut_annotation( 3, 'displayname', 'Name of suite', null ), - ut3.ut_annotation( 4, 'suitepath', 'all.globaltests', null ) - ); - - ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); - - end; - - procedure parse_accessible_by is - l_source clob; - l_actual ut3.ut_annotations; - l_expected ut3.ut_annotations; - - begin - l_source := 'PACKAGE test_tt accessible by (foo) AS - -- %suite - -- %displayname(Name of suite) - -- %suitepath(all.globaltests) - - procedure foo; - END;'; - - --Act - l_actual := ut3.ut_annotation_parser.parse_object_annotations(l_source); - - --Assert - l_expected := ut3.ut_annotations( - ut3.ut_annotation( 2, 'suite', null, null ), - ut3.ut_annotation( 3, 'displayname', 'Name of suite', null ), - ut3.ut_annotation( 4, 'suitepath', 'all.globaltests', null ) - ); - - ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); - - end; - - procedure complex_package_declaration is - l_source clob; - l_actual ut3.ut_annotations; - l_expected ut3.ut_annotations; - - begin - l_source := 'PACKAGE test_tt - ACCESSIBLE BY (calling_proc) - authid current_user - AS - -- %suite - -- %displayname(Name of suite) - -- %suitepath(all.globaltests) - - procedure foo; - END;'; - - --Act - l_actual := ut3.ut_annotation_parser.parse_object_annotations(l_source); - - --Assert - l_expected := ut3.ut_annotations( - ut3.ut_annotation( 5, 'suite', null, null ), - ut3.ut_annotation( 6, 'displayname', 'Name of suite', null ), - ut3.ut_annotation( 7, 'suitepath', 'all.globaltests', null ) - ); - - ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); - - end; - - procedure complex_text is - l_source clob; - l_actual ut3.ut_annotations; - l_expected ut3.ut_annotations; - - begin - l_source := 'PACKAGE test_tt AS - -- %suite - --%displayname(name = Name of suite) - -- %suitepath(key=all.globaltests,key2=foo,"--%some text") - - procedure foo; - END;'; - - --Act - l_actual := ut3.ut_annotation_parser.parse_object_annotations(l_source); - - --Assert - l_expected := ut3.ut_annotations( - ut3.ut_annotation( 2, 'suite', null, null ), - ut3.ut_annotation( 3, 'displayname', 'name = Name of suite', null ), - ut3.ut_annotation( 4, 'suitepath', 'key=all.globaltests,key2=foo,"--%some text"', null ) - ); - - ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); - - end; - - procedure ignore_annotations_in_comments is - l_source clob; - l_actual ut3.ut_annotations; - l_expected ut3.ut_annotations; - - begin - l_source := 'PACKAGE test_tt AS - /* - Some comment - -- inlined - -- %ignored - */ - -- %suite - --%displayname(Name of suite) - -- %suitepath(all.globaltests) - - procedure foo; - END;'; - - --Act - l_actual := ut3.ut_annotation_parser.parse_object_annotations(l_source); - - --Assert - l_expected := ut3.ut_annotations( - ut3.ut_annotation( 7, 'suite', null, null ), - ut3.ut_annotation( 8, 'displayname', 'Name of suite', null ), - ut3.ut_annotation( 9, 'suitepath', 'all.globaltests', null ) - ); - - ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); - - end; - - procedure ignore_wrapped_package is - l_source dbms_preprocessor.source_lines_t; - l_actual ut3.ut_annotations; - begin - --Arrange - l_source(1) := 'create or replace PACKAGE tst_wrapped_pck wrapped -a000000 -369 -abcd -abcd -abcd -abcd -abcd -abcd -abcd -abcd -abcd -abcd -abcd -abcd -abcd -abcd -abcd -9 -34 6d -bg9Jaf2KguofrwaqloE8yvbggKcwg5m49TOf9b9cFj7R9JaW8lYWWi70llr/K6V0iwlp5+eb -v58yvbLAXLi9gYHwoIvAgccti+Cmpg0DKLY= --- %some_annotation_like_text -'; - --Act - l_actual := ut3.ut_annotation_parser.parse_object_annotations(l_source); - --Assert - ut.expect(anydata.convertCollection(l_actual)).to_be_empty(); - end; - - procedure brackets_in_desc is - - l_source clob; - l_actual ut3.ut_annotations; - l_expected ut3.ut_annotations; - begin - l_source := 'PACKAGE test_tt AS - -- %suite(Name of suite (including some brackets) and some more text) -END;'; - - --Act - l_actual := ut3.ut_annotation_parser.parse_object_annotations(l_source); - - --Assert - l_expected := ut3.ut_annotations( - ut3.ut_annotation( 2, 'suite', 'Name of suite (including some brackets) and some more text', null ) - ); - - ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); - end; - - procedure test_space_before_annot_params is - l_source clob; - l_actual ut3.ut_annotations; - l_expected ut3.ut_annotations; - - begin - l_source := 'PACKAGE test_tt AS - /* - Some comment - -- inlined - */ - -- %suite - -- %suitepath (all.globaltests) - - procedure foo; -END;'; - - --Act - l_actual := ut3.ut_annotation_parser.parse_object_annotations(l_source); - - --Assert - l_expected := ut3.ut_annotations( - ut3.ut_annotation( 6, 'suite', null, null ), - ut3.ut_annotation( 7, 'suitepath', 'all.globaltests', null ) - ); - - ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); - end; - - procedure test_windows_newline - as - l_source clob; - l_actual ut3.ut_annotations; - l_expected ut3.ut_annotations; - begin - l_source := 'PACKAGE test_tt AS - -- %suite - -- %displayname(Name of suite)' || chr(13) || chr(10) - || ' -- %suitepath(all.globaltests) - END;'; - - --Act - l_actual := ut3.ut_annotation_parser.parse_object_annotations(l_source); - - --Assert - l_expected := ut3.ut_annotations( - ut3.ut_annotation( 2, 'suite', null, null ), - ut3.ut_annotation( 3, 'displayname', 'Name of suite', null ), - ut3.ut_annotation( 4, 'suitepath', 'all.globaltests', null ) - ); - - ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); - end; - - procedure test_annot_very_long_name - as - l_source clob; - l_actual ut3.ut_annotations; - l_expected ut3.ut_annotations; - begin - l_source := 'PACKAGE very_long_procedure_name_valid_for_oracle_12_so_utPLSQL_should_allow_it_definitely_well_still_not_reached_128_but_wait_we_did_it AS - -- %suite - -- %displayname(Name of suite) - -- %suitepath(all.globaltests) - - --%test - procedure very_long_procedure_name_valid_for_oracle_12_so_utPLSQL_should_allow_it_definitely_well_still_not_reached_128_but_wait_we_dit_it; - END;'; - - --Act - l_actual := ut3.ut_annotation_parser.parse_object_annotations(l_source); - - --Assert - l_expected := ut3.ut_annotations( - ut3.ut_annotation( 2, 'suite', null, null ), - ut3.ut_annotation( 3, 'displayname', 'Name of suite', null ), - ut3.ut_annotation( 4, 'suitepath', 'all.globaltests', null ), - ut3.ut_annotation( 6, 'test', null, 'very_long_procedure_name_valid_for_oracle_12_so_utPLSQL_should_allow_it_definitely_well_still_not_reached_128_but_wait_we_dit_it' ) - ); - - ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); - end; - - -end test_annotation_parser; -/ diff --git a/test/core/expectations/test_expectation_anydata.pkb b/test/core/expectations/test_expectation_anydata.pkb deleted file mode 100644 index bade26652..000000000 --- a/test/core/expectations/test_expectation_anydata.pkb +++ /dev/null @@ -1,518 +0,0 @@ -create or replace package body test_expectation_anydata is - - g_test_expected anydata; - g_test_actual anydata; - - procedure cleanup_expectations is - begin - expectations.cleanup_expectations( ); - end; - - procedure cleanup is - begin - g_test_expected := null; - g_test_actual := null; - cleanup_expectations(); - end; - - procedure fail_on_different_type_null is - begin - --Arrange - g_test_expected := anydata.convertObject( cast(null as test_dummy_object) ); - g_test_actual := anydata.convertObject( cast(null as other_dummy_object) ); - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_on_different_type is - begin - --Arrange - g_test_expected := anydata.convertObject( test_dummy_object(1, 'A', '0') ); - g_test_actual := anydata.convertObject( other_dummy_object(1, 'A', '0') ); - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_on_different_object_data is - begin - --Arrange - g_test_expected := anydata.convertObject( test_dummy_object(1, 'A', '0') ); - g_test_actual := anydata.convertObject( test_dummy_object(1, null, '0') ); - --Act - ut3.ut.expect( g_test_actual ).not_to_equal( g_test_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure fail_on_one_object_null is - begin - --Arrange - g_test_expected := anydata.convertObject( test_dummy_object(1, 'A', '0') ); - g_test_actual := anydata.convertObject( cast(null as test_dummy_object) ); - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_on_collection_vs_object is - begin - --Arrange - g_test_expected := anydata.convertObject( test_dummy_object(1, 'A', '0') ); - g_test_actual := anydata.convertCollection( test_dummy_object_list(test_dummy_object(1, 'A', '0')) ); - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_on_null_vs_empty_coll is - l_null_list test_dummy_object_list; - begin - --Arrange - g_test_expected := anydata.convertCollection( test_dummy_object_list() ); - g_test_actual := anydata.convertCollection( l_null_list ); - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_on_one_collection_null is - l_null_list test_dummy_object_list; - begin - --Arrange - g_test_expected := anydata.convertCollection( test_dummy_object_list(test_dummy_object(1, 'A', '0')) ); - g_test_actual := anydata.convertCollection( l_null_list ); - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_on_one_collection_empty is - begin - --Arrange - g_test_expected := anydata.convertCollection( test_dummy_object_list(test_dummy_object(1, 'A', '0')) ); - g_test_actual := anydata.convertCollection( test_dummy_object_list() ); - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_on_different_coll_data is - l_obj test_dummy_object := test_dummy_object(1, 'A', '0'); - begin - --Arrange - g_test_expected := anydata.convertCollection( test_dummy_object_list(l_obj) ); - g_test_actual := anydata.convertCollection( test_dummy_object_list(l_obj, l_obj) ); - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - --%test(Gives success when both anydata are NULL) - procedure success_on_both_anydata_null is - --Arrange - l_null_anydata anydata; - begin - --Act - ut3.ut.expect( l_null_anydata ).to_equal( l_null_anydata ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure success_on_both_object_null is - --Arrange - l_null_object test_dummy_object; - l_anydata anydata := anydata.convertObject(l_null_object); - begin - --Act - ut3.ut.expect( l_anydata ).to_equal( l_anydata ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure success_on_both_coll_null is - --Arrange - l_null_collection test_dummy_object_list; - l_anydata anydata := anydata.convertCollection(l_null_collection); - begin - --Act - ut3.ut.expect( l_anydata ).to_equal( l_anydata ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure success_on_same_coll_data is - begin - --Arrange - g_test_expected := anydata.convertCollection( test_dummy_object_list(test_dummy_object(1, 'A', '0')) ); - g_test_actual := anydata.convertCollection( test_dummy_object_list(test_dummy_object(1, 'A', '0')) ); - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure fail_on_coll_different_order is - l_first_obj test_dummy_object := test_dummy_object(1, 'A', '0'); - l_second_obj test_dummy_object := test_dummy_object(2, 'b', '1'); - begin - --Arrange - g_test_expected := anydata.convertCollection( test_dummy_object_list(l_first_obj, l_second_obj) ); - g_test_actual := anydata.convertCollection( test_dummy_object_list(l_second_obj, l_first_obj) ); - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure success_on_same_object_data is - begin - --Arrange - g_test_expected := anydata.convertObject( test_dummy_object(1, 'A', '0') ); - g_test_actual := anydata.convertObject( test_dummy_object(1, 'A', '0') ); - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure exclude_attributes_as_list is - l_list ut3.ut_varchar2_list; - begin - --Arrange - l_list := ut3.ut_varchar2_list('Value','/TEST_DUMMY_OBJECT/ID'); - g_test_expected := anydata.convertObject( test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); - g_test_actual := anydata.convertObject( test_dummy_object(id=>3, "name"=>'A',"Value"=>'1') ); - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected, a_exclude=> l_list ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure exclude_attributes_as_csv is - l_list varchar2(100); - begin - --Arrange - l_list := 'Value,ID'; - g_test_expected := anydata.convertObject( test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); - g_test_actual := anydata.convertObject( test_dummy_object(id=>2, "name"=>'A',"Value"=>'1') ); - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected, a_exclude=> l_list ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure exclude_attrib_xpath_invalid is - l_anydata_object anydata; - l_xpath varchar2(100); - begin - --Arrange - l_xpath := '//KEY,\\//Value'; - l_anydata_object := anydata.convertObject( test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); - --Act - ut3.ut.expect( l_anydata_object ).to_equal( l_anydata_object, a_exclude=> l_xpath ); - --Assert - ut.fail('Expected exception -31011 but nothing was raised'); - exception - when others then - ut.expect(sqlcode).to_equal(-31011); - end; - - procedure exclude_attributes_xpath is - l_xpath varchar2(100); - begin - --Arrange - l_xpath := '//Value|//ID'; - g_test_expected := anydata.convertObject( test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); - g_test_actual := anydata.convertObject( test_dummy_object(id=>2, "name"=>'A',"Value"=>'1') ); - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected, a_exclude=> l_xpath ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure exclude_ignores_invalid_attrib is - l_exclude varchar2(100); - begin - --Arrange - l_exclude := 'BadAttributeName'; - g_test_expected := anydata.convertObject( test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); - g_test_actual := anydata.convertObject( test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected, a_exclude=> l_exclude ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure include_attributes_as_list is - l_list ut3.ut_varchar2_list; - begin - --Arrange - l_list := ut3.ut_varchar2_list('Value','ID'); - g_test_expected := anydata.convertObject( test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); - g_test_actual := anydata.convertObject( test_dummy_object(id=>1, "name"=>'b',"Value"=>'0') ); - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected ).include( l_list ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure include_attributes_as_csv is - l_xpath varchar2(100); - begin - --Arrange - l_xpath := 'key,ID'; - g_test_expected := anydata.convertObject( test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); - g_test_actual := anydata.convertObject( test_dummy_object(id=>1, "name"=>'A',"Value"=>'1') ); - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected ).include( l_xpath ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure include_attrib_xpath_invalid is - l_anydata_object anydata; - l_xpath varchar2(100); - begin - --Arrange - l_xpath := '//KEY,\\//Value'; - l_anydata_object := anydata.convertObject( test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); - --Act - ut3.ut.expect( l_anydata_object ).to_equal( l_anydata_object ).include( l_xpath ); - --Assert - ut.fail('Expected exception -31011 but nothing was raised'); - exception - when others then - ut.expect(sqlcode).to_be_between(-31013,-31011); - end; - - procedure include_attributes_xpath is - l_xpath varchar2(100); - begin - --Arrange - l_xpath := '//key|//ID'; - g_test_expected := anydata.convertObject( test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); - g_test_actual := anydata.convertObject( test_dummy_object(id=>1, "name"=>'A',"Value"=>'1') ); - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected ).include( l_xpath ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure include_ignores_invalid_attrib is - l_include varchar2(100); - begin - --Arrange - l_include := ' BadAttributeName, ID '; - g_test_expected := anydata.convertObject( test_dummy_object(id=>1, "name"=>'B',"Value"=>'0') ); - g_test_actual := anydata.convertObject( test_dummy_object(id=>1, "name"=>'A',"Value"=>'1') ); - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected ).include( l_include ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure include_exclude_attributes_csv is - l_exclude varchar2(100); - l_include varchar2(100); - begin - --Arrange - l_include := 'key,ID,Value'; - l_exclude := '//key|//Value'; - g_test_expected := anydata.convertObject( test_dummy_object(id=>1, "name"=>'B',"Value"=>'0') ); - g_test_actual := anydata.convertObject( test_dummy_object(id=>1, "name"=>'A',"Value"=>'1') ); - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected ).exclude( l_exclude ).include( l_include ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure include_exclude_attrib_list is - l_exclude ut3.ut_varchar2_list; - l_include ut3.ut_varchar2_list; - begin - --Arrange - l_include := ut3.ut_varchar2_list('key','ID','Value'); - l_exclude := ut3.ut_varchar2_list('key','Value'); - g_test_expected := anydata.convertObject( test_dummy_object(id=>1, "name"=>'B',"Value"=>'0') ); - g_test_actual := anydata.convertObject( test_dummy_object(id=>1, "name"=>'A',"Value"=>'1') ); - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected ).exclude( l_exclude ).include( l_include ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure reports_diff_attribute is - l_expected varchar2(32767); - l_actual varchar2(32767); - begin - --Arrange - g_test_expected := anydata.convertObject( test_dummy_object(1, 'A', '0') ); - g_test_actual := anydata.convertObject( test_dummy_object(1, NULL, '0') ); - l_expected := q'[Actual: ut3_tester.test_dummy_object was expected to equal: ut3_tester.test_dummy_object -Diff: -Rows: [ 1 differences ] - Row No. 1 - Actual: - Row No. 1 - Expected: A]'; - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected ); - --Assert - l_actual := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - ut.expect(l_actual).to_be_like(l_expected); - end; - - - procedure reports_diff_structure is - l_obj test_dummy_object := test_dummy_object(1, 'A', '0'); - l_expected varchar2(32767); - l_actual varchar2(32767); - begin - --Arrange - g_test_expected := anydata.convertCollection( test_dummy_object_list(l_obj) ); - g_test_actual := anydata.convertCollection( test_dummy_object_list(l_obj, l_obj) ); - l_expected := q'[Actual: ut3_tester.test_dummy_object_list [ count = 2 ] was expected to equal: ut3_tester.test_dummy_object_list [ count = 1 ] -Diff: -Rows: [ 1 differences ] - Row No. 2 - Extra: 1A0]'; - --Act - ut3.ut.expect( g_test_actual ).to_equal( g_test_expected ); - --Assert - l_actual := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - ut.expect(l_actual).to_be_like(l_expected); - end; - - function get_anydata return anydata is - begin - return anydata.convertObject( test_dummy_object(1, 'B', '0') ); - end; - - procedure deprec_to_equal_excl_varch is - begin - --Act - ut3.ut.expect(get_anydata()).to_equal(get_anydata(), a_exclude => 'A_COLUMN,Some_Col'); - --Assert - ut.expect(cardinality(ut3.ut_expectation_processor.get_warnings())).to_equal(1); - ut.expect(ut3.ut_expectation_processor.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); - end; - - procedure deprec_to_equal_excl_list is - begin - --Act - ut3.ut.expect(get_anydata()).to_equal(get_anydata(), a_exclude => ut3.ut_varchar2_list('A_COLUMN','Some_Col')); - --Assert - ut.expect(cardinality(ut3.ut_expectation_processor.get_warnings())).to_equal(1); - ut.expect(ut3.ut_expectation_processor.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); - end; - - procedure deprec_not_to_equal_excl_varch is - begin - --Act - ut3.ut.expect(get_anydata()).not_to_equal(get_anydata(), a_exclude => 'A_COLUMN,Some_Col'); - --Assert - ut.expect(cardinality(ut3.ut_expectation_processor.get_warnings())).to_equal(1); - ut.expect(ut3.ut_expectation_processor.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); - end; - - procedure deprec_not_to_equal_excl_list is - begin - --Act - ut3.ut.expect(get_anydata()).not_to_equal(get_anydata(), a_exclude => ut3.ut_varchar2_list('A_COLUMN','Some_Col')); - --Assert - ut.expect(cardinality(ut3.ut_expectation_processor.get_warnings())).to_equal(1); - ut.expect(ut3.ut_expectation_processor.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); - end; - - procedure deprec_equal_excl_varch is - begin - --Act - ut3.ut.expect(get_anydata()).to_(ut3.equal(get_anydata(), a_exclude => 'A_COLUMN,Some_Col')); - --Assert - ut.expect(cardinality(ut3.ut_expectation_processor.get_warnings())).to_equal(1); - ut.expect(ut3.ut_expectation_processor.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); - end; - - procedure deprec_equal_excl_list is - begin - --Act - ut3.ut.expect(get_anydata()).to_(ut3.equal(get_anydata(), a_exclude => ut3.ut_varchar2_list('A_COLUMN','Some_Col'))); - --Assert - ut.expect(cardinality(ut3.ut_expectation_processor.get_warnings())).to_equal(1); - ut.expect(ut3.ut_expectation_processor.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); - end; - - --%test(Reports only mismatched columns on column data mismatch) - procedure data_diff_on_atr_data_mismatch is - l_actual test_dummy_object_list; - l_expected test_dummy_object_list; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - select test_dummy_object( rownum, 'Something '||rownum, rownum) - bulk collect into l_actual - from dual connect by level <=2; - select test_dummy_object( rownum, 'Something '||rownum, rownum) - bulk collect into l_expected - from dual connect by level <=2 - order by rownum desc; - --Act - ut3.ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); - - l_expected_message := q'[Actual: ut3_tester.test_dummy_object_list [ count = 2 ] was expected to equal: ut3_tester.test_dummy_object_list [ count = 2 ] -Diff: -Rows: [ 2 differences ] - Row No. 1 - Actual: 1Something 11 - Row No. 1 - Expected: 2Something 22 - Row No. 2 - Actual: 2Something 22 - Row No. 2 - Expected: 1Something 11]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure data_diff_on_20_rows_only is - l_actual test_dummy_object_list; - l_expected test_dummy_object_list; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - select test_dummy_object( rn, 'Something '||rn, rn1) - bulk collect into l_actual - from (select rownum * case when mod(rownum,2) = 0 then -1 else 1 end rn, - rownum * case when mod(rownum,4) = 0 then -1 else 1 end rn1 - from dual connect by level <=100); - select test_dummy_object( rownum, 'Something '||rownum, rownum) - bulk collect into l_expected - from dual connect by level <=110; - --Act - ut3.ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); - - l_expected_message := q'[Actual: ut3_tester.test_dummy_object_list [ count = 100 ] was expected to equal: ut3_tester.test_dummy_object_list [ count = 110 ] -Diff: -Rows: [ 60 differences, showing first 20 ] - Row No. 2 - Actual: -2Something -2 - Row No. 2 - Expected: 2Something 2 - Row No. 4 - Actual: -4Something -4-4 - Row No. 4 - Expected: 4Something 44 - % - Row No. 38 - Actual: -38Something -38 - Row No. 38 - Expected: 38Something 38 - Row No. 40 - Actual: -40Something -40-40 - Row No. 40 - Expected: 40Something 4040]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - -end; -/ \ No newline at end of file diff --git a/test/core/expectations/test_expectation_processor.pkb b/test/core/expectations/test_expectation_processor.pkb deleted file mode 100644 index 17ffbec3c..000000000 --- a/test/core/expectations/test_expectation_processor.pkb +++ /dev/null @@ -1,71 +0,0 @@ -create or replace package body test_expectation_processor is - - procedure who_called_expectation is - l_stack_trace varchar2(4000); - l_source_line varchar2(4000); - begin - l_stack_trace := q'[----- PL/SQL Call Stack ----- - object line object - handle number name -34f88e4420 124 package body SCH_TEST.UT_EXPECTATION_PROCESSOR -353dfeb2f8 26 SCH_TEST.UT_EXPECTATION_RESULT -cba249ce0 112 SCH_TEST.UT_EXPECTATION -3539881cf0 21 SCH_TEST.UT_EXPECTATION_NUMBER -351a608008 28 package body SCH_TEST.TPKG_PRIOR_YEAR_GENERATION -351a6862b8 6 anonymous block -351fe31010 1825 package body SYS.DBMS_SQL -20befbe4d8 129 SCH_TEST.UT_EXECUTABLE -20befbe4d8 65 SCH_TEST.UT_EXECUTABLE -34f8ab7cd8 80 SCH_TEST.UT_TEST -34f8ab98f0 48 SCH_TEST.UT_SUITE_ITEM -34f8ab9b10 74 SCH_TEST.UT_SUITE -34f8ab98f0 48 SCH_TEST.UT_SUITE_ITEM -cba24bfd0 75 SCH_TEST.UT_LOGICAL_SUITE -353dfecf30 59 SCH_TEST.UT_RUN -34f8ab98f0 48 SCH_TEST.UT_SUITE_ITEM -357f5421e8 77 package body SCH_TEST.UT_RUNNER -357f5421e8 111 package body SCH_TEST.UT_RUNNER -20be951ab0 292 package body SCH_TEST.UT -20be951ab0 320 package body SCH_TEST.UT -]'; - ut.expect( - ut3.ut_expectation_processor.who_called_expectation(l_stack_trace) - ).to_be_like('at "SCH_TEST.TPKG_PRIOR_YEAR_GENERATION", line 28 %'); - end; - - - procedure who_called_expectation_0x is - l_stack_trace varchar2(4000); - l_source_line varchar2(4000); - begin - l_stack_trace := q'[----- PL/SQL Call Stack ----- - object line object - handle number name -34f88e4420 124 package body SCH_TEST.UT_EXPECTATION_PROCESSOR -353dfeb2f8 26 SCH_TEST.UT_EXPECTATION_RESULT -cba249ce0 112 SCH_TEST.UT_EXPECTATION -3539881cf0 21 SCH_TEST.UT_EXPECTATION_NUMBER -351a608008 28 package body SCH_TEST.TPKG_PRIOR_YEAR_GENERATION -351a6862b8 6 anonymous block -351fe31010 1825 package body SYS.DBMS_SQL -20befbe4d8 129 SCH_TEST.UT_EXECUTABLE -20befbe4d8 65 SCH_TEST.UT_EXECUTABLE -34f8ab7cd8 80 SCH_TEST.UT_TEST -34f8ab98f0 48 SCH_TEST.UT_SUITE_ITEM -34f8ab9b10 74 SCH_TEST.UT_SUITE -34f8ab98f0 48 SCH_TEST.UT_SUITE_ITEM -cba24bfd0 75 SCH_TEST.UT_LOGICAL_SUITE -353dfecf30 59 SCH_TEST.UT_RUN -34f8ab98f0 48 SCH_TEST.UT_SUITE_ITEM -357f5421e8 77 package body SCH_TEST.UT_RUNNER -357f5421e8 111 package body SCH_TEST.UT_RUNNER -20be951ab0 292 package body SCH_TEST.UT -20be951ab0 320 package body SCH_TEST.UT -]'; - ut.expect( - ut3.ut_expectation_processor.who_called_expectation(l_stack_trace) - ).to_be_like('at "SCH_TEST.TPKG_PRIOR_YEAR_GENERATION", line 28 %'); - end; - -end; -/ diff --git a/test/core/expectations/test_expectation_processor.pks b/test/core/expectations/test_expectation_processor.pks deleted file mode 100644 index ecde48153..000000000 --- a/test/core/expectations/test_expectation_processor.pks +++ /dev/null @@ -1,17 +0,0 @@ -create or replace package test_expectation_processor is - - --%suite(expectation_processor) - --%suitepath(utplsql.core.expectations) - - --%context(who_called_expectation) - - --%test(parses stack trace and returns object and line that called expectation) - procedure who_called_expectation; - - --%test(parses stack trace containing 0x and returns object and line that called expectation) - procedure who_called_expectation_0x; - - --%endcontext - -end; -/ diff --git a/test/core/expectations/test_expectations_cursor.pkb b/test/core/expectations/test_expectations_cursor.pkb deleted file mode 100644 index d18cef5fb..000000000 --- a/test/core/expectations/test_expectations_cursor.pkb +++ /dev/null @@ -1,1991 +0,0 @@ -create or replace package body test_expectations_cursor is - - gc_blob blob := to_blob('123'); - gc_clob clob := to_clob('abc'); - gc_date date := sysdate; - gc_ds_int interval day(9) to second(9) := numtodsinterval(1.12345678912, 'day'); - gc_num number := 123456789.1234567890123456789; - gc_ts timestamp(9) := to_timestamp_tz('2017-03-30 00:21:12.123456789 cet','yyyy-mm-dd hh24:mi:ss.ff9 tzr'); - gc_ts_tz timestamp(9) with time zone := to_timestamp_tz('2017-03-30 00:21:12.123456789 cet','yyyy-mm-dd hh24:mi:ss.ff9 tzr'); - gc_ts_ltz timestamp(9) with local time zone := to_timestamp_tz('2017-03-30 00:21:12.123456789 cet','yyyy-mm-dd hh24:mi:ss.ff9 tzr'); - gc_varchar varchar2(4000) := 'a varchar2'; - gc_ym_int interval year(9) to month := numtoyminterval(1.1, 'year'); - - procedure cleanup_expectations is - begin - expectations.cleanup_expectations( ); - end; - - procedure setup_temp_table_test - as - pragma autonomous_transaction; - begin - execute immediate 'create global temporary table gtt_test_table ( - value varchar2(250) - ) on commit delete rows'; - - end; - - procedure cleanup_temp_table_test - as - pragma autonomous_transaction; - begin - execute immediate 'drop table gtt_test_table'; - end; - - procedure with_temp_table - as - pragma autonomous_transaction; - l_expected sys_refcursor; - l_actual sys_refcursor; - begin - -- Arrange - execute immediate 'insert into gtt_test_table ( value ) ' || - 'select ''Test-entry'' from dual union all ' || - 'select ''Other test entry'' from dual'; - open l_expected for - select 'Test-entry' as value from dual union all - select 'Other test entry' as value from dual; - open l_actual for 'select * from gtt_test_table'; - --Act - execute the expectation on cursor opened on GTT - ut3.ut.expect( l_actual ).to_equal( l_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - --Cleanup - rollback; - end; - - - procedure success_on_same_data - as - l_expected sys_refcursor; - l_actual sys_refcursor; - begin - -- Arrange - open l_expected for - select 1 as my_num, - 'This is my test string' as my_string, - to_clob('This is an even longer test clob') as my_clob, - to_date('1984-09-05', 'YYYY-MM-DD') as my_date - from dual; - open l_actual for - select 1 as my_num, - 'This is my test string' as my_string, - to_clob('This is an even longer test clob') as my_clob, - to_date('1984-09-05', 'YYYY-MM-DD') as my_date - from dual; - --Act - ut3.ut.expect( l_actual ).to_equal( l_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure success_on_empty - as - l_expected sys_refcursor; - l_actual sys_refcursor; - begin - -- Arrange - open l_expected for select * from dual where 1=0; - open l_actual for select * from dual where 1=0; - --Act - ut3.ut.expect( l_actual ).to_equal( l_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure success_on_both_null - as - l_expected sys_refcursor; - l_actual sys_refcursor; - begin - --Act - ut3.ut.expect( l_actual ).to_equal( l_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure success_to_be_null - as - l_actual sys_refcursor; - begin - --Act - ut3.ut.expect( l_actual ).to_be_null(); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure success_not_to_be_not_null - as - l_actual sys_refcursor; - begin - --Act - ut3.ut.expect( l_actual ).not_to_be_not_null(); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure success_not_to_be_null - as - l_actual sys_refcursor; - begin - --Arrange - open l_actual for select * from dual; - --Act - ut3.ut.expect( l_actual ).to_be_not_null(); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure success_to_be_not_null - as - l_actual sys_refcursor; - begin - --Arrange - open l_actual for select * from dual; - --Act - ut3.ut.expect( l_actual ).to_be_not_null(); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure success_is_empty - as - l_actual sys_refcursor; - begin - --Arrange - open l_actual for select * from dual where 0=1; - --Act - ut3.ut.expect( l_actual ).to_be_empty(); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure success_is_not_empty - as - l_actual sys_refcursor; - begin - --Arrange - open l_actual for select * from dual; - --Act - ut3.ut.expect( l_actual ).not_to_be_empty(); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure failure_is_null - as - l_actual sys_refcursor; - begin - --Arrange - open l_actual for select * from dual; - --Act - ut3.ut.expect( l_actual ).to_be_null(); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure failure_is_not_null - as - l_actual sys_refcursor; - begin - --Act - ut3.ut.expect( l_actual ).not_to_be_null(); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure failure_is_empty - as - l_actual sys_refcursor; - begin - --Arrange - open l_actual for select * from dual; - --Act - ut3.ut.expect( l_actual ).to_be_empty(); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure failure_is_not_empty - as - l_actual sys_refcursor; - begin - --Arrange - open l_actual for select * from dual where 0=1; - --Act - ut3.ut.expect( l_actual ).not_to_be_empty(); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_null_vs_empty - as - l_expected sys_refcursor; - l_actual sys_refcursor; - begin - --Arrange - open l_expected for select * from dual where 1=0; - --Act - ut3.ut.expect( l_actual ).not_to_equal( l_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure fail_on_difference - as - l_expected sys_refcursor; - l_actual sys_refcursor; - begin - --Arrange - open l_expected for select to_clob('This is an even longer test clob') as my_clob from dual; - open l_actual for select to_clob('Another totally different story') as my_clob from dual; - --Act - ut3.ut.expect( l_actual ).to_equal( l_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_on_expected_missing - as - l_expected sys_refcursor; - l_actual sys_refcursor; - begin - --Arrange - open l_expected for select 1 as my_num from dual; - open l_actual for select 1 as my_num from dual union all select 1 as my_num from dual; - --Act - ut3.ut.expect( l_actual ).to_equal( l_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_on_actual_missing - as - l_expected sys_refcursor; - l_actual sys_refcursor; - begin - --Arrange - open l_expected for select 1 as my_num from dual union all select 1 as my_num from dual; - open l_actual for select 1 as my_num from dual; - --Act - ut3.ut.expect( l_actual ).to_equal( l_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_on_different_column_name - as - l_expected sys_refcursor; - l_actual sys_refcursor; - begin - --Arrange - open l_expected for select 1 as col_1 from dual; - open l_actual for select 1 as col_2 from dual; - --Act - ut3.ut.expect( l_actual ).to_equal( l_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - - procedure fail_on_different_column_order - as - l_expected sys_refcursor; - l_actual sys_refcursor; - begin - --Arrange - open l_expected for select 1 as col_1, 2 as col_2 from dual; - open l_actual for select 2 as col_2, 1 as col_1 from dual; - --Act - ut3.ut.expect( l_actual ).to_equal( l_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_on_different_row_order - as - l_expected sys_refcursor; - l_actual sys_refcursor; - begin - --Arrange - open l_expected for select 1 as my_num from dual union all select 2 as my_num from dual; - open l_actual for select 2 as my_num from dual union all select 1 as my_num from dual; - --Act - ut3.ut.expect( l_actual ).to_equal( l_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure include_time_in_date_with_nls - as - l_expected sys_refcursor; - l_actual sys_refcursor; - l_date date := sysdate; - l_second number := 1/24/60/60; - begin - --Arrange - ut3.ut.set_nls; - open l_actual for select l_date as some_date from dual; - open l_expected for select l_date-l_second some_date from dual; - ut3.ut.reset_nls; - --Act - ut3.ut.expect( l_actual ).to_equal( l_expected ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure uses_default_nls_for_date - as - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select sysdate as some_date from dual; - open l_expected for select to_date(to_char(sysdate)) as some_date from dual; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure exclude_columns_as_list - as - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; - open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected, a_exclude=>ut3.ut_varchar2_list('A_COLUMN','Some_Col')); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure exclude_columns_as_csv - as - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; - open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected, a_exclude=>'A_COLUMN,Some_Col'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure exclude_columns_as_mixed_list is - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; - open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected, a_exclude=>ut3.ut_varchar2_list('A_COLUMN','/ROW/Some_Col')); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure exclude_columns_as_mix_csv_lst is - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; - open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected, a_exclude=>'A_COLUMN,/ROW/Some_Col'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure exclude_columns_xpath_invalid - as - l_actual SYS_REFCURSOR; - l_expected SYS_REFCURSOR; - l_error_code integer := -31011; --xpath_error - begin - --Arrange - open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; - open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; - begin - --Act - ut3.ut.expect(l_actual).to_equal(l_expected, a_exclude=>'/ROW/A_COLUMN,\\//Some_Col'); - --Assert - ut.fail('Expected '||l_error_code||' but nothing was raised'); - exception - when others then - ut.expect(sqlcode).to_equal(l_error_code); - end; - end; - - procedure exclude_columns_xpath - as - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual; - open l_expected for select 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected, a_exclude=>'/ROW/A_COLUMN|/ROW/Some_Col'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure exclude_ignores_invalid_column - as - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select rownum as rn, 'c' as A_COLUMN from dual a connect by level < 4; - open l_expected for select rownum as rn, 'd' as A_COLUMN from dual a connect by level < 4; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected, a_exclude=>ut3.ut_varchar2_list('A_COLUMN','non_existing_column')); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure include_columns_as_list - as - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; - open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).include(ut3.ut_varchar2_list('RN','//A_Column','SOME_COL')); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure include_columns_as_csv - as - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; - open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).include('RN,//A_Column,SOME_COL'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure include_columns_xpath_invalid - as - l_actual SYS_REFCURSOR; - l_expected SYS_REFCURSOR; - begin - --Arrange - open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; - open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; - begin - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).include('/ROW/RN,\\//A_Column,//SOME_COL'); - --Assert - ut.fail('Expected exception but nothing was raised'); - exception - when others then - ut.expect(sqlcode).to_be_between(-31013,-31011); - end; - end; - - procedure include_columns_xpath - as - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual connect by level < 4; - open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual connect by level < 4; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).include('/ROW/RN|//A_Column|//SOME_COL'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure include_ignores_invalid_column - as - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select rownum as rn, 'c' as A_COLUMN from dual a connect by level < 4; - open l_expected for select rownum as rn, 'd' as A_COLUMN from dual a connect by level < 4; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).include(ut3.ut_varchar2_list('RN','non_existing_column')); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure include_exclude_col_csv_xpath - as - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual connect by level < 4; - open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual connect by level < 4; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).exclude('Some_Col').include('/ROW/RN|//Some_Col'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure include_exclude_columns_list - as - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual connect by level < 4; - open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual connect by level < 4; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).exclude(ut3.ut_varchar2_list('A_COLUMN')).include(ut3.ut_varchar2_list('RN','A_Column','A_COLUMN')); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure data_diff_on_rows_mismatch - as - l_actual sys_refcursor; - l_expected sys_refcursor; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_actual for select 1 rn from dual union all select 6 rn from dual; - open l_expected for select rownum rn from dual connect by level <=3; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected); - - l_expected_message := q'[Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 3 ] -Diff: -Rows: [ 2 differences ] - Row No. 2 - Actual: 6 - Row No. 2 - Expected: 2 - Row No. 3 - Missing: 3]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure char_and_varchar2_col_is_equal is - l_expected sys_refcursor; - l_actual sys_refcursor; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_actual for select cast('a' as char(1)) a_column, 1 as id from dual; - open l_expected for select cast('a' as varchar2(10)) a_column from dual; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected); - l_expected_message := q'[Actual: refcursor [ count = 1 ] was expected to equal: refcursor [ count = 1 ] -Diff: -Columns: - Column [position: 2, data-type: NUMBER] is not expected in results. -Rows: [ 1 differences ] - All rows are different as the columns are not matching.]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure column_diff_on_data_type_diff is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_actual for select to_char(rownum) rn, rownum another_rn from dual connect by level <=2; - open l_expected for select rownum rn, rownum another_rn from dual connect by level <=2; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected); - - l_expected_message := q'[Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ] -Diff: -Columns: - Column data-type is invalid. Expected: NUMBER, actual: VARCHAR2.]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure column_diff_on_col_name_diff is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_actual for select rownum rn, rownum bad_column_name from dual connect by level <=2; - open l_expected for select rownum rn, rownum expected_column_name from dual connect by level <=2; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected); - - l_expected_message := q'[Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ] -Diff: -Columns:% - Column [data-type: NUMBER] is missing. Expected column position: 2.% - Column [position: 2, data-type: NUMBER] is not expected in results.%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - --%test(Reports column diff on cusror with different column positions) - procedure column_diff_on_col_position is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_actual for select rownum+1 col_1, rownum+2 col_2, rownum+3 col_3, rownum+4 col_4 from dual connect by level <=2; - open l_expected for select rownum+1 col_1, rownum+4 col_4, rownum+2 col_2, rownum+3 col_3 from dual connect by level <=2; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected); - - l_expected_message := q'[Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ] -Diff: -Columns: - Column is misplaced. Expected position: 2, actual position: 4. - Column is misplaced. Expected position: 3, actual position: 2. - Column is misplaced. Expected position: 4, actual position: 3. -Rows: [ 2 differences ] - All rows are different as the columns are not matching.]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - - --%test(Reports only mismatched columns on column data mismatch) - procedure data_diff_on_col_data_mismatch is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_actual for select rownum good_col, -rownum bad_col from dual connect by level <=2; - open l_expected for select rownum good_col, rownum bad_col from dual connect by level <=2; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected); - - l_expected_message := q'[Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ] -Diff: -Rows: [ 2 differences ] - Row No. 1 - Actual: -1 - Row No. 1 - Expected: 1 - Row No. 2 - Actual: -2 - Row No. 2 - Expected: 2]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure data_diff_on_20_rows_only is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_actual for - select rownum - * case when mod(rownum,2) = 0 then -1 else 1 end bad_col, - rownum good_col - from dual connect by level <=100; - open l_expected for select rownum bad_col, rownum good_col from dual connect by level <=110; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected); - - l_expected_message := q'[Actual: refcursor [ count = 100 ] was expected to equal: refcursor [ count = 110 ] -Diff: -Rows: [ 60 differences, showing first 20 ] - Row No. 2 - Actual: -2 - Row No. 2 - Expected: 2 - Row No. 4 - Actual: -4 - Row No. 4 - Expected: 4 - Row No. 6 - Actual: -6 - Row No. 6 - Expected: 6 - Row No. 8 - Actual: -8 - Row No. 8 - Expected: 8 - % - Row No. 38 - Actual: -38 - Row No. 38 - Expected: 38 - Row No. 40 - Actual: -40 - Row No. 40 - Expected: 40]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure column_and_data_diff is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_expected for - select 1 as ID, 'JACK' as FIRST_NAME, 'SPARROW' AS LAST_NAME, 10000 AS SALARY from dual union all - select 2 as ID, 'LUKE' as FIRST_NAME, 'SKYWALKER' AS LAST_NAME, 1000 AS SALARY from dual union all - select 3 as ID, 'TONY' as FIRST_NAME, 'STARK' AS LAST_NAME, 100000 AS SALARY from dual; - open l_actual for - select 'M' AS GENDER, 'JACK' as FIRST_NAME, 'SPARROW' AS LAST_NAME, 1 as ID, '25000' AS SALARY from dual union all - select 'M' AS GENDER, 'TONY' as FIRST_NAME, 'STARK' AS LAST_NAME, 3 as ID, '100000' AS SALARY from dual union all - select 'F' AS GENDER, 'JESSICA' as FIRST_NAME, 'JONES' AS LAST_NAME, 4 as ID, '2345' AS SALARY from dual union all - select 'M' AS GENDER, 'LUKE' as FIRST_NAME, 'SKYWALKER' AS LAST_NAME, 2 as ID, '1000' AS SALARY from dual; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected); - l_expected_message := q'[Actual: refcursor [ count = 4 ] was expected to equal: refcursor [ count = 3 ] -Diff: -Columns: - Column is misplaced. Expected position: 1, actual position: 4. - Column data-type is invalid. Expected: NUMBER, actual: VARCHAR2. - Column [position: 1, data-type: CHAR] is not expected in results. -Rows: [ 4 differences ] - Row No. 1 - Actual: 25000 - Row No. 1 - Expected: 10000 - Row No. 2 - Actual: TONYSTARK3100000 - Row No. 2 - Expected: 2LUKESKYWALKER1000 - Row No. 3 - Actual: JESSICAJONES42345 - Row No. 3 - Expected: 3TONYSTARK100000 - Row No. 4 - Extra: MLUKESKYWALKER21000]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure prepare_table - as - pragma autonomous_transaction; - begin - execute immediate - 'create table test_table_for_cursors ( - some_blob blob, - some_clob clob, - some_date date, - some_ds_interval interval day(9) to second(9), - some_nummber number, - some_timestamp timestamp(9), - some_timestamp_tz timestamp(9) with time zone, - some_timestamp_ltz timestamp(9) with local time zone, - some_varchar2 varchar2(4000), - some_ym_interval interval year(9) to month - )'; - execute immediate q'[ - insert into test_table_for_cursors - values( :gc_blob, :gc_clob, :gc_date, :gc_ds_int, :gc_num, :gc_ts, :gc_ts_tz, :gc_ts_ltz, :gc_varchar, :gc_ym_int - ) -]' using gc_blob, gc_clob, gc_date, gc_ds_int, gc_num, gc_ts, gc_ts_tz, gc_ts_ltz, gc_varchar, gc_ym_int; - commit; - end; - - procedure cleanup_table - as - pragma autonomous_transaction; - begin - execute immediate 'drop table test_table_for_cursors'; - end; - - procedure compares_sql_and_plsql_types is - l_expected sys_refcursor; - l_actual sys_refcursor; - begin - --Arrange - open l_expected for - select gc_blob some_blob, - gc_clob some_clob, - gc_date some_date, - gc_ds_int some_ds_interval, - gc_num some_nummber, - gc_ts some_timestamp, - gc_ts_tz some_timestamp_tz, - gc_ts_ltz some_timestamp_ltz , - gc_varchar some_varchar2, - gc_ym_int some_ym_interval - from dual; - open l_actual for q'[select * from test_table_for_cursors]'; - --Act - ut3.ut.expect(l_expected).to_equal(l_actual); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure closes_cursor_after_use - as - l_actual sys_refcursor; - begin - --Arrange - open l_actual for select 1 as value from dual; - --Act - ut3.ut.expect(l_actual).to_be_empty(); - --Assert - ut.expect(l_actual%isopen).to_be_false(); - end; - - procedure closes_cursor_after_use_on_err - as - l_actual sys_refcursor; - begin - --Arrange - open l_actual for select 1/0 as value from dual; - --Act - begin - ut3.ut.expect(l_actual).to_be_empty(); - exception - when others then - null; - end; - --Assert - ut.expect(l_actual%isopen).to_be_false(); - end; - - procedure reports_on_exception_in_cursor - as - l_actual sys_refcursor; - l_error_code integer := -19202; --Error occurred in XML processing - begin - --Act - open l_actual for select 1/0 as error_column from dual connect by level < 10; - begin - ut3.ut.expect(l_actual).to_be_empty(); - --Assert - ut.fail('Expected '||l_error_code||' but nothing was raised'); - exception - when others then - ut.expect(sqlcode).to_equal(l_error_code); - end; - end; - - procedure exception_when_closed_cursor - is - l_actual sys_refcursor; - l_error_code constant integer := -20155; - begin - --Arrange - open l_actual for select * from dual; - close l_actual; - --Act - ut3.ut.expect( l_actual ).not_to_be_null; - exception - when others then - --Assert - ut.expect(sqlcode).to_equal(l_error_code); - end; - - procedure compares_over_1000_rows - as - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select object_name from all_objects where rownum <=1100; - open l_expected for select object_name from all_objects where rownum <=1100; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected); - - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - function get_cursor return sys_refcursor is - l_cursor sys_refcursor; - begin - open l_cursor for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; - return l_cursor; - end; - - procedure deprec_to_equal_excl_varch is - begin - --Act - ut3.ut.expect(get_cursor()).to_equal(get_cursor(), a_exclude => 'A_COLUMN,Some_Col'); - --Assert - ut.expect(cardinality(ut3.ut_expectation_processor.get_warnings())).to_equal(1); - ut.expect(ut3.ut_expectation_processor.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); - end; - - procedure deprec_to_equal_excl_list is - begin - --Act - ut3.ut.expect(get_cursor()).to_equal(get_cursor(), a_exclude => ut3.ut_varchar2_list('A_COLUMN','Some_Col')); - --Assert - ut.expect(cardinality(ut3.ut_expectation_processor.get_warnings())).to_equal(1); - ut.expect(ut3.ut_expectation_processor.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); - end; - - procedure deprec_not_to_equal_excl_varch is - begin - --Act - ut3.ut.expect(get_cursor()).not_to_equal(get_cursor(), a_exclude => 'A_COLUMN,Some_Col'); - --Assert - ut.expect(cardinality(ut3.ut_expectation_processor.get_warnings())).to_equal(1); - ut.expect(ut3.ut_expectation_processor.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); - end; - - procedure deprec_not_to_equal_excl_list is - begin - --Act - ut3.ut.expect(get_cursor()).not_to_equal(get_cursor(), a_exclude => ut3.ut_varchar2_list('A_COLUMN','Some_Col')); - --Assert - ut.expect(cardinality(ut3.ut_expectation_processor.get_warnings())).to_equal(1); - ut.expect(ut3.ut_expectation_processor.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); - end; - - procedure deprec_equal_excl_varch is - begin - --Act - ut3.ut.expect(get_cursor()).to_(ut3.equal(get_cursor(), a_exclude => 'A_COLUMN,Some_Col')); - --Assert - ut.expect(cardinality(ut3.ut_expectation_processor.get_warnings())).to_equal(1); - ut.expect(ut3.ut_expectation_processor.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); - end; - - procedure deprec_equal_excl_list is - begin - --Act - ut3.ut.expect(get_cursor()).to_(ut3.equal(get_cursor(), a_exclude => ut3.ut_varchar2_list('A_COLUMN','Some_Col'))); - --Assert - ut.expect(cardinality(ut3.ut_expectation_processor.get_warnings())).to_equal(1); - ut.expect(ut3.ut_expectation_processor.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); - end; - - procedure col_diff_on_col_name_implicit is - l_actual SYS_REFCURSOR; - l_expected SYS_REFCURSOR; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_actual for select '1' , '2' from dual connect by level <=2; - open l_expected for select rownum , rownum expected_column_name from dual connect by level <=2; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected); - - l_expected_message := q'[Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ]% -Diff:% -Columns:% - Column [data-type: NUMBER] is missing. Expected column position: 1.% - Column [data-type: NUMBER] is missing. Expected column position: 2.% - Column <%1%> [position: 1, data-type: CHAR] is not expected in results.% - Column <%2%> [position: 2, data-type: CHAR] is not expected in results.% -Rows: [ 2 differences ]% - All rows are different as the columns are not matching.%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure col_mtch_on_col_name_implicit is - l_actual SYS_REFCURSOR; - l_expected SYS_REFCURSOR; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_actual for select '1' , rownum from dual connect by level <=2; - open l_expected for select '1' , rownum from dual connect by level <=2; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - - procedure include_col_name_implicit is - l_actual SYS_REFCURSOR; - l_expected SYS_REFCURSOR; - begin - --Arrange - open l_actual for select rownum as rn, 'a', 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; - open l_expected for select rownum as rn, 'a', 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; - begin - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).include(q'!/ROW/RN,'a',//SOME_COL!'); - --Assert - ut.fail('Expected exception but nothing was raised'); - exception - when others then - ut.expect(sqlcode).to_be_between(-31013,-31011); - end; - end; - - procedure exclude_col_name_implicit is - l_actual SYS_REFCURSOR; - l_expected SYS_REFCURSOR; - begin - --Arrange - open l_actual for select rownum as rn, 'a', 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; - open l_expected for select rownum as rn, 'a', 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; - begin - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).exclude(q'!/ROW/RN,'a',//SOME_COL!'); - --Assert - ut.fail('Expected exception but nothing was raised'); - exception - when others then - ut.expect(sqlcode).to_be_between(-31013,-31011); - end; - end; - - procedure cursor_unorderd_compr_success is - l_actual SYS_REFCURSOR; - l_expected SYS_REFCURSOR; - begin - --Arrange - open l_actual for select username , user_id from all_users order by username asc; - open l_expected for select username , user_id from all_users order by username desc; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).unordered; - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure cursor_unordered_compare_fail is - l_actual SYS_REFCURSOR; - l_expected SYS_REFCURSOR; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_actual for select 'test1' username,-100 user_id from dual - union all - select 'test' username,-666 user_id from dual - order by 1 asc; - - open l_expected for select 'test1' username,-100 user_id from dual - union all - select 'test' username,-667 user_id from dual - order by 1 desc; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).unordered; - l_expected_message := q'[%Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ]% -%Diff:% -%Rows: [ 2 differences ]% -%Extra: test-666% -%Missing: test-667%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure cursor_joinby_compare is - l_actual SYS_REFCURSOR; - l_expected SYS_REFCURSOR; - begin - --Arrange - open l_actual for select owner, object_name,object_type from all_objects where owner = user - order by 1,2,3 asc; - open l_expected for select owner, object_name,object_type from all_objects where owner = user - order by 1,2,3 desc; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by('OWNER'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure cursor_joinby_compare_twocols is - l_actual SYS_REFCURSOR; - l_expected SYS_REFCURSOR; - begin - --Arrange - open l_actual for select owner, object_name,object_type from all_objects where owner = user - order by 1,2,3 asc; - open l_expected for select owner, object_name,object_type from all_objects where owner = user - order by 1,2,3 desc; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by(ut3.ut_varchar2_list('OWNER,OBJECT_NAME')); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure cursor_joinby_compare_nokey is - l_actual SYS_REFCURSOR; - l_expected SYS_REFCURSOR; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_actual for select rownum as rn, 'x' SOME_COL from dual a connect by level < 4; - open l_expected for select rownum as rn, 'x' SOME_COL from dual a connect by level < 4; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by('OWNER'); - --Assert - l_expected_message := q'[%Actual: refcursor [ count = 3 ] was expected to equal: refcursor [ count = 3 ]% -Diff:% -%Unable to join sets:% -%Join key OWNER does not exists in expected% -%Join key OWNER does not exists in actual%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure cur_joinby_comp_twocols_nokey is - l_actual SYS_REFCURSOR; - l_expected SYS_REFCURSOR; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_actual for select rownum as rn, 'x' SOME_COL from dual a connect by level < 4; - open l_expected for select rownum as rn, 'x' SOME_COL from dual a connect by level < 4; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by(ut3.ut_varchar2_list('OWNER,USER_ID')); - --Assert - l_expected_message := q'[%Actual: refcursor [ count = 3 ] was expected to equal: refcursor [ count = 3 ]% -Diff:% -%Unable to join sets:% -%Join key OWNER does not exists in expected% -%Join key USER_ID does not exists in expected% -%Join key OWNER does not exists in actual% -%Join key USER_ID does not exists in actual%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure cursor_joinby_compare_exkey is - l_actual SYS_REFCURSOR; - l_expected SYS_REFCURSOR; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_actual for select rownum as rn, 'x' SOME_COL from dual a connect by level < 4; - open l_expected for select rownum as rn, 'x' SOME_COL from dual a connect by level < 4; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by('SOME_COL').exclude('SOME_COL'); - --Assert - l_expected_message := q'[%Actual: refcursor [ count = 3 ] was expected to equal: refcursor [ count = 3 ]% -Diff:% -%Unable to join sets:% -%Join key SOME_COL does not exists in expected% -%Join key SOME_COL does not exists in actual%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure cur_joinby_comp_twocols_exkey is - l_actual SYS_REFCURSOR; - l_expected SYS_REFCURSOR; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_actual for select rownum as rn, 'x' SOME_COL from dual a connect by level < 4; - open l_expected for select rownum as rn, 'x' SOME_COL from dual a connect by level < 4; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by(ut3.ut_varchar2_list('RN,SOME_COL')).exclude('RN'); - --Assert - l_expected_message := q'[%Actual: refcursor [ count = 3 ] was expected to equal: refcursor [ count = 3 ]% -Diff:% -%Unable to join sets:% -%Join key RN does not exists in expected% -%Join key RN does not exists in actual%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure cursor_joinby_comp_nokey_ex is - l_actual SYS_REFCURSOR; - l_expected SYS_REFCURSOR; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_actual for select rownum as rni, 'x' SOME_COL from dual a connect by level < 4; - open l_expected for select rownum as rn, 'x' SOME_COL from dual a connect by level < 4; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by('RNI'); - --Assert - l_expected_message := q'[%Actual: refcursor [ count = 3 ] was expected to equal: refcursor [ count = 3 ]% -Diff:% -%Unable to join sets:% -%Join key RNI does not exists in expected%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure cursor_joinby_comp_nokey_ac is - l_actual SYS_REFCURSOR; - l_expected SYS_REFCURSOR; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_actual for select rownum as rn, 'x' SOME_COL from dual a connect by level < 4; - open l_expected for select rownum as rni, 'x' SOME_COL from dual a connect by level < 4; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by('RNI'); - --Assert - l_expected_message := q'[%Actual: refcursor [ count = 3 ] was expected to equal: refcursor [ count = 3 ]% -Diff:% -%Unable to join sets:% -%Join key RNI does not exists in actual%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure cursor_joinby_compare_1000 is - l_actual SYS_REFCURSOR; - l_expected SYS_REFCURSOR; - begin - --Arrange - open l_actual for select object_name from all_objects where rownum <=1100; - open l_expected for select object_name from all_objects where rownum <=1100; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by('OBJECT_NAME'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure cursor_joinby_compare_fail is - l_actual SYS_REFCURSOR; - l_expected SYS_REFCURSOR; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_expected for select username, user_id from all_users union all - select 'TEST' username, -600 user_id from dual order by 1 desc; - - open l_actual for select username, user_id from all_users union all - select 'TEST' username, -610 user_id from dual order by 1 asc; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by('USERNAME'); - --Assert - l_expected_message := q'[%Actual: refcursor [ count = % ] was expected to equal: refcursor [ count = % ] -%Diff:% -%Rows: [ 1 differences ]% -%PK TEST - Actual:%-610% -%PK TEST - Expected:%-600%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure cursor_joinby_cmp_twocol_fail is - l_actual SYS_REFCURSOR; - l_expected SYS_REFCURSOR; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_expected for select username, user_id from all_users union all - select 'TEST' username, -600 user_id from dual order by 1 desc; - - open l_actual for select username, user_id from all_users union all - select 'TEST' username, -610 user_id from dual order by 1 asc; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by(ut3.ut_varchar2_list('USERNAME,USER_ID')); - --Assert - l_expected_message := q'[%Actual: refcursor [ count = % ] was expected to equal: refcursor [ count = % ] -%Diff:% -%Rows: [ 2 differences ]% -%PK TEST-610 - Extra% -%PK TEST-600 - Missing%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure cur_joinby_cmp_threcol_fail is - l_actual SYS_REFCURSOR; - l_expected SYS_REFCURSOR; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_expected for select username, user_id,'Y' is_valid from all_users union all - select 'TEST' username, -600 user_id,'Y' is_valid from dual order by 1 desc; - - open l_actual for select username, user_id,'Y' is_valid from all_users union all - select 'TEST' username, -610 user_id,'Y' is_valid from dual order by 1 asc; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by(ut3.ut_varchar2_list('USERNAME,IS_VALID')); - --Assert - l_expected_message := q'[%Actual: refcursor [ count = % ] was expected to equal: refcursor [ count = % ] -%Diff:% -%Rows: [ 1 differences ]% -%PK TESTY - Actual:%-610% -%PK TESTY - Expected:%-600%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure unord_incl_cols_as_list - as - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; - open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).include(ut3.ut_varchar2_list('RN','//A_Column','SOME_COL')).unordered; - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure joinby_incl_cols_as_list - as - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; - open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).include(ut3.ut_varchar2_list('RN','//A_Column','SOME_COL')).join_by('SOME_COL'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure joinby_excl_cols_as_list - as - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; - open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).exclude(ut3.ut_varchar2_list('//Some_Col','A_COLUMN')).join_by('SOME_COL'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure unord_excl_cols_as_list - as - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; - open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).exclude(ut3.ut_varchar2_list('A_COLUMN|//Some_Col')).unordered; - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure excl_dif_cols_as_list - as - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select rownum as rn, 'TEST' as A_COLUMN from dual a connect by level < 4; - open l_expected for select rownum as rn, 1 as A_COLUMN from dual a connect by level < 4; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).exclude(ut3.ut_varchar2_list('A_COLUMN')); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure inlc_dif_cols_as_list - as - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select rownum as rn, 'TEST' as A_COLUMN from dual a connect by level < 4; - open l_expected for select rownum as rn, 1 as A_COLUMN from dual a connect by level < 4; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).include(ut3.ut_varchar2_list('RN')); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure inlc_exc_dif_cols_as_list - as - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select rownum as rn, 'TEST' as A_COLUMN from dual a connect by level < 4; - open l_expected for select rownum as rn, 1 as A_COLUMN from dual a connect by level < 4; - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).include(ut3.ut_varchar2_list('RN')).exclude(ut3.ut_varchar2_list('A_COLUMN')); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure compare_obj_typ_col_un is - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select test_dummy_object( rownum, 'Something '||rownum, rownum) as colval - from dual connect by level <=2 order by rownum asc; - - open l_expected for select test_dummy_object( rownum, 'Something '||rownum, rownum) as colval - from dual connect by level <=2 order by rownum desc; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).unordered; - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure compare_obj_typ_col_jb is - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select test_dummy_object( rownum, 'Something '||rownum, rownum) as colval - from dual connect by level <=2 order by rownum asc; - - open l_expected for select test_dummy_object( rownum, 'Something '||rownum, rownum) as colval - from dual connect by level <=2 order by rownum desc; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by('COLVAL/ID'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure comp_obj_typ_col_un_fail is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_expected_message varchar2(32767); - l_actual_message varchar2(32767); - begin - --Arrange - open l_actual for select test_dummy_object( rownum, 'Something '||rownum, rownum) as colval - from dual connect by level <=2 order by rownum asc; - - open l_expected for select test_dummy_object( rownum, 'Somethings '||rownum, rownum) as colval - from dual connect by level <=3 order by rownum desc; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).unordered; - l_expected_message := q'[%Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 3 ]% -Diff:% -Rows: [ 5 differences ] -%Extra: 2Something 22% -%Extra: 1Something 11% -%Missing: 1Somethings 11% -%Missing: 2Somethings 22% -%Missing: 3Somethings 33%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure comp_obj_typ_col_jb_fail is - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select test_dummy_object( rownum, 'Something '||rownum, rownum) as colval - from dual connect by level <=2 order by rownum asc; - - open l_expected for select test_dummy_object( rownum, 'Somethings '||rownum, rownum) as colval - from dual connect by level <=2 order by rownum desc; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by('COLVAL/ID'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_not_null(); - end; - - procedure comp_obj_typ_col_jb_multi is - l_actual sys_refcursor; - l_expected sys_refcursor; - begin - --Arrange - open l_actual for select rownum as rn,test_dummy_object( rownum, 'Something '||rownum, rownum) as colval - from dual connect by level <=2 order by rownum asc; - - open l_expected for select rownum as rn,test_dummy_object( rownum, 'Something '||rownum, rownum) as colval - from dual connect by level <=2 order by rownum desc; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by(ut3.ut_varchar2_list('RN,COLVAL/ID')); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure comp_obj_typ_col_jb_nokey is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_expected_message varchar2(32767); - l_actual_message varchar2(32767); - begin - --Arrange - open l_actual for select test_dummy_object( rownum, 'Something '||rownum, rownum) as colval - from dual connect by level <=2 order by rownum asc; - - open l_expected for select test_dummy_object( rownum, 'Something '||rownum, rownum) as colval - from dual connect by level <=2 order by rownum desc; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by('COLVAL/IDS'); - - l_expected_message := q'[%Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ]% -Diff:% -%Unable to join sets:% -%Join key COLVAL/IDS does not exists in expected% -%Join key COLVAL/IDS does not exists in actual%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure compare_nest_tab_col_jb is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_actual_tab ut3.ut_key_value_pairs := ut3.ut_key_value_pairs(); - l_expected_tab ut3.ut_key_value_pairs := ut3.ut_key_value_pairs(); - l_expected_message varchar2(32767); - l_actual_message varchar2(32767); - begin - select ut3.ut_key_value_pair(rownum,'Something '||rownum) - bulk collect into l_actual_tab - from dual connect by level <=2; - - select ut3.ut_key_value_pair(rownum,'Something '||rownum) - bulk collect into l_expected_tab - from dual connect by level <=2; - - --Arrange - open l_actual for select key,value - from table(l_actual_tab) order by 1 asc; - - open l_expected for select key,value - from table(l_expected_tab) order by 1 desc; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by('KEY'); - - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure compare_nest_tab_col_jb_fail is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_actual_tab ut3.ut_key_value_pairs := ut3.ut_key_value_pairs(); - l_expected_tab ut3.ut_key_value_pairs := ut3.ut_key_value_pairs(); - l_expected_message varchar2(32767); - l_actual_message varchar2(32767); - begin - select ut3.ut_key_value_pair(rownum,'Something '||rownum) - bulk collect into l_actual_tab - from dual connect by level <=2; - - select ut3.ut_key_value_pair(rownum,'Somethings '||rownum) - bulk collect into l_expected_tab - from dual connect by level <=2; - - --Arrange - open l_actual for select key,value - from table(l_actual_tab) order by 1 asc; - - open l_expected for select key,value - from table(l_expected_tab) order by 1 desc; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by('KEY'); - l_expected_message := q'[%Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ]% -%Diff:% -%Rows: [ 2 differences ]% -%PK % - Actual: %% -%PK % - Expected: %% -%PK % - Actual: %% -%PK % - Expected: %%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure compare_nest_tab_cols_jb is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_actual_tab ut3.ut_key_value_pairs := ut3.ut_key_value_pairs(); - l_expected_tab ut3.ut_key_value_pairs := ut3.ut_key_value_pairs(); - l_expected_message varchar2(32767); - l_actual_message varchar2(32767); - begin - select ut3.ut_key_value_pair(rownum,'Something '||rownum) - bulk collect into l_actual_tab - from dual connect by level <=2; - - select ut3.ut_key_value_pair(rownum,'Something '||rownum) - bulk collect into l_expected_tab - from dual connect by level <=2; - - --Arrange - open l_actual for select key,value - from table(l_actual_tab) order by 1 asc; - - open l_expected for select key,value - from table(l_expected_tab) order by 1 desc; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by(ut3.ut_varchar2_list('KEY,VALUE')); - - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure compare_nest_tab_cols_jb_fail is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_actual_tab ut3.ut_key_value_pairs := ut3.ut_key_value_pairs(); - l_expected_tab ut3.ut_key_value_pairs := ut3.ut_key_value_pairs(); - l_expected_message varchar2(32767); - l_actual_message varchar2(32767); - begin - select ut3.ut_key_value_pair(rownum,'Something '||rownum) - bulk collect into l_actual_tab - from dual connect by level <=2; - - select ut3.ut_key_value_pair(rownum,'Somethings '||rownum) - bulk collect into l_expected_tab - from dual connect by level <=2; - - --Arrange - open l_actual for select key,value - from table(l_actual_tab) order by 1 asc; - - open l_expected for select key,value - from table(l_expected_tab) order by 1 desc; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by(ut3.ut_varchar2_list('KEY,VALUE')); - l_expected_message := q'[%Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ]% -%Diff:% -%Rows: [ 4 differences ]% -%PK %% - Extra% -%PK %% - Extra% -%PK %% - Missing% -%PK %% - Missing%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure compare_tabtype_as_cols_jb is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_actual_tab ut3.ut_key_value_pairs := ut3.ut_key_value_pairs(); - l_expected_tab ut3.ut_key_value_pairs := ut3.ut_key_value_pairs(); - l_expected_message varchar2(32767); - l_actual_message varchar2(32767); - begin - select ut3.ut_key_value_pair(rownum,'Something '||rownum) - bulk collect into l_actual_tab - from dual connect by level <=2; - - select ut3.ut_key_value_pair(rownum,'Somethings '||rownum) - bulk collect into l_expected_tab - from dual connect by level <=2; - - --Arrange - open l_actual for select rownum rn, l_actual_tab as nested_table - from dual connect by level <=2; - - open l_expected for select rownum rn, l_expected_tab as nested_table - from dual connect by level <=2; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by('NESTED_TABLE'); - - --Assert - l_expected_message := q'[%Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ]% -%Diff:% -%Rows: [ 2 differences ]% -%PK %%%%%%%%%%%%%Extra%%% -%PK %%%%%%%%%%%%%Extra%%% -%PK %%%%%%%%%%%%%Missing%%% -%PK %%%%%%%%%%%%%Missing%%%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - - end; - - procedure compare_tabtype_as_cols is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_actual_tab ut3.ut_key_value_pairs := ut3.ut_key_value_pairs(); - l_expected_tab ut3.ut_key_value_pairs := ut3.ut_key_value_pairs(); - l_expected_message varchar2(32767); - l_actual_message varchar2(32767); - begin - select ut3.ut_key_value_pair(rownum,'Something '||rownum) - bulk collect into l_actual_tab - from dual connect by level <=2 order by rownum asc; - - select ut3.ut_key_value_pair(rownum,'Something '||rownum) - bulk collect into l_expected_tab - from dual connect by level <=2 order by rownum asc; - - --Arrange - open l_actual for select rownum rn, l_actual_tab as nested_table - from dual connect by level <=2; - - open l_expected for select rownum rn, l_expected_tab as nested_table - from dual connect by level <=2; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - - end; - - procedure compare_tabtype_as_cols_coll is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_actual_tab ut3.ut_key_value_pairs := ut3.ut_key_value_pairs(); - l_expected_tab ut3.ut_key_value_pairs := ut3.ut_key_value_pairs(); - l_expected_message varchar2(32767); - l_actual_message varchar2(32767); - begin - select ut3.ut_key_value_pair(rownum,'Something '||rownum) - bulk collect into l_actual_tab - from dual connect by level <=2; - - select ut3.ut_key_value_pair(rownum,'Somethings '||rownum) - bulk collect into l_expected_tab - from dual connect by level <=2; - - --Arrange - open l_actual for select rownum rn, l_actual_tab as nested_table - from dual connect by level <=2; - - open l_expected for select rownum rn, l_expected_tab as nested_table - from dual connect by level <=2; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by('NESTED_TABLE/UT_KEY_VALUE_PAIR'); - - --Assert - l_expected_message := q'[%Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ] -%Diff: -%Unable to join sets: -%Join key NESTED_TABLE/UT_KEY_VALUE_PAIR does not exists in expected% -%Join key NESTED_TABLE/UT_KEY_VALUE_PAIR does not exists in actual% -%Please make sure that your join clause is not refferring to collection element%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - - end; - - procedure compare_rec_colltype_as_cols is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_actual_tab ut3.ut_annotated_object; - l_expected_tab ut3.ut_annotated_object; - l_expected_message varchar2(32767); - l_actual_message varchar2(32767); - begin - select ut3.ut_annotated_object('TEST','TEST','TEST', - 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', - ut3.ut_annotations(ut3.ut_annotation(1,'test','test','test'), - ut3.ut_annotation(2,'test','test','test')) - ) - into l_expected_tab from dual; - - --Arrange - open l_actual for select l_actual_tab as nested_table from dual; - - open l_expected for select l_expected_tab as nested_table from dual; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by('NESTED_TABLE'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - - end; - - procedure compare_rec_colltype_as_attr is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_actual_tab ut3.ut_annotated_object; - l_expected_tab ut3.ut_annotated_object; - l_expected_message varchar2(32767); - l_actual_message varchar2(32767); - begin - select ut3.ut_annotated_object('TEST','TEST','TEST', - 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', - ut3.ut_annotations(ut3.ut_annotation(1,'test','test','test'), - ut3.ut_annotation(2,'test','test','test')) - ) - into l_expected_tab from dual; - - --Arrange - open l_actual for select l_actual_tab as nested_table from dual; - - open l_expected for select l_expected_tab as nested_table from dual; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by('NESTED_TABLE/OBJECT_OWNER'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - - end; - - procedure compare_collection_in_rec is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_actual_tab ut3.ut_annotated_object; - l_expected_tab ut3.ut_annotated_object; - l_expected_message varchar2(32767); - l_actual_message varchar2(32767); - begin - select ut3.ut_annotated_object('TEST','TEST','TEST', - 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', - ut3.ut_annotations(ut3.ut_annotation(1,'test','test','test'), - ut3.ut_annotation(2,'test','test','test')) - ) - into l_expected_tab from dual; - - --Arrange - open l_actual for select l_actual_tab as nested_table from dual; - - open l_expected for select l_expected_tab as nested_table from dual; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by('NESTED_TABLE/ANNOTATIONS'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - - end; - - procedure compare_rec_coll_as_cols_fl is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_actual_tab ut3.ut_annotated_object; - l_expected_tab ut3.ut_annotated_object; - l_expected_message varchar2(32767); - l_actual_message varchar2(32767); - begin - select ut3.ut_annotated_object('TEST','TEST','TEST', - 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', - ut3.ut_annotations(ut3.ut_annotation(1,'1test','test','test'), - ut3.ut_annotation(2,'test','test','test')) - ) - into l_expected_tab - from dual; - - --Arrange - open l_actual for select rownum rn, l_actual_tab as nested_table - from dual; - - open l_expected for select rownum rn, l_expected_tab as nested_table - from dual; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by('NESTED_TABLE/OBJECT_OWNER'); - - --Assert - 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%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - --ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure compare_rec_coll_as_join is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_actual_tab ut3.ut_annotated_object; - l_expected_tab ut3.ut_annotated_object; - l_expected_message varchar2(32767); - l_actual_message varchar2(32767); - begin - select ut3.ut_annotated_object('TEST','TEST','TEST', - 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', - ut3.ut_annotations(ut3.ut_annotation(1,'test','test','test'), - ut3.ut_annotation(2,'test','test','test')) - ) - into l_expected_tab from dual; - - --Arrange - open l_actual for select l_actual_tab as nested_table from dual; - - open l_expected for select l_expected_tab as nested_table from dual; - - --Act - ut3.ut.expect(l_actual).to_equal(l_expected).join_by('NESTED_TABLE/ANNOTATIONS/TEXT'); - - --Assert - l_expected_message := q'[%Actual: refcursor [ count = 1 ] was expected to equal: refcursor [ count = 1 ]% -%Diff:% -%Unable to join sets:% -%Join key NESTED_TABLE/ANNOTATIONS/TEXT does not exists in expected% -%Join key NESTED_TABLE/ANNOTATIONS/TEXT does not exists in actual% -%Please make sure that your join clause is not refferring to collection element%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - - end; - -end; -/ diff --git a/test/core/expectations/unary/test_expect_not_to_be_null.pkb b/test/core/expectations/unary/test_expect_not_to_be_null.pkb deleted file mode 100644 index 45ce4f697..000000000 --- a/test/core/expectations/unary/test_expect_not_to_be_null.pkb +++ /dev/null @@ -1,265 +0,0 @@ -create or replace package body test_expect_not_to_be_null -is - gc_object_name constant varchar2(30) := 't_not_to_be_null_test'; - gc_nested_table_name constant varchar2(30) := 'tt_not_to_be_null_test'; - gc_varray_name constant varchar2(30) := 'tv_not_to_be_null_test'; - - procedure cleanup_expectations is - begin - expectations.cleanup_expectations( ); - end; - - procedure create_types is - pragma autonomous_transaction; - begin - execute immediate 'create type ' || gc_object_name || ' is object (dummy number)'; - execute immediate 'create type ' || gc_nested_table_name || ' is table of number'; - execute immediate 'create type ' || gc_varray_name || ' is varray(1) of number'; - end; - - procedure drop_types is - pragma autonomous_transaction; - begin - execute immediate 'drop type ' || gc_object_name; - execute immediate 'drop type ' || gc_nested_table_name; - execute immediate 'drop type ' || gc_varray_name; - end; - - procedure blob_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block( 'not_to_be_null', 'blob', 'to_blob(''abc'')' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure blob_0_length is - begin - --Act - execute immediate expectations.unary_expectation_block( 'not_to_be_null', 'blob', 'empty_blob()' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure boolean_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block( 'not_to_be_null', 'boolean', 'true' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure clob_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block( 'not_to_be_null', 'clob', 'to_clob(''abc'')' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - - procedure clob_0_length is - begin - --Act - execute immediate expectations.unary_expectation_block( 'not_to_be_null', 'clob', 'empty_clob()' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure date_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block( 'not_to_be_null', 'date', 'sysdate' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure number_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block( 'not_to_be_null', 'number', '1234' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure timestamp_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block( 'not_to_be_null', 'timestamp', 'systimestamp' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure timestamp_with_ltz_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block( - 'not_to_be_null', 'timestamp with local time zone', 'systimestamp' - ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure timestamp_with_tz_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block( 'not_to_be_null', 'timestamp with time zone', - 'systimestamp' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure varchar2_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block( 'not_to_be_null', 'varchar2(4000)', '''abc''' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure initialized_object is - begin - --Act - execute immediate expectations.unary_expectation_object_block( - 'not_to_be_null', gc_object_name, gc_object_name || '(1)', 'object' - ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure initialized_nested_table is - begin - --Act - execute immediate expectations.unary_expectation_object_block( - 'not_to_be_null', gc_nested_table_name, gc_nested_table_name || '()', 'collection' - ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure initialized_varray is - begin - --Act - execute immediate expectations.unary_expectation_object_block( - 'not_to_be_null', gc_varray_name, gc_varray_name || '()', 'collection' - ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure null_blob is - begin - --Act - execute immediate expectations.unary_expectation_block( 'not_to_be_null', 'blob', 'null' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure null_boolean is - begin - --Act - execute immediate expectations.unary_expectation_block( 'not_to_be_null', 'boolean', 'null' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure null_clob is - begin - --Act - execute immediate expectations.unary_expectation_block( 'not_to_be_null', 'clob', 'null' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure null_date is - begin - --Act - execute immediate expectations.unary_expectation_block( 'not_to_be_null', 'date', 'null' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure null_number is - begin - --Act - execute immediate expectations.unary_expectation_block( 'not_to_be_null', 'number', 'null' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure null_timestamp is - begin - --Act - execute immediate expectations.unary_expectation_block( 'not_to_be_null', 'timestamp', 'null' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure null_timestamp_with_ltz is - begin - --Act - execute immediate expectations.unary_expectation_block( - 'not_to_be_null', 'timestamp with local time zone', 'null' - ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure null_timestamp_with_tz is - begin - --Act - execute immediate expectations.unary_expectation_block( - 'not_to_be_null', 'timestamp with time zone', 'null' - ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure null_varchar2 is - begin - --Act - execute immediate expectations.unary_expectation_block( 'not_to_be_null', 'varchar2(4000)', 'null' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure null_anydata is - begin - --Act - execute immediate expectations.unary_expectation_block( 'not_to_be_null', 'anydata', 'null' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure uninit_object_in_anydata is - begin - --Act - execute immediate expectations.unary_expectation_object_block( - 'not_to_be_null', gc_object_name, 'null', 'object' - ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure uninit_nested_table_in_anydata is - begin - --Act - execute immediate expectations.unary_expectation_object_block( - 'not_to_be_null', gc_nested_table_name, 'null', 'collection' - ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure uninit_varray_in_anydata is - begin - --Act - execute immediate expectations.unary_expectation_object_block( - 'not_to_be_null', gc_varray_name, 'null', 'collection' - ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - -end test_expect_not_to_be_null; -/ diff --git a/test/core/expectations/unary/test_expect_to_be_empty.pkb b/test/core/expectations/unary/test_expect_to_be_empty.pkb deleted file mode 100644 index ef4c34c12..000000000 --- a/test/core/expectations/unary/test_expect_to_be_empty.pkb +++ /dev/null @@ -1,267 +0,0 @@ -create or replace package body test_expect_to_be_empty is - - procedure cleanup_expectations is - begin - expectations.cleanup_expectations( ); - end; - - procedure success_be_empty_cursor is - l_cursor sys_refcursor; - begin - --Arrange - open l_cursor for select * from dual where 1 = 2; - --Act - ut3.ut.expect(l_cursor).to_be_empty; - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure fail_be_empty_cursor is - l_cursor sys_refcursor; - begin - --Arrange - open l_cursor for select * from dual; - --Act - ut3.ut.expect(l_cursor).to_be_empty; - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_be_empty_cursor_report is - l_cursor sys_refcursor; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_cursor for select * from dual; - --Act - ut3.ut.expect(l_cursor).to_be_empty; - - l_expected_message := q'[Actual: (refcursor [ count = 1 ])% - X% -was expected to be empty%%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure success_not_be_empty_cursor is - l_cursor sys_refcursor; - begin - --Arrange - open l_cursor for select * from dual; - --Act - ut3.ut.expect(l_cursor).not_to_be_empty; - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure fail_not_be_empty_cursor is - l_cursor sys_refcursor; - begin - --Arrange - open l_cursor for select * from dual where 1 = 2; - --Act - ut3.ut.expect(l_cursor).not_to_be_empty; - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure success_be_empty_collection is - l_actual anydata; - begin - --Arrange - l_actual := anydata.convertcollection(ora_mining_varchar2_nt()); - -- Act - ut3.ut.expect(l_actual).to_be_empty(); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure fail_be_empty_collection is - l_actual anydata; - begin - --Arrange - l_actual := anydata.convertcollection(ora_mining_varchar2_nt('a')); - -- Act - ut3.ut.expect(l_actual).to_be_empty(); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure success_not_be_empty_coll is - l_actual anydata; - begin - --Arrange - l_actual := anydata.convertcollection(ora_mining_varchar2_nt('a')); - -- Act - ut3.ut.expect(l_actual).not_to_be_empty(); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure fail_not_be_empty_collection is - l_actual anydata; - begin - --Arrange - l_actual := anydata.convertcollection(ora_mining_varchar2_nt()); - -- Act - ut3.ut.expect(l_actual).not_to_be_empty(); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_be_empty_null_collection is - l_actual anydata; - l_data ora_mining_varchar2_nt; - begin - --Arrange - l_actual := anydata.convertcollection(l_data); - -- Act - ut3.ut.expect(l_actual).to_be_empty(); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_not_be_empty_null_coll is - l_actual anydata; - l_data ora_mining_varchar2_nt; - begin - --Arrange - l_actual := anydata.convertcollection(l_data); - -- Act - ut3.ut.expect(l_actual).not_to_be_empty(); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_be_empty_object is - l_actual anydata; - begin - --Arrange - l_actual := anydata.convertObject(ut3.ut_data_value_number(1)); - -- Act - ut3.ut.expect(l_actual).to_be_empty(); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_be_empty_null_object is - l_actual anydata; - l_data ut3.ut_data_value_number; - begin - --Arrange - l_actual := anydata.convertObject(l_data); - -- Act - ut3.ut.expect(l_actual).to_be_empty(); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_be_empty_number is - begin - -- Act - ut3.ut.expect( 1 ).to_( ut3.be_empty() ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_not_be_empty_object is - l_actual anydata; - begin - --Arrange - l_actual := anydata.convertObject(ut3.ut_data_value_number(1)); - -- Act - ut3.ut.expect(l_actual).not_to_be_empty(); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_not_be_empty_null_object is - l_actual anydata; - l_data ut3.ut_data_value_number; - begin - --Arrange - l_actual := anydata.convertObject(l_data); - -- Act - ut3.ut.expect(l_actual).not_to_be_empty(); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_not_be_empty_number is - begin - -- Act - ut3.ut.expect( 1 ).not_to( ut3.be_empty() ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure success_be_empty_clob is - begin - -- Act - ut3.ut.expect( empty_clob() ).to_( ut3.be_empty() ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure fail_be_empty_clob is - begin - -- Act - ut3.ut.expect( to_clob(' ') ).to_( ut3.be_empty() ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure success_be_empty_blob is - begin - -- Act - ut3.ut.expect( empty_blob() ).to_( ut3.be_empty() ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure fail_be_empty_blob is - begin - -- Act - ut3.ut.expect( to_blob('AA') ).to_( ut3.be_empty() ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - - procedure fail_not_be_empty_clob is - begin - -- Act - ut3.ut.expect( empty_clob() ).not_to( ut3.be_empty() ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure success_not_be_empty_clob is - begin - -- Act - ut3.ut.expect( to_clob(' ') ).not_to( ut3.be_empty() ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure fail_not_be_empty_blob is - begin - -- Act - ut3.ut.expect( empty_blob() ).not_to( ut3.be_empty() ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure success_not_be_empty_blob is - begin - -- Act - ut3.ut.expect( to_blob('AA') ).not_to( ut3.be_empty() ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - -end; -/ \ No newline at end of file diff --git a/test/core/expectations/unary/test_expect_to_be_not_null.pkb b/test/core/expectations/unary/test_expect_to_be_not_null.pkb deleted file mode 100644 index be6b3f2f8..000000000 --- a/test/core/expectations/unary/test_expect_to_be_not_null.pkb +++ /dev/null @@ -1,264 +0,0 @@ -create or replace package body test_expect_to_be_not_null -is - gc_object_name constant varchar2(30) := 't_to_be_not_null_test'; - gc_nested_table_name constant varchar2(30) := 'tt_to_be_not_null_test'; - gc_varray_name constant varchar2(30) := 'tv_to_be_not_null_test'; - - procedure cleanup_expectations is - begin - expectations.cleanup_expectations(); - end; - - procedure create_types is - pragma autonomous_transaction; - begin - execute immediate 'create type '||gc_object_name||' is object (dummy number)'; - execute immediate 'create type '||gc_nested_table_name||' is table of number'; - execute immediate 'create type '||gc_varray_name||' is varray(1) of number'; - end; - - procedure drop_types is - pragma autonomous_transaction; - begin - execute immediate 'drop type '||gc_object_name; - execute immediate 'drop type '||gc_nested_table_name; - execute immediate 'drop type '||gc_varray_name; - end; - - procedure blob_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block('to_be_not_null', 'blob', 'to_blob(''abc'')'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure empty_blob is - begin - --Act - execute immediate expectations.unary_expectation_block('to_be_not_null', 'blob', 'empty_blob()'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure boolean_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block('to_be_not_null', 'boolean', 'true'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure clob_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block('to_be_not_null', 'clob', 'to_clob(''abc'')'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure empty_clob is - begin - --Act - execute immediate expectations.unary_expectation_block('to_be_not_null', 'clob', 'empty_clob()'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure date_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block('to_be_not_null', 'date', 'sysdate'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure number_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block('to_be_not_null', 'number', '1234'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure timestamp_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block('to_be_not_null', 'timestamp', 'systimestamp'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure timestamp_with_ltz_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block('to_be_not_null', 'timestamp with local time zone', 'systimestamp'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure timestamp_with_tz_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block('to_be_not_null', 'timestamp with time zone', 'systimestamp'); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure varchar2_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block('to_be_not_null', 'varchar2(4000)', '''abc'''); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure initialized_object is - begin - --Act - execute immediate expectations.unary_expectation_object_block( - 'to_be_not_null', gc_object_name, gc_object_name||'(1)', 'object' - ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure initialized_nested_table is - begin - --Act - execute immediate expectations.unary_expectation_object_block( - 'to_be_not_null', gc_nested_table_name, gc_nested_table_name||'()', 'collection' - ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure initialized_varray is - begin - --Act - execute immediate expectations.unary_expectation_object_block( - 'to_be_not_null', gc_varray_name, gc_varray_name||'()', 'collection' - ); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure null_blob is - begin - --Act - execute immediate expectations.unary_expectation_block('to_be_not_null', 'blob', 'null'); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure null_boolean is - begin - --Act - execute immediate expectations.unary_expectation_block('to_be_not_null', 'boolean', 'null'); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - - procedure null_clob is - begin - --Act - execute immediate expectations.unary_expectation_block('to_be_not_null', 'clob', 'null'); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - - procedure null_date is - begin - --Act - execute immediate expectations.unary_expectation_block('to_be_not_null', 'date', 'null'); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - - procedure null_number is - begin - --Act - execute immediate expectations.unary_expectation_block('to_be_not_null', 'number', 'null'); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - - procedure null_timestamp is - begin - --Act - execute immediate expectations.unary_expectation_block('to_be_not_null', 'timestamp', 'null'); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - - procedure null_timestamp_with_ltz is - begin - --Act - execute immediate expectations.unary_expectation_block('to_be_not_null', 'timestamp with local time zone', 'null'); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - - procedure null_timestamp_with_tz is - begin - --Act - execute immediate expectations.unary_expectation_block('to_be_not_null', 'timestamp with time zone', 'null'); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - - procedure null_varchar2 is - begin - --Act - execute immediate expectations.unary_expectation_block('to_be_not_null', 'varchar2(4000)', 'null'); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure null_anydata is - begin - --Act - execute immediate expectations.unary_expectation_block('to_be_not_null', 'anydata', 'null'); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure uninit_object_in_anydata is - begin - --Act - execute immediate expectations.unary_expectation_object_block( - 'to_be_not_null', gc_object_name, 'null', 'object' - ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure uninit_nested_table_in_anydata is - begin - --Act - execute immediate expectations.unary_expectation_object_block( - 'to_be_not_null', gc_nested_table_name, 'null', 'collection' - ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure uninit_varray_in_anydata is - begin - --Act - execute immediate expectations.unary_expectation_object_block( - 'to_be_not_null', gc_varray_name, 'null', 'collection' - ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - -end test_expect_to_be_not_null; -/ diff --git a/test/core/expectations/unary/test_expect_to_be_null.pkb b/test/core/expectations/unary/test_expect_to_be_null.pkb deleted file mode 100644 index 4179bfbe6..000000000 --- a/test/core/expectations/unary/test_expect_to_be_null.pkb +++ /dev/null @@ -1,260 +0,0 @@ -create or replace package body test_expect_to_be_null -is - gc_object_name constant varchar2(30) := 't_to_be_null_test'; - gc_nested_table_name constant varchar2(30) := 'tt_to_be_null_test'; - gc_varray_name constant varchar2(30) := 'tv_to_be_null_test'; - - procedure cleanup_expectations is - begin - expectations.cleanup_expectations( ); - end; - - procedure create_types is - pragma autonomous_transaction; - begin - execute immediate 'create type ' || gc_object_name || ' is object (dummy number)'; - execute immediate 'create type ' || gc_nested_table_name || ' is table of number'; - execute immediate 'create type ' || gc_varray_name || ' is varray(1) of number'; - end; - - procedure drop_types is - pragma autonomous_transaction; - begin - execute immediate 'drop type ' || gc_object_name; - execute immediate 'drop type ' || gc_nested_table_name; - execute immediate 'drop type ' || gc_varray_name; - end; - - procedure null_blob is - begin - --Act - execute immediate expectations.unary_expectation_block( 'to_be_null', 'blob', 'null' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure null_boolean is - begin - --Act - execute immediate expectations.unary_expectation_block( 'to_be_null', 'boolean', 'null' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure null_clob is - begin - --Act - execute immediate expectations.unary_expectation_block( 'to_be_null', 'clob', 'null' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure null_date is - begin - --Act - execute immediate expectations.unary_expectation_block( 'to_be_null', 'date', 'null' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure null_number is - begin - --Act - execute immediate expectations.unary_expectation_block( 'to_be_null', 'number', 'null' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure null_timestamp is - begin - --Act - execute immediate expectations.unary_expectation_block( 'to_be_null', 'timestamp', 'null' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure null_timestamp_with_ltz is - begin - --Act - execute immediate expectations.unary_expectation_block( 'to_be_null', 'timestamp with local time zone', 'null' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure null_timestamp_with_tz is - begin - --Act - execute immediate expectations.unary_expectation_block( 'to_be_null', 'timestamp with time zone', 'null' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure null_varchar2 is - begin - --Act - execute immediate expectations.unary_expectation_block( 'to_be_null', 'varchar2(4000)', 'null' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure null_anydata is - begin - --Act - execute immediate expectations.unary_expectation_block( 'to_be_null', 'anydata', 'null' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure uninit_object_in_anydata is - begin - --Act - execute immediate expectations.unary_expectation_object_block( - 'to_be_null', gc_object_name, 'null', 'object' - ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure uninit_nested_table_in_anydata is - begin - --Act - execute immediate expectations.unary_expectation_object_block( - 'to_be_null', gc_nested_table_name, 'null', 'collection' - ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure uninit_varray_in_anydata is - begin - --Act - execute immediate expectations.unary_expectation_object_block( 'to_be_null', gc_varray_name, - 'null', 'collection' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure blob_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block( 'to_be_null', 'blob', 'to_blob(''abc'')' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure empty_blob is - begin - --Act - execute immediate expectations.unary_expectation_block( 'to_be_null', 'blob', 'empty_blob()' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure boolean_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block( 'to_be_null', 'boolean', 'true' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure clob_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block( 'to_be_null', 'clob', 'to_clob(''abc'')' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure empty_clob is - begin - --Act - execute immediate expectations.unary_expectation_block( 'to_be_null', 'clob', 'empty_clob()' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure date_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block( 'to_be_null', 'date', 'sysdate' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure number_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block( 'to_be_null', 'number', '1234' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure timestamp_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block( 'to_be_null', 'timestamp', 'systimestamp' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure timestamp_with_ltz_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block( - 'to_be_null', 'timestamp with local time zone', 'systimestamp' - ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure timestamp_with_tz_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block( - 'to_be_null', 'timestamp with time zone', 'systimestamp' - ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure varchar2_not_null is - begin - --Act - execute immediate expectations.unary_expectation_block( 'to_be_null', 'varchar2(4000)', '''abc''' ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure initialized_object is - begin - --Act - execute immediate expectations.unary_expectation_object_block( - 'to_be_null', gc_object_name, gc_object_name || '(1)', 'object' - ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure initialized_nested_table is - begin - --Act - execute immediate expectations.unary_expectation_object_block( - 'to_be_null', gc_nested_table_name, gc_nested_table_name || '()', 'collection' - ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure initialized_varray is - begin - --Act - execute immediate expectations.unary_expectation_object_block( - 'to_be_null', gc_varray_name, gc_varray_name || '()', 'collection' - ); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - -end test_expect_to_be_null; -/ diff --git a/test/core/expectations/unary/test_expect_to_be_true_false.pkb b/test/core/expectations/unary/test_expect_to_be_true_false.pkb deleted file mode 100644 index 32ef58a7d..000000000 --- a/test/core/expectations/unary/test_expect_to_be_true_false.pkb +++ /dev/null @@ -1,139 +0,0 @@ -create or replace package body test_expect_to_be_true_false -is - - procedure cleanup_expectations is - begin - expectations.cleanup_expectations( ); - end; - - procedure to_be_true_null_boolean is - begin - --Act - ut3.ut.expect( 1=null ).to_be_true(); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure to_be_true_success is - begin - --Act - ut3.ut.expect( 1=1 ).to_be_true(); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure to_be_true_failure is - begin - --Act - ut3.ut.expect( 1=2 ).to_be_true(); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure to_be_true_bad_type is - begin - --Act - ut3.ut.expect( 1 ).to_be_true(); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure not_to_be_true_null_boolean is - begin - --Act - ut3.ut.expect( 1=null ).not_to_be_true(); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure not_to_be_true_success is - begin - --Act - ut3.ut.expect( 1=2 ).not_to_be_true(); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure not_to_be_true_failure is - begin - --Act - ut3.ut.expect( 1=1 ).not_to_be_true(); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - - procedure not_to_be_true_bad_type is - begin - --Act - ut3.ut.expect( 1 ).not_to_be_true(); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure to_be_false_null_boolean is - begin - --Act - ut3.ut.expect( 1=null ).to_be_false(); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure to_be_false_success is - begin - --Act - ut3.ut.expect( 1=2 ).to_be_false(); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure to_be_false_failure is - begin - --Act - ut3.ut.expect( 1=1 ).to_be_false(); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure to_be_false_bad_type is - begin - --Act - ut3.ut.expect( 1 ).to_be_false(); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure not_to_be_false_null_boolean is - begin - --Act - ut3.ut.expect( 1=null ).not_to_be_false(); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure not_to_be_false_success is - begin - --Act - ut3.ut.expect( 1=1 ).not_to_be_false(); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); - end; - - procedure not_to_be_false_failure is - begin - --Act - ut3.ut.expect( 1=2 ).not_to_be_false(); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - - procedure not_to_be_false_bad_type is - begin - --Act - ut3.ut.expect( 1 ).not_to_be_false(); - --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); - end; - -end; -/ diff --git a/test/core/expectations/unary/test_expect_to_have_count.pkb b/test/core/expectations/unary/test_expect_to_have_count.pkb deleted file mode 100644 index 663f60962..000000000 --- a/test/core/expectations/unary/test_expect_to_have_count.pkb +++ /dev/null @@ -1,200 +0,0 @@ -create or replace package body test_expect_to_have_count is - - procedure cleanup_expectations is - begin - expectations.cleanup_expectations( ); - end; - - procedure success_have_count_cursor is - l_cursor sys_refcursor; - begin - --Arrange - open l_cursor for select * from dual connect by level <= 11; - --Act - ut3.ut.expect(l_cursor).to_have_count(11); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure fail_have_count_cursor is - l_cursor sys_refcursor; - begin - --Arrange - open l_cursor for select * from dual where 0=1; - --Act - ut3.ut.expect(l_cursor).to_have_count(1); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_have_count_cursor_report is - l_cursor sys_refcursor; - l_actual_message varchar2(32767); - l_expected_message varchar2(32767); - begin - --Arrange - open l_cursor for select * from dual; - --Act - ut3.ut.expect(l_cursor).to_have_count(2); - - l_expected_message := q'[Actual: (refcursor [ count = 1 ]) was expected to have [ count = 2 ]%]'; - l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; - - --Assert - ut.expect(l_actual_message).to_be_like(l_expected_message); - end; - - procedure success_not_have_count_cursor is - l_cursor sys_refcursor; - begin - --Arrange - open l_cursor for select * from dual; - --Act - ut3.ut.expect(l_cursor).not_to_have_count(2); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure fail_not_have_count_cursor is - l_cursor sys_refcursor; - begin - --Arrange - open l_cursor for select * from dual where 1 = 2; - --Act - ut3.ut.expect(l_cursor).not_to_have_count(0); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure success_have_count_collection is - l_actual anydata; - begin - --Arrange - l_actual := anydata.convertcollection(ora_mining_varchar2_nt()); - -- Act - ut3.ut.expect(l_actual).to_have_count(0); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure fail_have_count_collection is - l_actual anydata; - begin - --Arrange - l_actual := anydata.convertcollection(ora_mining_varchar2_nt('a')); - -- Act - ut3.ut.expect(l_actual).to_have_count(0); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure success_not_have_count_coll is - l_actual anydata; - begin - --Arrange - l_actual := anydata.convertcollection(ora_mining_varchar2_nt('a')); - -- Act - ut3.ut.expect(l_actual).not_to_have_count(2); - --Assert - ut.expect(expectations.failed_expectations_data()).to_be_empty(); - end; - - procedure fail_not_have_count_coll is - l_actual anydata; - begin - --Arrange - l_actual := anydata.convertcollection(ora_mining_varchar2_nt()); - -- Act - ut3.ut.expect(l_actual).not_to_have_count(0); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_have_count_null_coll is - l_actual anydata; - l_data ora_mining_varchar2_nt; - begin - --Arrange - l_actual := anydata.convertcollection(l_data); - -- Act - ut3.ut.expect(l_actual).to_have_count(0); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_not_have_count_null_coll is - l_actual anydata; - l_data ora_mining_varchar2_nt; - begin - --Arrange - l_actual := anydata.convertcollection(l_data); - -- Act - ut3.ut.expect(l_actual).not_to_have_count(0); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_have_count_object is - l_actual anydata; - begin - --Arrange - l_actual := anydata.convertObject(ut3.ut_data_value_number(1)); - -- Act - ut3.ut.expect(l_actual).to_have_count(0); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_have_count_null_object is - l_actual anydata; - l_data ut3.ut_data_value_number; - begin - --Arrange - l_actual := anydata.convertObject(l_data); - -- Act - ut3.ut.expect(l_actual).to_have_count(0); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_have_count_number is - begin - -- Act - ut3.ut.expect( 1 ).to_( ut3.have_count(0) ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_not_have_count_object is - l_actual anydata; - begin - --Arrange - l_actual := anydata.convertObject(ut3.ut_data_value_number(1)); - -- Act - ut3.ut.expect(l_actual).not_to_have_count(0); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_not_have_count_null_obj is - l_actual anydata; - l_data ut3.ut_data_value_number; - begin - --Arrange - l_actual := anydata.convertObject(l_data); - -- Act - ut3.ut.expect(l_actual).not_to_have_count(0); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - - procedure fail_not_have_count_number is - begin - -- Act - ut3.ut.expect( 1 ).not_to( ut3.have_count(0) ); - --Assert - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); - end; - -end; -/ \ No newline at end of file diff --git a/test/core/reporters/test_coverage.pkb b/test/core/reporters/test_coverage.pkb deleted file mode 100644 index 4e3846af8..000000000 --- a/test/core/reporters/test_coverage.pkb +++ /dev/null @@ -1,263 +0,0 @@ -create or replace package body test_coverage is - - function get_mock_run_id return integer is - v_result integer; - begin - select nvl(min(runid),0) - 1 into v_result - from ut3.plsql_profiler_runs; - return v_result; - end; - - procedure create_dummy_coverage_package is - pragma autonomous_transaction; - begin - execute immediate q'[create or replace package UT3.DUMMY_COVERAGE is - procedure do_stuff; - end;]'; - execute immediate q'[create or replace package body UT3.DUMMY_COVERAGE is - procedure do_stuff is - begin - if 1 = 2 then - dbms_output.put_line('should not get here'); - else - dbms_output.put_line('should get here'); - end if; - end; - end;]'; - end; - - procedure create_dummy_coverage_test is - pragma autonomous_transaction; - begin - execute immediate q'[create or replace package UT3.TEST_DUMMY_COVERAGE is - --%suite(dummy coverage test) - --%suitepath(coverage_testing) - - --%test - procedure test_do_stuff; - end;]'; - execute immediate q'[create or replace package body UT3.TEST_DUMMY_COVERAGE is - procedure test_do_stuff is - begin - dummy_coverage.do_stuff; - end; - end;]'; - end; - - procedure create_dummy_coverage_test_1 is - pragma autonomous_transaction; - begin - execute immediate q'[create or replace package UT3.DUMMY_COVERAGE_1 is - procedure do_stuff; - end;]'; - execute immediate q'[create or replace package body UT3.DUMMY_COVERAGE_1 is - procedure do_stuff is - begin - if 1 = 2 then - dbms_output.put_line('should not get here'); - else - dbms_output.put_line('should get here'); - end if; - end; - end;]'; - execute immediate q'[create or replace package UT3.TEST_DUMMY_COVERAGE_1 is - --%suite(dummy coverage test 1) - --%suitepath(coverage_testing) - - --%test - procedure test_do_stuff; - end;]'; - execute immediate q'[create or replace package body UT3.TEST_DUMMY_COVERAGE_1 is - procedure test_do_stuff is - begin - dummy_coverage_1.do_stuff; - end; - end;]'; - end; - - procedure drop_dummy_coverage_test_1 is - pragma autonomous_transaction; - begin - execute immediate q'[drop package UT3.DUMMY_COVERAGE_1]'; - execute immediate q'[drop package UT3.TEST_DUMMY_COVERAGE_1]'; - end; - - - procedure mock_coverage_data(a_run_id integer) is - c_unit_id constant integer := 1; - begin - insert into ut3.plsql_profiler_runs ( runid, run_owner, run_date, run_comment) - values(a_run_id, user, sysdate, 'unit testing utPLSQL'); - - insert into ut3.plsql_profiler_units ( runid, unit_number, unit_type, unit_owner, unit_name) - values(a_run_id, c_unit_id, 'PACKAGE BODY', 'UT3', 'DUMMY_COVERAGE'); - - insert into ut3.plsql_profiler_data ( runid, unit_number, line#, total_occur, total_time) - select a_run_id, c_unit_id, 4, 1, 1 from dual union all - select a_run_id, c_unit_id, 5, 0, 0 from dual union all - select a_run_id, c_unit_id, 7, 1, 1 from dual; - end; - - procedure create_dummy_coverage_pkg is - pragma autonomous_transaction; - begin - create_dummy_coverage_package(); - create_dummy_coverage_test(); - end; - - procedure setup_dummy_coverage is - pragma autonomous_transaction; - begin - g_run_id := get_mock_run_id(); - ut3.ut_coverage.mock_coverage_id(g_run_id, ut3.ut_coverage.gc_proftab_coverage); - mock_coverage_data(g_run_id); - commit; - end; - - procedure drop_dummy_coverage_pkg is - pragma autonomous_transaction; - begin - begin execute immediate q'[drop package ut3.test_dummy_coverage]'; exception when others then null; end; - begin execute immediate q'[drop package ut3.dummy_coverage]'; exception when others then null; end; - end; - - procedure cleanup_dummy_coverage is - pragma autonomous_transaction; - begin - delete from ut3.plsql_profiler_data where runid = g_run_id; - delete from ut3.plsql_profiler_units where runid = g_run_id; - delete from ut3.plsql_profiler_runs where runid = g_run_id; - commit; - end; - - procedure coverage_for_object is - l_expected clob; - l_actual clob; - l_results ut3.ut_varchar2_list; - begin - --Arrange - l_expected := '%%'; - --Act - select * - bulk collect into l_results - from table( - ut3.ut.run( - a_path => 'ut3.test_dummy_coverage', - a_reporter=> ut3.ut_coverage_sonar_reporter( ), - a_include_objects => ut3.ut_varchar2_list( 'ut3.dummy_coverage' ) - ) - ); - --Assert - l_actual := ut3.ut_utils.table_to_clob(l_results); - ut.expect(l_actual).to_be_like(l_expected); - end; - - procedure coverage_for_object_no_owner is - l_expected clob; - l_actual clob; - l_results ut3.ut_varchar2_list; - begin - --Arrange - l_expected := '%%'; - --Act - select * - bulk collect into l_results - from table( - ut3.ut.run( - a_path => 'ut3.test_dummy_coverage', - a_reporter=> ut3.ut_coverage_sonar_reporter( ), - a_include_objects => ut3.ut_varchar2_list( 'dummy_coverage' ) - ) - ); - --Assert - l_actual := ut3.ut_utils.table_to_clob(l_results); - ut.expect(l_actual).to_be_like(l_expected); - end; - - procedure coverage_for_schema is - l_expected clob; - l_actual clob; - l_results ut3.ut_varchar2_list; - begin - --Arrange - l_expected := ''; - l_expected := '%'||l_expected||'%'||l_expected||'%'; - --Act - select * - bulk collect into l_results - from table( - ut3.ut.run( - a_path => 'ut3.test_dummy_coverage', - a_reporter=> ut3.ut_coverage_sonar_reporter( ), - a_coverage_schemes => ut3.ut_varchar2_list( 'ut3' ) - ) - ); - --Assert - l_actual := ut3.ut_utils.table_to_clob(l_results); - ut.expect(l_actual).to_be_like(l_expected); - end; - - procedure coverage_for_file is - l_expected clob; - l_actual clob; - l_results ut3.ut_varchar2_list; - l_file_path varchar2(100); - begin - --Arrange - l_file_path := lower('test/ut3.dummy_coverage.pkb'); - l_expected := '%%'; - --Act - select * - bulk collect into l_results - from table( - ut3.ut.run( - a_path => 'ut3.test_dummy_coverage', - a_reporter=> ut3.ut_coverage_sonar_reporter( ), - a_source_files => ut3.ut_varchar2_list( l_file_path ), - a_test_files => ut3.ut_varchar2_list( ) - ) - ); - --Assert - l_actual := ut3.ut_utils.table_to_clob(l_results); - ut.expect(l_actual).to_be_like(l_expected); - end; - - procedure coverage_tmp_data_refresh is - l_actual clob; - l_results ut3.ut_varchar2_list; - begin - --Arrange - select * - bulk collect into l_results - from table( - ut3.ut.run( - a_path => 'ut3:coverage_testing', - a_reporter=> ut3.ut_coverage_sonar_reporter( ), - a_include_objects => ut3.ut_varchar2_list( 'ut3.dummy_coverage' ) - ) - ); - cleanup_dummy_coverage(); - drop_dummy_coverage_pkg(); - create_dummy_coverage_test_1; - - --Act - select * - bulk collect into l_results - from table( - ut3.ut.run( - a_path => 'ut3:coverage_testing', - a_reporter=> ut3.ut_coverage_sonar_reporter( ), - a_include_objects => ut3.ut_varchar2_list( 'ut3.dummy_coverage' ) - ) - ); - - --Assert - l_actual := ut3.ut_utils.table_to_clob(l_results); - ut.expect(l_actual).to_equal(to_clob(' - -')); - drop_dummy_coverage_test_1; - end; - -end; -/ diff --git a/test/core/reporters/test_coverage.pks b/test/core/reporters/test_coverage.pks deleted file mode 100644 index 65e99666b..000000000 --- a/test/core/reporters/test_coverage.pks +++ /dev/null @@ -1,38 +0,0 @@ -create or replace package test_coverage is - - --%suite - --%suitepath(utplsql.core.reporters) - - g_run_id integer; - - --%beforeall - procedure create_dummy_coverage_pkg; - --%beforeall - procedure setup_dummy_coverage; - - - --%afterall - procedure drop_dummy_coverage_pkg; - --%afterall - procedure cleanup_dummy_coverage; - - - --%test(Coverage is gathered for specified object - default coverage type) - procedure coverage_for_object; - - --%test(Coverage is gathered for specified schema - default coverage type) - procedure coverage_for_object_no_owner; - - --%test(Coverage is gathered for specified schema) - procedure coverage_for_schema; - - --%test(Coverage is gathered for specified file - default coverage type) - procedure coverage_for_file; - - --%test(Coverage data is not cached between runs - issue #562 ) - --%aftertest(create_dummy_coverage_pkg) - --%aftertest(setup_dummy_coverage) - procedure coverage_tmp_data_refresh; - -end; -/ diff --git a/test/core/reporters/test_coverage/test_cov_cobertura_reporter.pkb b/test/core/reporters/test_coverage/test_cov_cobertura_reporter.pkb deleted file mode 100644 index e89fbd283..000000000 --- a/test/core/reporters/test_coverage/test_cov_cobertura_reporter.pkb +++ /dev/null @@ -1,44 +0,0 @@ -create or replace package body test_cov_cobertura_reporter is - - procedure report_on_file is - l_results ut3.ut_varchar2_list; - l_expected clob; - l_actual clob; - begin - --Arrange - l_expected := - ' - - -test/ut3.dummy_coverage.pkb - - - - - - - - - - - - -'; - --Act - select * - bulk collect into l_results - from table( - ut3.ut.run( - a_path => 'ut3.test_dummy_coverage', - a_reporter=> ut3.ut_coverage_cobertura_reporter( ), - a_source_files => ut3.ut_varchar2_list( 'test/ut3.dummy_coverage.pkb' ), - a_test_files => ut3.ut_varchar2_list( ) - ) - ); - l_actual := ut3.ut_utils.table_to_clob(l_results); - --Assert - ut.expect(l_actual).to_be_like(l_expected); - end; - -end; -/ diff --git a/test/core/reporters/test_coverage/test_coverage_sonar_reporter.pkb b/test/core/reporters/test_coverage/test_coverage_sonar_reporter.pkb deleted file mode 100644 index 81b2c12f8..000000000 --- a/test/core/reporters/test_coverage/test_coverage_sonar_reporter.pkb +++ /dev/null @@ -1,39 +0,0 @@ -create or replace package body test_coverage_sonar_reporter is - - procedure report_on_file is - l_results ut3.ut_varchar2_list; - l_expected clob; - l_actual clob; - begin - --Arrange - l_expected := ' - - - - - - -'; - --Act - select * - bulk collect into l_results - from table( - ut3.ut.run( - a_path => 'ut3.test_dummy_coverage', - a_reporter=> ut3.ut_coverage_sonar_reporter( ), - a_source_files => ut3.ut_varchar2_list( 'test/ut3.dummy_coverage.pkb' ), - a_test_files => ut3.ut_varchar2_list( ) - ) - ); - l_actual := ut3.ut_utils.table_to_clob(l_results); - --Assert - ut.expect(l_actual).to_equal(l_expected); - end; - - procedure check_encoding_included is - begin - reporters.check_xml_encoding_included(ut3.ut_coverage_sonar_reporter(), 'UTF-8'); - end; - -end; -/ diff --git a/test/core/reporters/test_coverage/test_coveralls_reporter.pkb b/test/core/reporters/test_coverage/test_coveralls_reporter.pkb deleted file mode 100644 index 3b6b88346..000000000 --- a/test/core/reporters/test_coverage/test_coveralls_reporter.pkb +++ /dev/null @@ -1,78 +0,0 @@ -create or replace package body test_coveralls_reporter is - - procedure report_on_file is - l_results ut3.ut_varchar2_list; - l_expected clob; - l_actual clob; - begin - --Arrange - l_expected := q'[{"source_files":[ -{ "name": "test/ut3.dummy_coverage.pkb", -"coverage": [null, -null, -null, -1, -0, -null, -1 -]}]} - ]'; - --Act - select * - bulk collect into l_results - from table( - ut3.ut.run( - a_path => 'ut3.test_dummy_coverage', - a_reporter=> ut3.ut_coveralls_reporter( ), - a_source_files => ut3.ut_varchar2_list( 'test/ut3.dummy_coverage.pkb' ), - a_test_files => ut3.ut_varchar2_list( ) - ) - ); - l_actual := ut3.ut_utils.table_to_clob(l_results); - --Assert - ut.expect(l_actual).to_equal(l_expected); - end; - - procedure report_zero_coverage is - l_results ut3.ut_varchar2_list; - l_expected clob; - l_actual clob; - pragma autonomous_transaction; - begin - --Arrange - l_expected := q'[{"source_files":[ -{ "name": "ut3.dummy_coverage", -"coverage": [0, -0, -0, -0, -0, -0, -0, -0, -0, -0]}]} - ]'; - - test_coverage.cleanup_dummy_coverage; - - --Act - select * - bulk collect into l_results - from table( - ut3.ut.run( - 'ut3.test_dummy_coverage', - ut3.ut_coveralls_reporter(), - a_include_objects => ut3.ut_varchar2_list('UT3.DUMMY_COVERAGE') - ) - ); - l_actual := ut3.ut_utils.table_to_clob(l_results); - --Assert - ut.expect(l_actual).to_equal(l_expected); - - test_coverage.setup_dummy_coverage; - - end; - -end; -/ diff --git a/test/core/reporters/test_coverage/test_html_extended_reporter.pkb b/test/core/reporters/test_coverage/test_html_extended_reporter.pkb deleted file mode 100644 index 19e1fe807..000000000 --- a/test/core/reporters/test_coverage/test_html_extended_reporter.pkb +++ /dev/null @@ -1,29 +0,0 @@ -create or replace package body test_html_extended_reporter is - - procedure report_on_file is - l_results ut3.ut_varchar2_list; - l_expected varchar2(32767); - l_actual clob; - l_charset varchar2(100) := 'ISO-8859-1'; - begin - --Arrange - l_expected := '%%

UT3.DUMMY_COVERAGE_PACKAGE_WITH_AN_AMAZINGLY_LONG_NAME_THAT_YOU_WOULD_NOT_THINK_OF_IN_REAL_LIFE_PROJECT_BECAUSE_ITS_SIMPLY_TOO_LONG

%4 relevant lines. 3 lines covered (including 1 lines partially covered ) and 1 lines missed%'; - - select * - bulk collect into l_results - from table( - ut3.ut.run( - a_path => 'ut3.test_dummy_coverage', - a_reporter=> ut3.ut_coverage_html_reporter(), - a_source_files => ut3.ut_varchar2_list( 'test/ut3.dummy_coverage_package_with_an_amazingly_long_name_that_you_would_not_think_of_in_real_life_project_because_its_simply_too_long.pkb' ), - a_test_files => ut3.ut_varchar2_list( ), - a_client_character_set => l_charset - ) - ); - l_actual := ut3.ut_utils.table_to_clob(l_results); - --Assert - ut.expect(l_actual).to_be_like(l_expected); - end; - -end test_html_extended_reporter; -/ diff --git a/test/core/reporters/test_coverage/test_html_extended_reporter.pks b/test/core/reporters/test_coverage/test_html_extended_reporter.pks deleted file mode 100644 index cefa71d66..000000000 --- a/test/core/reporters/test_coverage/test_html_extended_reporter.pks +++ /dev/null @@ -1,10 +0,0 @@ -create or replace package test_html_extended_reporter is - - --%suite(ut_html_extended_reporter) - --%suitepath(utplsql.core.reporters.test_extended_coverage) - - --%test(reports on a project file mapped to database object in extended profiler coverage) - procedure report_on_file; - -end test_html_extended_reporter; -/ diff --git a/test/core/reporters/test_coverage/test_html_proftab_reporter.pkb b/test/core/reporters/test_coverage/test_html_proftab_reporter.pkb deleted file mode 100644 index c10af2869..000000000 --- a/test/core/reporters/test_coverage/test_html_proftab_reporter.pkb +++ /dev/null @@ -1,29 +0,0 @@ -create or replace package body test_html_proftab_reporter is - - procedure report_on_file is - l_results ut3.ut_varchar2_list; - l_expected varchar2(32767); - l_actual clob; - l_charset varchar2(100) := 'ISO-8859-1'; - begin - --Arrange - l_expected := '%%

UT3.DUMMY_COVERAGE

%3 relevant lines. 2 lines covered and 1 lines missed%'; - --Act - select * - bulk collect into l_results - from table( - ut3.ut.run( - a_path => 'ut3.test_dummy_coverage', - a_reporter=> ut3.ut_coverage_html_reporter(), - a_source_files => ut3.ut_varchar2_list( 'test/ut3.dummy_coverage.pkb' ), - a_test_files => ut3.ut_varchar2_list( ), - a_client_character_set => l_charset - ) - ); - l_actual := ut3.ut_utils.table_to_clob(l_results); - --Assert - ut.expect(l_actual).to_be_like(l_expected); - end; - -end test_html_proftab_reporter; -/ diff --git a/test/core/reporters/test_coverage/test_html_proftab_reporter.pks b/test/core/reporters/test_coverage/test_html_proftab_reporter.pks deleted file mode 100644 index d091510c6..000000000 --- a/test/core/reporters/test_coverage/test_html_proftab_reporter.pks +++ /dev/null @@ -1,10 +0,0 @@ -create or replace package test_html_proftab_reporter is - - --%suite(ut_html_proftab_reporter) - --%suitepath(utplsql.core.reporters.test_coverage) - - --%test(reports on a project file mapped to database object in profiler coverage) - procedure report_on_file; - -end test_html_proftab_reporter; -/ diff --git a/test/core/reporters/test_documentation_reporter.pkb b/test/core/reporters/test_documentation_reporter.pkb deleted file mode 100644 index 7045aa7ca..000000000 --- a/test/core/reporters/test_documentation_reporter.pkb +++ /dev/null @@ -1 +0,0 @@ -create or replace package body test_documentation_reporter as procedure report_produces_expected_out is l_results ut3.ut_varchar2_list; l_actual clob; l_expected varchar2(32767):=q'[%org utplsql tests helpers A suite for testing different outcomes from reporters A description of some context passing_test [% sec] a test with failing assertion [% sec] (FAILED - 1) a test raising unhandled exception [% sec] (FAILED - 2) a disabled test [0 sec] (DISABLED) % Failures: % 1) failing_test "Fails as values are different" Actual: 'number [1] ' (varchar2) was expected to equal: 'number [2] ' (varchar2)% at "UT3_TESTER.TEST_REPORTERS%", line 36 ut3.ut.expect('number [1] ','Fails as values are different').to_equal('number [2] '); % % 2) erroring_test ORA-06502: PL/SQL: numeric or value error: character to number conversion error ORA-06512: at "UT3_TESTER.TEST_REPORTERS", line 44% ORA-06512: at line 6 Finished in % seconds 4 tests, 1 failed, 1 errored, 1 disabled, 0 warning(s)%]'; begin select * bulk collect into l_results from table( ut3.ut.run( 'test_reporters', ut3.ut_documentation_reporter() ) ); l_actual := ut3.ut_utils.table_to_clob(l_results); ut.expect(l_actual).to_be_like(l_expected); end; procedure check_encoding_included is begin reporters.check_xml_encoding_included(ut3.ut_sonar_test_reporter(), 'UTF-8'); end; end; / \ No newline at end of file diff --git a/test/core/reporters/test_extended_coverage.pkb b/test/core/reporters/test_extended_coverage.pkb deleted file mode 100644 index a3719e503..000000000 --- a/test/core/reporters/test_extended_coverage.pkb +++ /dev/null @@ -1,188 +0,0 @@ -create or replace package body test_extended_coverage is - - g_run_id ut3.ut_coverage.tt_coverage_id_arr; - - function get_mock_block_run_id return integer is - v_result integer; - begin - select nvl(min(run_id),0) - 1 into v_result - from dbmspcc_runs; - return v_result; - end; - - function get_mock_proftab_run_id return integer is - v_result integer; - begin - select nvl(min(runid),0) - 1 into v_result - from ut3.plsql_profiler_runs; - return v_result; - end; - - procedure create_dummy_coverage_package is - pragma autonomous_transaction; - begin - execute immediate q'[create or replace package UT3.DUMMY_COVERAGE_PACKAGE_WITH_AN_AMAZINGLY_LONG_NAME_THAT_YOU_WOULD_NOT_THINK_OF_IN_REAL_LIFE_PROJECT_BECAUSE_ITS_SIMPLY_TOO_LONG is - procedure do_stuff(i_input in number); - end;]'; - execute immediate q'[create or replace package body UT3.DUMMY_COVERAGE_PACKAGE_WITH_AN_AMAZINGLY_LONG_NAME_THAT_YOU_WOULD_NOT_THINK_OF_IN_REAL_LIFE_PROJECT_BECAUSE_ITS_SIMPLY_TOO_LONG is - procedure do_stuff(i_input in number) is - begin - if i_input = 2 then - dbms_output.put_line('should not get here'); - else - dbms_output.put_line('should get here'); - end if; - end; - end;]'; - end; - - procedure create_dummy_coverage_test is - pragma autonomous_transaction; - begin - execute immediate q'[create or replace package UT3.TEST_DUMMY_COVERAGE is - --%suite(dummy coverage test) - --%suitepath(coverage_testing) - - --%test - procedure test_do_stuff; - end;]'; - execute immediate q'[create or replace package body UT3.TEST_DUMMY_COVERAGE is - procedure test_do_stuff is - begin - dummy_coverage_package_with_an_amazingly_long_name_that_you_would_not_think_of_in_real_life_project_because_its_simply_too_long.do_stuff(1); - ut.expect(1).to_equal(1); - end; - end;]'; - end; - - procedure mock_block_coverage_data(a_run_id integer) is - c_unit_id constant integer := 1; - begin - insert into dbmspcc_runs ( run_id, run_owner, run_timestamp, run_comment) - values(a_run_id, user, sysdate, 'unit testing utPLSQL'); - - insert into dbmspcc_units ( run_id, object_id, type, owner, name,last_ddl_time) - values(a_run_id, c_unit_id, 'PACKAGE BODY', 'UT3', 'DUMMY_COVERAGE_PACKAGE_WITH_AN_AMAZINGLY_LONG_NAME_THAT_YOU_WOULD_NOT_THINK_OF_IN_REAL_LIFE_PROJECT_BECAUSE_ITS_SIMPLY_TOO_LONG',sysdate); - - insert into dbmspcc_blocks ( run_id, object_id, line,block,col,covered,not_feasible) - select a_run_id, c_unit_id,4,1,1,1,0 from dual union all - select a_run_id, c_unit_id,4,2,2,0,0 from dual union all - select a_run_id, c_unit_id,5,3,0,1,0 from dual union all - select a_run_id, c_unit_id,7,4,1,1,0 from dual; - end; - - procedure mock_profiler_coverage_data(a_run_id integer) is - c_unit_id constant integer := 1; - begin - insert into ut3.plsql_profiler_runs ( runid, run_owner, run_date, run_comment) - values(a_run_id, user, sysdate, 'unit testing utPLSQL'); - - insert into ut3.plsql_profiler_units ( runid, unit_number, unit_type, unit_owner, unit_name) - values(a_run_id, c_unit_id, 'PACKAGE BODY', 'UT3', 'DUMMY_COVERAGE_PACKAGE_WITH_AN_AMAZINGLY_LONG_NAME_THAT_YOU_WOULD_NOT_THINK_OF_IN_REAL_LIFE_PROJECT_BECAUSE_ITS_SIMPLY_TOO_LONG'); - - insert into ut3.plsql_profiler_data ( runid, unit_number, line#, total_occur, total_time) - select a_run_id, c_unit_id, 4, 1, 1 from dual union all - select a_run_id, c_unit_id, 5, 0, 0 from dual union all - select a_run_id, c_unit_id, 6, 1, 0 from dual union all - select a_run_id, c_unit_id, 7, 1, 1 from dual; - end; - - procedure setup_dummy_coverage is - pragma autonomous_transaction; - begin - create_dummy_coverage_package(); - create_dummy_coverage_test(); - g_run_id(ut3.ut_coverage.gc_block_coverage) := get_mock_block_run_id(); - g_run_id(ut3.ut_coverage.gc_proftab_coverage) := get_mock_proftab_run_id(); - ut3.ut_coverage.mock_coverage_id(g_run_id); - mock_block_coverage_data(g_run_id(ut3.ut_coverage.gc_block_coverage)); - mock_profiler_coverage_data(g_run_id(ut3.ut_coverage.gc_proftab_coverage)); - commit; - end; - - procedure cleanup_dummy_coverage is - pragma autonomous_transaction; - begin - begin execute immediate q'[drop package ut3.test_dummy_coverage]'; exception when others then null; end; - begin execute immediate q'[drop package ut3.dummy_coverage_package_with_an_amazingly_long_name_that_you_would_not_think_of_in_real_life_project_because_its_simply_too_long]'; exception when others then null; end; - delete from dbmspcc_blocks where run_id = g_run_id(ut3.ut_coverage.gc_block_coverage); - delete from dbmspcc_units where run_id = g_run_id(ut3.ut_coverage.gc_block_coverage); - delete from dbmspcc_runs where run_id = g_run_id(ut3.ut_coverage.gc_block_coverage); - delete from ut3.plsql_profiler_data where runid = g_run_id(ut3.ut_coverage.gc_proftab_coverage); - delete from ut3.plsql_profiler_units where runid = g_run_id(ut3.ut_coverage.gc_proftab_coverage); - delete from ut3.plsql_profiler_runs where runid = g_run_id(ut3.ut_coverage.gc_proftab_coverage); - commit; - end; - - procedure coverage_for_object is - l_expected clob; - l_actual clob; - l_results ut3.ut_varchar2_list; - begin - --Arrange - l_expected := '%%%'; - --Act - select * - bulk collect into l_results - from table( - ut3.ut.run( - a_path => 'ut3.test_dummy_coverage', - a_reporter=> ut3.ut_coverage_sonar_reporter( ), - a_include_objects => ut3.ut_varchar2_list( 'ut3.dummy_coverage_package_with_an_amazingly_long_name_that_you_would_not_think_of_in_real_life_project_because_its_simply_too_long' ) - ) - ); - --Assert - l_actual := ut3.ut_utils.table_to_clob(l_results); - ut.expect(l_actual).to_be_like(l_expected); - end; - - procedure coverage_for_schema is - l_expected clob; - l_actual clob; - l_results ut3.ut_varchar2_list; - begin - --Arrange - l_expected := '%%%'; - --Act - select * - bulk collect into l_results - from table( - ut3.ut.run( - a_path => 'ut3.test_dummy_coverage', - a_reporter=> ut3.ut_coverage_sonar_reporter( ), - a_coverage_schemes => ut3.ut_varchar2_list( 'ut3' ) - ) - ); - --Assert - l_actual := ut3.ut_utils.table_to_clob(l_results); - ut.expect(l_actual).to_be_like(l_expected); - ut.expect(l_actual).to_be_like('%%%'); - end; - - procedure coverage_for_file is - l_expected clob; - l_actual clob; - l_results ut3.ut_varchar2_list; - l_file_path varchar2(250); - begin - --Arrange - l_file_path := lower('test/ut3.dummy_coverage_package_with_an_amazingly_long_name_that_you_would_not_think_of_in_real_life_project_because_its_simply_too_long.pkb'); - l_expected := '%%%'; - --Act - select * - bulk collect into l_results - from table( - ut3.ut.run( - a_path => 'ut3.test_dummy_coverage', - a_reporter=> ut3.ut_coverage_sonar_reporter( ), - a_source_files => ut3.ut_varchar2_list( l_file_path ), - a_test_files => ut3.ut_varchar2_list( ) - ) - ); - --Assert - l_actual := ut3.ut_utils.table_to_clob(l_results); - ut.expect(l_actual).to_be_like(l_expected); - end; - -end; -/ diff --git a/test/core/reporters/test_extended_coverage.pks b/test/core/reporters/test_extended_coverage.pks deleted file mode 100644 index 6d85a4a30..000000000 --- a/test/core/reporters/test_extended_coverage.pks +++ /dev/null @@ -1,22 +0,0 @@ -create or replace package test_extended_coverage is - - --%suite - --%suitepath(utplsql.core.reporters) - - --%beforeall - procedure setup_dummy_coverage; - - --%afterall - procedure cleanup_dummy_coverage; - - --%test(Coverage is gathered for specified object - extended coverage type) - procedure coverage_for_object; - - --%test(Coverage is gathered for specified schema - extended coverage type) - procedure coverage_for_schema; - - --%test(Coverage is gathered for specified file - extended coverage type) - procedure coverage_for_file; - -end; -/ diff --git a/test/core/reporters/test_teamcity_reporter.pkb b/test/core/reporters/test_teamcity_reporter.pkb deleted file mode 100644 index 77b850b15..000000000 --- a/test/core/reporters/test_teamcity_reporter.pkb +++ /dev/null @@ -1,131 +0,0 @@ -create or replace package body test_teamcity_reporter as - - procedure create_a_test_package is - pragma autonomous_transaction; - begin - execute immediate q'[create or replace package check_escape_special_chars is - --%suite(A suite with 'quote') - - --%test(A test with 'quote') - procedure test_do_stuff; - - end;]'; - execute immediate q'[create or replace package body check_escape_special_chars is - procedure test_do_stuff is - begin - ut3.ut.expect(' [ ' || chr(13) || chr(10) || ' ] ' ).to_be_null; - end; - - end;]'; - - execute immediate q'[create or replace package check_trims_long_output is - --%suite - - --%test - procedure long_output; - end;]'; - execute immediate q'[create or replace package body check_trims_long_output is - procedure long_output is - begin - ut3.ut.expect(rpad('aVarchar',4000,'a')).to_be_null; - end; - end;]'; - - end; - - - procedure report_produces_expected_out is - l_output_data ut3.ut_varchar2_list; - l_output clob; - l_expected varchar2(32767); - begin - l_expected := q'{%##teamcity[testSuiteStarted timestamp='%' name='org'] -%##teamcity[testSuiteStarted timestamp='%' name='org.utplsql'] -%##teamcity[testSuiteStarted timestamp='%' name='org.utplsql.tests'] -%##teamcity[testSuiteStarted timestamp='%' name='org.utplsql.tests.helpers'] -%##teamcity[testSuiteStarted timestamp='%' name='A suite for testing different outcomes from reporters'] -%##teamcity[testSuiteStarted timestamp='%' name='A description of some context'] -%##teamcity[testStarted timestamp='%' captureStandardOutput='true' name='ut3_tester.test_reporters.passing_test'] - - - - - -%##teamcity[testFinished timestamp='%' duration='%' name='ut3_tester.test_reporters.passing_test'] -%##teamcity[testSuiteFinished timestamp='%' name='A description of some context'] -%##teamcity[testStarted timestamp='%' captureStandardOutput='true' name='ut3_tester.test_reporters.failing_test'] - - - -%##teamcity[testFailed timestamp='%' details='Actual: |'number |[1|] |' (varchar2) was expected to equal: |'number |[2|] |' (varchar2) ' message='Fails as values are different' name='ut3_tester.test_reporters.failing_test'] -%##teamcity[testFinished timestamp='%' duration='%' name='ut3_tester.test_reporters.failing_test'] -%##teamcity[testStarted timestamp='%' captureStandardOutput='true' name='ut3_tester.test_reporters.erroring_test'] - - - -%##teamcity[testStdErr timestamp='%' name='ut3_tester.test_reporters.erroring_test' out='Test exception:|nORA-06512: at "UT3_TESTER.TEST_REPORTERS", line %|nORA-06512: at %|n|n'] -%##teamcity[testFailed timestamp='%' details='Test exception:|nORA-06512: at "UT3_TESTER.TEST_REPORTERS", line %|nORA-06512: at %|n|n' message='Error occured' name='ut3_tester.test_reporters.erroring_test'] -%##teamcity[testFinished timestamp='%' duration='%' name='ut3_tester.test_reporters.erroring_test'] -%##teamcity[testStarted timestamp='%' captureStandardOutput='true' name='ut3_tester.test_reporters.disabled_test'] -%##teamcity[testIgnored timestamp='%' name='ut3_tester.test_reporters.disabled_test'] -%##teamcity[testSuiteFinished timestamp='%' name='A suite for testing different outcomes from reporters'] -%##teamcity[testSuiteFinished timestamp='%' name='org.utplsql.tests.helpers'] -%##teamcity[testSuiteFinished timestamp='%' name='org.utplsql.tests'] -%##teamcity[testSuiteFinished timestamp='%' name='org.utplsql'] -%##teamcity[testSuiteFinished timestamp='%' name='org']}'; - --act - select * - bulk collect into l_output_data - from table(ut3.ut.run('test_reporters',ut3.ut_teamcity_reporter())); - - --assert - ut.expect(ut3.ut_utils.table_to_clob(l_output_data)).to_be_like(l_expected); - end; - - procedure escape_special_chars is - l_output_data ut3.ut_varchar2_list; - l_output clob; - l_expected varchar2(32767); - begin - l_expected := q'{%##teamcity[testSuiteStarted timestamp='%' name='A suite with |'quote|''] -%##teamcity[testStarted timestamp='%' captureStandardOutput='true' name='ut3_tester.check_escape_special_chars.test_do_stuff'] -%##teamcity[testFailed timestamp='%' details='Actual: (varchar2)|n |' |[ |r|n |] |'|nwas expected to be null' name='ut3_tester.check_escape_special_chars.test_do_stuff'] -%##teamcity[testFinished timestamp='%' duration='%' name='ut3_tester.check_escape_special_chars.test_do_stuff'] -%##teamcity[testSuiteFinished timestamp='%' name='A suite with |'quote|'']}'; - --act - select * - bulk collect into l_output_data - from table(ut3.ut.run('check_escape_special_chars',ut3.ut_teamcity_reporter())); - - --assert - ut.expect(ut3.ut_utils.table_to_clob(l_output_data)).to_be_like(l_expected); - end; - - procedure trims_long_output is - l_output_data ut3.ut_varchar2_list; - l_output clob; - l_expected varchar2(32767); - begin - l_expected := q'{%##teamcity[testSuiteStarted timestamp='%' name='check_trims_long_output'] -%##teamcity[testStarted timestamp='%' captureStandardOutput='true' name='ut3_tester.check_trims_long_output.long_output'] -%##teamcity[testFailed timestamp='%' details='Actual: (varchar2)|n |'aVarcharaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|[...|]' name='ut3_tester.check_trims_long_output.long_output'] -%##teamcity[testFinished timestamp='%' duration='%' name='ut3_tester.check_trims_long_output.long_output'] -%##teamcity[testSuiteFinished timestamp='%' name='check_trims_long_output']}'; - --act - select * - bulk collect into l_output_data - from table(ut3.ut.run('check_trims_long_output',ut3.ut_teamcity_reporter())); - - --assert - ut.expect(ut3.ut_utils.table_to_clob(l_output_data)).to_be_like(l_expected); - end; - - procedure remove_test_package is - pragma autonomous_transaction; - begin - execute immediate 'drop package check_escape_special_chars'; - execute immediate 'drop package check_trims_long_output'; - end; - -end; -/ diff --git a/test/core/reporters/test_tfs_junit_reporter.pkb b/test/core/reporters/test_tfs_junit_reporter.pkb deleted file mode 100644 index bd09b8682..000000000 --- a/test/core/reporters/test_tfs_junit_reporter.pkb +++ /dev/null @@ -1,207 +0,0 @@ -create or replace package body test_tfs_junit_reporter as - - procedure crate_a_test_package is - pragma autonomous_transaction; - begin - execute immediate q'[create or replace package check_junit_reporting is - --%suite(A suite with ) - - --%test(A test with ) - procedure test_do_stuff; - - end;]'; - execute immediate q'[create or replace package body check_junit_reporting is - procedure test_do_stuff is - begin - ut3.ut.expect(1).to_equal(1); - ut3.ut.expect(1).to_equal(2); - end; - - end;]'; - - execute immediate q'[create or replace package check_junit_rep_suitepath is - --%suitepath(core) - --%suite(check_junit_rep_suitepath) - --%displayname(Check JUNIT Get path for suitepath) - - --%test(check_junit_rep_suitepath) - --%displayname(Check JUNIT Get path for suitepath) - procedure check_junit_rep_suitepath; - end;]'; - execute immediate q'[create or replace package body check_junit_rep_suitepath is - procedure check_junit_rep_suitepath is - begin - ut3.ut.expect(1).to_equal(1); - end; - end;]'; - - execute immediate q'[create or replace package check_junit_flat_suitepath is - --%suitepath(core.check_junit_rep_suitepath) - --%suite(flatsuitepath) - - --%beforeall - procedure donuffin; - end;]'; - execute immediate q'[create or replace package body check_junit_flat_suitepath is - procedure donuffin is - begin - null; - end; - end;]'; - - - execute immediate q'[create or replace package check_fail_escape is - --%suitepath(core) - --%suite(checkfailedescape) - --%displayname(Check JUNIT XML failure is escaped) - - --%test(Fail Miserably) - procedure fail_miserably; - - end;]'; - - execute immediate q'[create or replace package body check_fail_escape is - procedure fail_miserably is - begin - ut3.ut.expect('test').to_equal(''); - end; - end;]'; - - end; - - - procedure escapes_special_chars is - l_results ut3.ut_varchar2_list; - l_actual clob; - begin - --Act - select * - bulk collect into l_results - from table(ut3.ut.run('check_junit_reporting',ut3.ut_tfs_junit_reporter())); - l_actual := ut3.ut_utils.table_to_clob(l_results); - --Assert - ut.expect(l_actual).not_to_be_like('%%'); - ut.expect(l_actual).to_be_like('%<tag>%'); - end; - - procedure reports_only_failed_or_errored is - l_results ut3.ut_varchar2_list; - l_actual clob; - begin - --Act - select * - bulk collect into l_results - from table(ut3.ut.run('check_junit_reporting',ut3.ut_tfs_junit_reporter())); - l_actual := ut3.ut_utils.table_to_clob(l_results); - --Assert - ut.expect(l_actual).not_to_be_like('%Actual: 1 (number) was expected to equal: 1 (number)%'); - ut.expect(l_actual).to_be_like('%Actual: 1 (number) was expected to equal: 2 (number)%'); - end; - - procedure reports_failed_line is - l_results ut3.ut_varchar2_list; - l_actual clob; - begin - --Act - select * - bulk collect into l_results - from table(ut3.ut.run('check_junit_reporting',ut3.ut_tfs_junit_reporter())); - l_actual := ut3.ut_utils.table_to_clob(l_results); - --Assert - ut.expect(l_actual).to_be_like('%at "%.CHECK_JUNIT_REPORTING%", line %'); - end; - - procedure check_classname_suite is - l_results ut3.ut_varchar2_list; - l_actual clob; - begin - --Act - select * - bulk collect into l_results - from table(ut3.ut.run('check_junit_reporting',ut3.ut_tfs_junit_reporter())); - l_actual := ut3.ut_utils.table_to_clob(l_results); - --Assert - ut.expect(l_actual).to_be_like('%testcase classname="check_junit_reporting"%'); - end; - - procedure check_flatten_nested_suites is - l_results ut3.ut_varchar2_list; - l_actual clob; - begin - --Act - select * - bulk collect into l_results - from table(ut3.ut.run('check_junit_flat_suitepath',ut3.ut_tfs_junit_reporter())); - l_actual := ut3.ut_utils.table_to_clob(l_results); - --Assert - ut.expect(l_actual).to_be_like(' - - - - - -%'); - end; - - procedure check_nls_number_formatting is - l_results ut3.ut_varchar2_list; - l_actual clob; - l_nls_numeric_characters varchar2(30); - begin - --Arrange - select nsp.value into l_nls_numeric_characters - from nls_session_parameters nsp - where parameter = 'NLS_NUMERIC_CHARACTERS'; - execute immediate q'[alter session set NLS_NUMERIC_CHARACTERS=', ']'; - --Act - select * - bulk collect into l_results - from table(ut3.ut.run('check_junit_reporting', ut3.ut_tfs_junit_reporter())); - l_actual := ut3.ut_utils.table_to_clob(l_results); - --Assert - ut.expect(l_actual).to_match('time="[0-9]*\.[0-9]{3,6}"'); - --Cleanup - execute immediate 'alter session set NLS_NUMERIC_CHARACTERS='''||l_nls_numeric_characters||''''; - end; - - procedure check_failure_escaped is - l_results ut3.ut_varchar2_list; - l_actual clob; - begin - --Act - select * - bulk collect into l_results - from table(ut3.ut.run('check_fail_escape',ut3.ut_tfs_junit_reporter())); - l_actual := ut3.ut_utils.table_to_clob(l_results); - --Assert - ut.expect(l_actual).to_be_like('%Actual: 'test' (varchar2) was expected to equal: '<![CDATA[some stuff]]>' (varchar2)%'); - end; - - procedure check_classname_suitepath is - l_results ut3.ut_varchar2_list; - l_actual clob; - begin - --Act - select * - bulk collect into l_results - from table(ut3.ut.run('check_junit_rep_suitepath',ut3.ut_tfs_junit_reporter())); - l_actual := ut3.ut_utils.table_to_clob(l_results); - --Assert - ut.expect(l_actual).to_be_like('%testcase classname="core.check_junit_rep_suitepath"%'); - end; - procedure remove_test_package is - pragma autonomous_transaction; - begin - execute immediate 'drop package check_junit_reporting'; - execute immediate 'drop package check_junit_rep_suitepath'; - execute immediate 'drop package check_junit_flat_suitepath'; - execute immediate 'drop package check_fail_escape'; - end; - - procedure check_encoding_included is - begin - reporters.check_xml_encoding_included(ut3.ut_tfs_junit_reporter(), 'UTF-8'); - end; - -end; -/ diff --git a/test/core/test_file_mapper.pkb b/test/core/test_file_mapper.pkb deleted file mode 100644 index 34b38f108..000000000 --- a/test/core/test_file_mapper.pkb +++ /dev/null @@ -1,45 +0,0 @@ -create or replace package body test_file_mapper is - - procedure default_mappings is - l_actual ut3.ut_file_mappings; - l_expected ut3.ut_file_mappings; - begin - --Arrange - l_expected := ut3.ut_file_mappings( - ut3.ut_file_mapping('C:\tests\helpers\core.pkb',USER,'CORE','PACKAGE BODY'), - ut3.ut_file_mapping('tests/helpers/test_file_mapper.pkb',USER,'TEST_FILE_MAPPER','PACKAGE BODY') - ); - --Act - l_actual := ut3.ut_file_mapper.build_file_mappings( - ut3.ut_varchar2_list( - 'C:\tests\helpers\core.pkb', - 'tests/helpers/test_file_mapper.pkb' - ) - ); - --Assert - ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); - end; - - procedure specific_owner is - l_actual ut3.ut_file_mappings; - l_expected ut3.ut_file_mappings; - begin - --Arrange - l_expected := ut3.ut_file_mappings( - ut3.ut_file_mapping('C:\source\core\types\ut_file_mapping.tpb','UT3','UT_FILE_MAPPING','TYPE BODY'), - ut3.ut_file_mapping('source/core/ut_file_mapper.pkb','UT3','UT_FILE_MAPPER','PACKAGE BODY') - ); - --Act - l_actual := ut3.ut_file_mapper.build_file_mappings( - 'UT3', - ut3.ut_varchar2_list( - 'C:\source\core\types\ut_file_mapping.tpb', - 'source/core/ut_file_mapper.pkb' - ) - ); - --Assert - ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); - end; - -end; -/ diff --git a/test/core/test_output_buffer.pkb b/test/core/test_output_buffer.pkb deleted file mode 100644 index a22f3772d..000000000 --- a/test/core/test_output_buffer.pkb +++ /dev/null @@ -1,71 +0,0 @@ -create or replace package body test_output_buffer is - - procedure test_recieve is - l_result varchar2(4000); - l_remaining integer; - l_expected varchar2(4000); - l_buffer ut3.ut_output_buffer_base := ut3.ut_output_table_buffer(); - begin - --Act - l_expected := lpad('a text',4000,',a text'); - l_buffer.send_line(l_expected); - - select * into l_result from table(l_buffer.get_lines(0,0)); - - ut.expect(l_result).to_equal(l_expected); - - select count(1) into l_remaining from ut3.ut_output_buffer_tmp where output_id = l_buffer.output_id; - - ut.expect(l_remaining).to_equal(0); - end; - - procedure test_doesnt_send_on_null_text is - l_cur sys_refcursor; - l_result integer; - l_buffer ut3.ut_output_buffer_base := ut3.ut_output_table_buffer(); - begin - delete from ut3.ut_output_buffer_tmp; - --Act - l_buffer.send_line(null); - - open l_cur for select * from ut3.ut_output_buffer_tmp; - ut.expect(l_cur).to_be_empty; - end; - - procedure test_send_line is - l_result varchar2(4000); - c_expected constant varchar2(4000) := lpad('a text',4000,',a text'); - l_buffer ut3.ut_output_buffer_base := ut3.ut_output_table_buffer(); - begin - l_buffer.send_line(c_expected); - - select text into l_result from ut3.ut_output_buffer_tmp where output_id = l_buffer.output_id; - - ut.expect(l_result).to_equal(c_expected); - end; - - procedure test_waiting_for_data is - l_result varchar2(4000); - l_remaining integer; - l_expected varchar2(4000); - l_buffer ut3.ut_output_buffer_base := ut3.ut_output_table_buffer(); - l_start timestamp; - l_duration interval day to second; - begin - --Act - l_expected := lpad('a text',4000,',a text'); - l_buffer.send_line(l_expected); - l_start := localtimestamp; - select * into l_result from table(l_buffer.get_lines(1,1)); - l_duration := localtimestamp - l_start; - - ut.expect(l_result).to_equal(l_expected); - ut.expect(l_duration).to_be_greater_than(interval '0.99' second); - select count(1) into l_remaining from ut3.ut_output_buffer_tmp where output_id = l_buffer.output_id; - - ut.expect(l_remaining).to_equal(0); - - end; - -end test_output_buffer; -/ diff --git a/test/core/test_output_buffer.pks b/test/core/test_output_buffer.pks deleted file mode 100644 index 1392b39ad..000000000 --- a/test/core/test_output_buffer.pks +++ /dev/null @@ -1,19 +0,0 @@ -create or replace package test_output_buffer is - - --%suite(output_buffer) - --%suitepath(utplsql.core) - - --%test(Receives a line from buffer table and deletes) - procedure test_recieve; - - --%test(Does not send line if null text given) - procedure test_doesnt_send_on_null_text; - - --%test(Sends a line into buffer table) - procedure test_send_line; - - --%test(Waits For The Data To Appear For Specified Time) - procedure test_waiting_for_data; - -end test_output_buffer; -/ diff --git a/test/core/test_suite_builder.pkb b/test/core/test_suite_builder.pkb deleted file mode 100644 index 19ea81aa0..000000000 --- a/test/core/test_suite_builder.pkb +++ /dev/null @@ -1,1056 +0,0 @@ -create or replace package body test_suite_builder is - - function invoke_builder_for_annotations( - 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_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) - ) ) x; - l_suites := ut3.ut_suite_builder.build_suites(l_cursor).schema_suites; - l_suite := l_suites(l_suites.first); - - select deletexml( - xmltype(l_suite), - '//RESULTS_COUNT|//START_TIME|//END_TIME|//RESULT|//ASSOCIATED_EVENT_NAME' || - '|//TRANSACTION_INVALIDATORS|//ERROR_BACKTRACE|//ERROR_STACK|//SERVEROUTPUT' - ) - into l_xml - from dual; - - return l_xml.getClobVal(); - end; - - procedure no_suite_description is - l_actual clob; - l_annotations ut3.ut_annotations; - begin - --Arrange - l_annotations := ut3.ut_annotations( - ut3.ut_annotation(1, 'suite',null, null) - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_match( - 'UT3_TESTERsome_packagesome_package()?\s*some_package' - ); - end; - - procedure suite_description_from_suite is - l_actual clob; - l_annotations ut3.ut_annotations; - begin - --Arrange - l_annotations := ut3.ut_annotations( - ut3.ut_annotation(1, 'suite','Some description', null), - ut3.ut_annotation(2, 'suite','Another description', null) - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%some_packageSome description%' - ); - end; - - procedure suitepath_from_non_empty_path is - l_actual clob; - l_annotations ut3.ut_annotations; - begin - --Arrange - l_annotations := ut3.ut_annotations( - ut3.ut_annotation(1, 'suite',null, null), - ut3.ut_annotation(2, 'suitepath','org.utplsql.some', null), - ut3.ut_annotation(3, 'suitepath','dummy.utplsql.some', null) - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%org.utplsql.some%' - ); - end; - - procedure suite_descr_from_displayname is - l_actual clob; - l_annotations ut3.ut_annotations; - begin - --Arrange - l_annotations := ut3.ut_annotations( - ut3.ut_annotation(1, 'suite','Some description', null), - ut3.ut_annotation(2, 'suite','Another description', null), - ut3.ut_annotation(3, 'displayname','New description', null), - ut3.ut_annotation(4, 'displayname','Newest description', null) - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%some_packageNew description%' - ); - end; - - procedure rollback_type_valid is - l_actual clob; - l_annotations ut3.ut_annotations; - begin - --Arrange - l_annotations := ut3.ut_annotations( - ut3.ut_annotation(1, 'suite',null, null), - ut3.ut_annotation(2, 'rollback','manual', null), - ut3.ut_annotation(3, 'rollback','bad', null) - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%'||ut3.ut_utils.gc_rollback_manual||'%' - ); - end; - - procedure rollback_type_duplicated is - l_actual clob; - l_annotations ut3.ut_annotations; - begin - --Arrange - l_annotations := ut3.ut_annotations( - ut3.ut_annotation(1, 'suite',null, null), - ut3.ut_annotation(2, 'rollback','manual', null), - ut3.ut_annotation(3, 'rollback','bad', null) - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%%"--%rollback"%%UT3_TESTER.SOME_PACKAGE%3%%' - ); - end; - - procedure suite_annot_duplicated is - l_actual clob; - l_annotations ut3.ut_annotations; - begin - --Arrange - l_annotations := ut3.ut_annotations( - ut3.ut_annotation(2, 'suite','Cool', null), - ut3.ut_annotation(8, 'suite','bad', null) - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%Cool%%"--%suite"%UT3_TESTER.SOME_PACKAGE%line 8%%' - ); - end; - - procedure test_annotation is - l_actual clob; - l_annotations ut3.ut_annotations; - begin - --Arrange - l_annotations := ut3.ut_annotations( - ut3.ut_annotation(2, 'suite','Cool', null), - ut3.ut_annotation(8, 'test','Some test', 'test_procedure') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%' || - '%test_procedureSome testsome_package.test_procedure' || - '%%' - ); - end; - - procedure test_annot_duplicated is - l_actual clob; - l_annotations ut3.ut_annotations; - begin - --Arrange - l_annotations := ut3.ut_annotations( - ut3.ut_annotation(2, 'suite','Cool', null), - ut3.ut_annotation(8, 'test','Some test', 'test_procedure'), - ut3.ut_annotation(9, 'test','Dup', 'test_procedure') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%Cool%%"--%test"%UT3_TESTER.SOME_PACKAGE.TEST_PROCEDURE%line 9%%' - ); - end; - - procedure beforeall_annot_duplicated is - l_actual clob; - l_annotations ut3.ut_annotations; - begin - --Arrange - l_annotations := ut3.ut_annotations( - ut3.ut_annotation(2, 'suite','Cool', null), - ut3.ut_annotation(8, 'beforeall', null, 'test_procedure'), - ut3.ut_annotation(9, 'beforeall', null, 'test_procedure') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%Cool%%"--%beforeall"%UT3_TESTER.SOME_PACKAGE.TEST_PROCEDURE%line 9%%' - ); - end; - - procedure beforeeach_annot_duplicated is - l_actual clob; - l_annotations ut3.ut_annotations; - begin - --Arrange - l_annotations := ut3.ut_annotations( - ut3.ut_annotation(2, 'suite','Cool', null), - ut3.ut_annotation(8, 'beforeeach', null, 'test_procedure'), - ut3.ut_annotation(9, 'beforeeach', null, 'test_procedure') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%Cool%%"--%beforeeach"%UT3_TESTER.SOME_PACKAGE.TEST_PROCEDURE%line 9%%' - ); - end; - - procedure afterall_annot_duplicated is - l_actual clob; - l_annotations ut3.ut_annotations; - begin - --Arrange - l_annotations := ut3.ut_annotations( - ut3.ut_annotation(2, 'suite','Cool', null), - ut3.ut_annotation(8, 'afterall', null, 'test_procedure'), - ut3.ut_annotation(9, 'afterall', null, 'test_procedure') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%Cool%%"--%afterall"%UT3_TESTER.SOME_PACKAGE.TEST_PROCEDURE%line 9%%' - ); - end; - - procedure aftereach_annot_duplicated is - l_actual clob; - l_annotations ut3.ut_annotations; - begin - --Arrange - l_annotations := ut3.ut_annotations( - ut3.ut_annotation(2, 'suite','Cool', null), - ut3.ut_annotation(8, 'aftereach', null, 'test_procedure'), - ut3.ut_annotation(9, 'aftereach', null, 'test_procedure') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%Cool%%"--%aftereach"%UT3_TESTER.SOME_PACKAGE.TEST_PROCEDURE%line 9%%' - ); - end; - - procedure suitepath_annot_duplicated is - l_actual clob; - l_annotations ut3.ut_annotations; - begin - --Arrange - l_annotations := ut3.ut_annotations( - ut3.ut_annotation(2, 'suite','Cool', null), - ut3.ut_annotation(3, 'suitepath','dummy.utplsql.some', null), - ut3.ut_annotation(4, 'suitepath','org.utplsql.some', null) - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%%"--%suitepath"%line 4%%' - ); - end; - - procedure displayname_annot_duplicated is - l_actual clob; - l_annotations ut3.ut_annotations; - begin - --Arrange - l_annotations := ut3.ut_annotations( - ut3.ut_annotation(2, 'suite','Cool', null), - ut3.ut_annotation(4, 'displayname','New description', null), - ut3.ut_annotation(5, 'displayname','Newest description', null) - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%%"--%displayname"%line 5%%' - ); - end; - - procedure suitepath_annot_empty 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(3, 'suitepath',null, null) - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%%"--%suitepath" annotation requires a non-empty parameter value.%%' - ); - end; - - procedure suitepath_annot_invalid_path 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, 'suitepath','path with spaces', null) - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%%Invalid path value in annotation "--%suitepath(path with spaces)"%%' - ); - end; - - procedure displayname_annot_empty 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(3, 'displayname',null, null) - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%%"--%displayname" annotation requires a non-empty parameter value.%%' - ); - end; - - procedure rollback_type_empty 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(3, 'rollback',null, null) - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%%"--%rollback" annotation requires one of values as parameter:%%' - ); - end; - - procedure rollback_type_invalid 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, 'rollback','bad', null) - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%%"--%rollback" annotation requires one of values as parameter: "auto" or "manual". Annotation ignored.%%' - ); - end; - - procedure multiple_before_after 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, 'first_before_all'), - ut3.ut_annotation(3, 'beforeall',null, 'another_before_all'), - ut3.ut_annotation(4, 'beforeeach',null, 'first_bfore_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'), - ut3.ut_annotation(8, 'afterall',null, 'first_after_all'), - ut3.ut_annotation(9, 'afterall',null, 'another_after_all'), - ut3.ut_annotation(14, 'test','A test', 'some_test'), - ut3.ut_annotation(15, 'beforetest','before_test_proc', 'some_test'), - ut3.ut_annotation(16, 'beforetest','before_test_proc2', 'some_test'), - ut3.ut_annotation(18, 'aftertest','after_test_proc', 'some_test'), - ut3.ut_annotation(20, 'aftertest','after_test_proc2', 'some_test') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%%some_package%some_test' || - '%' || - '%some_packagefirst_bfore_each' || - '%some_packageanother_before_each' || - '%' || - '%' || - '%some_packagebefore_test_proc' || - '%some_packagebefore_test_proc2' || - '%' || - '%' || - '%some_packageafter_test_proc' || - '%some_packageafter_test_proc2' || - '%' || - '%' || - '%some_packagefirst_after_each' || - '%some_packageanother_after_each' || - '%' || - '%' || - '%' || - '%some_packagefirst_before_all' || - '%some_packageanother_before_all' || - '%' || - '%' || - '%some_packagefirst_after_all' || - '%some_packageanother_after_all' || - '%%' - ); - end; - - procedure multiple_standalone_bef_aft 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', 'some_package.first_before_all',null), - ut3.ut_annotation(3, 'beforeall', 'different_package.another_before_all',null), - ut3.ut_annotation(4, 'beforeeach', 'first_before_each',null), - ut3.ut_annotation(5, 'beforeeach', 'different_owner.different_package.another_before_each',null), - ut3.ut_annotation(6, 'aftereach', 'first_after_each',null), - ut3.ut_annotation(7, 'aftereach', 'another_after_each,different_owner.different_package.one_more_after_each',null), - ut3.ut_annotation(8, 'afterall', 'first_after_all',null), - ut3.ut_annotation(9, 'afterall', 'another_after_all',null), - ut3.ut_annotation(14, 'test','A test', 'some_test'), - ut3.ut_annotation(15, 'beforetest','before_test_proc', 'some_test'), - ut3.ut_annotation(16, 'beforetest','before_test_proc2', 'some_test'), - ut3.ut_annotation(18, 'aftertest','after_test_proc', 'some_test'), - ut3.ut_annotation(20, 'aftertest','after_test_proc2', 'some_test') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%%some_package%some_test' || - '%' || - '%some_packagefirst_before_each' || - '%different_ownerdifferent_packageanother_before_each' || - '%' || - '%' || - '%some_packagebefore_test_proc' || - '%some_packagebefore_test_proc2' || - '%' || - '%' || - '%some_packageafter_test_proc' || - '%some_packageafter_test_proc2' || - '%' || - '%' || - '%some_packagefirst_after_each' || - '%some_packageanother_after_each' || - '%different_ownerdifferent_packageone_more_after_each' || - '%' || - '%' || - '%' || - '%some_packagefirst_before_all' || - '%different_packageanother_before_all' || - '%' || - '%' || - '%some_packagefirst_after_all' || - '%some_packageanother_after_all' || - '%%' - ); - end; - - procedure before_after_on_single_proc 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, 'do_stuff'), - ut3.ut_annotation(3, 'beforeeach',null, 'do_stuff'), - ut3.ut_annotation(4, 'aftereach',null, 'do_stuff'), - ut3.ut_annotation(5, 'afterall',null, 'do_stuff'), - ut3.ut_annotation(6, 'test','A test', 'some_test') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%%some_package%some_test' || - '%' || - '%some_packagedo_stuff' || - '%' || - '%' || - '%some_packagedo_stuff' || - '%' || - '%' || - '%' || - '%some_packagedo_stuff' || - '%' || - '%' || - '%some_packagedo_stuff' || - '%%' - ); - end; - - procedure multiple_mixed_bef_aft 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,'first_before_all'), - ut3.ut_annotation(3, 'beforeall', 'different_package.another_before_all',null), - ut3.ut_annotation(4, 'beforeeach', 'first_before_each',null), - ut3.ut_annotation(5, 'beforeeach', 'different_owner.different_package.another_before_each',null), - ut3.ut_annotation(6, 'aftereach', null, 'first_after_each'), - ut3.ut_annotation(7, 'aftereach', 'another_after_each,different_owner.different_package.one_more_after_each',null), - ut3.ut_annotation(8, 'afterall', 'first_after_all',null), - ut3.ut_annotation(9, 'afterall', 'another_after_all',null), - ut3.ut_annotation(14, 'test','A test', 'some_test'), - ut3.ut_annotation(15, 'beforetest','before_test_proc', 'some_test'), - ut3.ut_annotation(16, 'beforetest','before_test_proc2', 'some_test'), - ut3.ut_annotation(18, 'aftertest','after_test_proc', 'some_test'), - ut3.ut_annotation(20, 'aftertest','after_test_proc2', 'some_test'), - ut3.ut_annotation(21, 'beforeall', null,'last_before_all'), - ut3.ut_annotation(22, 'aftereach', null, 'last_after_each'), - ut3.ut_annotation(23, 'afterall', null, 'last_after_all') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%%some_package%some_test' || - '%' || - '%some_packagefirst_before_each' || - '%different_ownerdifferent_packageanother_before_each' || - '%' || - '%' || - '%some_packagebefore_test_proc' || - '%some_packagebefore_test_proc2' || - '%' || - '%' || - '%some_packageafter_test_proc' || - '%some_packageafter_test_proc2' || - '%' || - '%' || - '%some_packagefirst_after_each' || - '%some_packageanother_after_each' || - '%different_ownerdifferent_packageone_more_after_each' || - '%some_packagelast_after_each' || - '%' || - '%' || - '%' || - '%some_packagefirst_before_all' || - '%different_packageanother_before_all' || - '%some_packagelast_before_all' || - '%' || - '%' || - '%some_packagefirst_after_all' || - '%some_packageanother_after_all' || - '%some_packagelast_after_all' || - '%%' - ); - end; - - - procedure before_after_mixed_with_test 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, 'do_stuff'), - ut3.ut_annotation(3, 'beforeeach',null, 'do_stuff'), - ut3.ut_annotation(4, 'aftereach',null, 'do_stuff'), - ut3.ut_annotation(5, 'afterall',null, 'do_stuff'), - ut3.ut_annotation(6, 'test','A test', 'do_stuff') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like('%%Annotation "--\%beforeall"%line 2%%', '\'); - ut.expect(l_actual).to_be_like('%%Annotation "--\%beforeeach"%line 3%%', '\'); - ut.expect(l_actual).to_be_like('%%Annotation "--\%aftereach"%line 4%%', '\'); - ut.expect(l_actual).to_be_like('%%Annotation "--\%afterall" cannot be used with "--\%test". Annotation ignored.' - ||'%at "UT3_TESTER.SOME_PACKAGE.DO_STUFF", line 5%%', '\'); - ut.expect(l_actual).not_to_be_like('%%'); - ut.expect(l_actual).not_to_be_like('%%'); - ut.expect(l_actual).not_to_be_like('%%'); - ut.expect(l_actual).not_to_be_like('%%'); - end; - - procedure suite_from_context 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) - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - 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 before_after_in_context 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, 'test', 'In suite', 'suite_level_test'), - ut3.ut_annotation(3, 'context', 'a_context', null), - ut3.ut_annotation(4, 'beforeall', 'context_beforeall', null), - ut3.ut_annotation(5, 'beforeeach', null, 'context_beforeeach'), - ut3.ut_annotation(6, 'test', 'In context', 'test_in_a_context'), - ut3.ut_annotation(7, 'aftereach', 'context_aftereach' ,null), - ut3.ut_annotation(8, 'afterall', null, 'context_afterall'), - ut3.ut_annotation(9, 'endcontext', null, null) - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '' || - '%' || - '%' || - '%a_context' || - '%' || - '%' || - '%test_in_a_context' || - '%%context_beforeeach%' || - '%%test_in_a_context%' || - '%%context_aftereach%' || - '%' || - '%' || - '%%context_beforeall%' || - '%%context_afterall%' || - '%' || - '%' || - '%suite_level_test' || - '%%suite_level_test%' || - '%' || - '%' || - '%' - ); - ut.expect(l_actual).not_to_be_like('%%%%%%'); - ut.expect(l_actual).not_to_be_like('%%%%%%'); - ut.expect(l_actual).not_to_be_like('%%%%%%'); - ut.expect(l_actual).not_to_be_like('%%%%%%'); - end; - - procedure before_after_out_of_context 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, 'beforeeach',null, 'suite_level_beforeeach'), - ut3.ut_annotation(4, 'test','In suite', 'suite_level_test'), - ut3.ut_annotation(5, 'context','a_context', null), - ut3.ut_annotation(6, 'test', 'In context', 'test_in_a_context'), - ut3.ut_annotation(7, 'endcontext',null, null), - ut3.ut_annotation(8, 'aftereach',null, 'suite_level_aftereach'), - ut3.ut_annotation(9, 'afterall',null, 'suite_level_afterall') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '' || - '%' || - '%' || - '%a_context' || - '%' || - '%' || - '%test_in_a_context' || - '%%suite_level_beforeeach%' || - '%%test_in_a_context%' || - '%%suite_level_aftereach%' || - '%' || - '%' || - '%' || - '%' || - '%suite_level_test' || - '%%suite_level_beforeeach%' || - '%%suite_level_test%' || - '%%suite_level_aftereach%' || - '%' || - '%' || - '%%suite_level_beforeall%' || - '%%suite_level_afterall%' || - '%' - ); - ut.expect(l_actual).not_to_be_like('%%%%%%'); - ut.expect(l_actual).not_to_be_like('%%%%%%'); - end; - - procedure context_without_endcontext 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, 'beforeall',null, 'context_setup'), - ut3.ut_annotation(7, 'test', 'In context', 'test_in_a_context') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%Invalid annotation "--\%context". Cannot find following "--\%endcontext". Annotation ignored.%at "UT3_TESTER.SOME_PACKAGE", line 4%' - ,'\' - ); - ut.expect(l_actual).to_be_like( - '' || - '%' || - '' || - '%suite_level_testIn suitesome_package.suite_level_test' || - '%' || - '' || - '%test_in_a_contextIn contextsome_package.test_in_a_context' || - '%' || - '' || - '' || - '%some_packagesuite_level_beforeall' || - '%some_packagecontext_setup' || - '%' || - '' || - '' - ); - end; - - procedure endcontext_without_context 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, 'endcontext',null, null) - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%Invalid annotation "--\%endcontext". Cannot find preceding "--\%context". Annotation 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; - begin - --Arrange - l_annotations := ut3.ut_annotations( - ut3.ut_annotation(1, 'suite','Cool', null), - ut3.ut_annotation(3, 'test','A test with empty throws annotation', 'A_TEST_PROCEDURE'), - ut3.ut_annotation(3, 'throws',null, 'A_TEST_PROCEDURE') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%%"--%throws" annotation requires a parameter. Annotation ignored.%%' - ); - end; - - procedure throws_value_invalid 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(3, 'test','A test with invalid throws annotation', 'A_TEST_PROCEDURE'), - ut3.ut_annotation(3, 'throws',' -20145 , bad_variable_name ', 'A_TEST_PROCEDURE') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%%Invalid parameter value "bad_variable_name" for "--%throws" annotation. Parameter ignored.%%' - ); - end; - - - procedure before_aftertest_multi 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(14, 'test','A test', 'some_test'), - ut3.ut_annotation(15, 'beforetest','before_test_proc', 'some_test'), - ut3.ut_annotation(16, 'beforetest','before_test_proc2', 'some_test'), - ut3.ut_annotation(18, 'aftertest','after_test_proc', 'some_test'), - ut3.ut_annotation(20, 'aftertest','after_test_proc2', 'some_test') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%%some_package%some_test' || - '%' || - '%some_packagebefore_test_proc' || - '%some_packagebefore_test_proc2' || - '%' || - '%' || - '%some_packageafter_test_proc' || - '%some_packageafter_test_proc2' || - '%' || - '%%' - ); - end; - - procedure before_aftertest_twice 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(14, 'test','A test', 'some_test'), - ut3.ut_annotation(15, 'beforetest','before_test_proc, before_test_proc2', 'some_test'), - ut3.ut_annotation(16, 'beforetest','before_test_proc3', 'some_test'), - ut3.ut_annotation(18, 'aftertest','after_test_proc,after_test_proc2', 'some_test'), - ut3.ut_annotation(20, 'aftertest','after_test_proc3', 'some_test') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%%some_package%some_test' || - '%' || - '%some_packagebefore_test_proc' || - '%some_packagebefore_test_proc2' || - '%some_packagebefore_test_proc3' || - '%' || - '%' || - '%some_packageafter_test_proc' || - '%some_packageafter_test_proc2' || - '%some_packageafter_test_proc3' || - '%' || - '%%' - ); - end; - - procedure before_aftertest_pkg_proc 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(14, 'test','A test', 'some_test'), - ut3.ut_annotation(15, 'beforetest','external_package.before_test_proc', 'some_test'), - ut3.ut_annotation(18, 'aftertest','external_package.after_test_proc', 'some_test') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%%some_package%some_test' || - '%' || - '%external_packagebefore_test_proc' || - '%' || - '%' || - '%external_packageafter_test_proc' || - '%' || - '%%' - ); - end; - - procedure before_aftertest_mixed_syntax 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(14, 'test','A test', 'some_test'), - ut3.ut_annotation(15, 'beforetest','external_package.before_test_proc, before_test_proc2', 'some_test'), - ut3.ut_annotation(18, 'aftertest','external_package.after_test_proc, after_test_proc2', 'some_test') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%%some_package%some_test' || - '%' || - '%external_packagebefore_test_proc' || - '%some_packagebefore_test_proc2' || - '%' || - '%' || - '%external_packageafter_test_proc' || - '%some_packageafter_test_proc2' || - '%' || - '%%' - ); - end; - - procedure test_annotation_ordering 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(4, 'test','B test', 'b_test'), - ut3.ut_annotation(10, 'test','Z test', 'z_test'), - ut3.ut_annotation(14, 'test','A test', 'a_test') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like( - '%%some_package%b_test' || - '%%'|| - '%%some_package%z_test' || - '%%'|| - '%%some_package%a_test' || - '%%' - ); - end; - - procedure test_bad_procedure_annotation 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, 'bad_procedure_annotation',null, 'some_procedure'), - ut3.ut_annotation(6, 'test','A test', 'do_stuff') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like('%Unsupported annotation "--\%bad_procedure_annotation". Annotation ignored.% line 2%', '\'); - end; - - procedure test_bad_package_annotation 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(17, 'bad_package_annotation',null, null), - ut3.ut_annotation(24, 'test','A test', 'do_stuff') - ); - --Act - l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); - --Assert - ut.expect(l_actual).to_be_like('%Unsupported annotation "--\%bad_package_annotation". Annotation ignored.% line 17%', '\'); - end; - -end test_suite_builder; -/ diff --git a/test/core/test_suite_builder.pks b/test/core/test_suite_builder.pks deleted file mode 100644 index 36517432b..000000000 --- a/test/core/test_suite_builder.pks +++ /dev/null @@ -1,178 +0,0 @@ -create or replace package test_suite_builder is - --%suite(suite_builder) - --%suitepath(utplsql.core) - - --%context(suite) - --%displayname(--%suite annotation) - - --%test(Sets suite name from package name and leaves description empty) - procedure no_suite_description; - - --%test(Sets suite description using first --%suite annotation) - procedure suite_description_from_suite; - - --%test(Gives warning if more than one --%suite annotation used) - procedure suite_annot_duplicated; - - --%endcontext - - --%context(displayname) - --%displayname(--%displayname annotation) - - --%test(Overrides suite description using first --%displayname annotation) - procedure suite_descr_from_displayname; - - --%test(Gives warning if more than one --%displayname annotation used) - procedure displayname_annot_duplicated; - - --%test(Gives warning if --%displayname annotation has no value) - procedure displayname_annot_empty; - - --%endcontext - - --%context(test) - --%displayname(--%test annotation) - - --%test(Creates a test item for procedure annotated with --%test annotation) - procedure test_annotation; - - --%test(Gives warning if more than one --%test annotation used) - procedure test_annot_duplicated; - - --%endcontext - - --%context(suitepath) - --%displayname(--%suitepath annotation) - - --%test(Sets suite path using first --%suitepath annotation) - procedure suitepath_from_non_empty_path; - - --%test(Gives warning if more than one --%suitepath annotation used) - procedure suitepath_annot_duplicated; - - --%test(Gives warning if --%suitepath annotation has no value) - procedure suitepath_annot_empty; - - --%test(Gives warning if --%suitepath annotation has invalid value) - procedure suitepath_annot_invalid_path; - - --%endcontext - - --%context(rollback) - --%displayname(--%rollback annotation) - - --%test(Sets rollback type using first --%rollback annotation) - procedure rollback_type_valid; - - --%test(Gives warning if more than one --%rollback annotation used) - procedure rollback_type_duplicated; - - --%test(Gives warning if --%rollback annotation has no value) - procedure rollback_type_empty; - - --%test(Gives warning if --%rollback annotation has invalid value) - procedure rollback_type_invalid; - - --%endcontext - - --%context(before_after_all_each) - --%displayname(--%before/after all/each annotations) - - --%test(Supports multiple before/after all/each procedure level definitions) - procedure multiple_before_after; - - --%test(Supports multiple before/after all/each standalone level definitions) - procedure multiple_standalone_bef_aft; - - --%test(Supports mixing before/after all/each annotations on single procedure) - procedure before_after_on_single_proc; - - --%test(Supports mixed before/after all/each as standalone and procedure level definitions) - procedure multiple_mixed_bef_aft; - - --%test(Gives warning if more than one --%beforeall annotation used on procedure) - procedure beforeall_annot_duplicated; - - --%test(Gives warning if more than one --%beforeeach annotation used on procedure) - procedure beforeeach_annot_duplicated; - - --%test(Gives warning if more than one --%afterall annotation used on procedure) - procedure afterall_annot_duplicated; - - --%test(Gives warning if more than one --%aftereach annotation used on procedure) - procedure aftereach_annot_duplicated; - - --%test(Gives warning on before/after all/each annotations mixed with test) - procedure before_after_mixed_with_test; - - --%endcontext - - --%context(context) - --%displayname(--%context annotation) - - --%test(Creates nested suite for content between context/endcontext annotations) - procedure suite_from_context; - - --%test(Associates before/after all/each to tests in context only) - procedure before_after_in_context; - - --%test(Propagates beforeeach/aftereach to context) - procedure before_after_out_of_context; - - --%test(Does not create context and gives warning when endcontext is missing) - procedure context_without_endcontext; - - --%test(Gives warning if --%endcontext is missing a preceding --%context) - procedure endcontext_without_context; - - --%endcontext - - --%context(throws) - --%displayname(--%throws annotation) - - --%test(Gives warning if --%throws annotation has no value) - procedure throws_value_empty; - - --%test(Gives warning if --%throws annotation has invalid value) - procedure throws_value_invalid; - - --%endcontext - - --%context(beforetest_aftertest) - --%displayname(--%beforetest/aftertest annotation) - - --%test(Supports multiple occurrences of beforetest/aftertest for a test) - procedure before_aftertest_multi; - - --%test(Supports same procedure defined twice) - procedure before_aftertest_twice; - - --%test(Supports beforetest from external package) - procedure before_aftertest_pkg_proc; - - --%test(Supports mix of procedure and package.procedure) - procedure before_aftertest_mixed_syntax; - - --%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) - - --%test(Gives warning when unknown procedure level annotation passed) - procedure test_bad_procedure_annotation; - - --%test(Gives warning when unknown package level annotation passed) - procedure test_bad_package_annotation; - - --%endcontext - -end test_suite_builder; -/ diff --git a/test/core/test_suite_manager.pkb b/test/core/test_suite_manager.pkb deleted file mode 100644 index 59f1f42ea..000000000 --- a/test/core/test_suite_manager.pkb +++ /dev/null @@ -1,1437 +0,0 @@ -create or replace package body test_suite_manager is - - ex_obj_doesnt_exist exception; - pragma exception_init(ex_obj_doesnt_exist, -04043); - - procedure compile_dummy_packages is - pragma autonomous_transaction; - begin - execute immediate q'[create or replace package test_package_1 is - - --%suite - --%displayname(test_package_1) - --%suitepath(tests) - --%rollback(manual) - - gv_glob_val number; - - --%beforeeach - procedure global_setup; - - --%aftereach - procedure global_teardown; - - --%test - --%displayname(Test1 from test package 1) - procedure test1; - - --%test(Test2 from test package 1) - --%beforetest(test2_setup) - --%aftertest(test2_teardown) - procedure test2; - - procedure test2_setup; - - procedure test2_teardown; - -end test_package_1;]'; - - execute immediate q'[create or replace package body test_package_1 is - gv_var_1 number; - gv_var_1_temp number; - - procedure global_setup is - begin - gv_var_1 := 1; - gv_glob_val := 1; - end; - - procedure global_teardown is - begin - gv_var_1 := 0; - gv_glob_val := 0; - end; - - procedure test1 is - begin - ut.expect(gv_var_1, 'Some expectation').to_equal(1); - end; - - procedure test2 is - begin - ut.expect(gv_var_1, 'Some expectation').to_equal(2); - end; - - procedure test2_setup is - begin - gv_var_1_temp := gv_var_1; - gv_var_1 := 2; - end; - - procedure test2_teardown is - begin - gv_var_1 := gv_var_1_temp; - gv_var_1_temp := null; - end; - -end test_package_1;]'; - - execute immediate q'[create or replace package test_package_2 is - --%suite - --%suitepath(tests.test_package_1) - - gv_glob_val varchar2(1); - - --%beforeeach - procedure global_setup; - - --%aftereach - procedure global_teardown; - - --%test - procedure test1; - - --%test - --%beforetest(test2_setup) - --%aftertest(test2_teardown) - procedure test2; - - procedure test2_setup; - - procedure test2_teardown; - - --%beforeall - procedure context_setup; - - --%test(Test in a context) - procedure context_test; - - --%afterall - procedure context_teardown; - -end test_package_2;]'; - - execute immediate q'[create or replace package body test_package_2 is - gv_var_1 varchar2(1); - gv_var_1_temp varchar2(1); - - procedure global_setup is - begin - gv_var_1 := 'a'; - gv_glob_val := 'z'; - end; - - procedure global_teardown is - begin - gv_var_1 := 'n'; - gv_glob_val := 'n'; - end; - - procedure test1 is - begin - ut.expect(gv_var_1).to_equal('a'); - end; - - procedure test2 is - begin - ut.expect(gv_var_1).to_equal('b'); - end; - - procedure test2_setup is - begin - gv_var_1_temp := gv_var_1; - gv_var_1 := 'b'; - end; - - procedure test2_teardown is - begin - gv_var_1 := gv_var_1_temp; - gv_var_1_temp := null; - end; - - procedure context_setup is - begin - gv_var_1_temp := gv_var_1 || 'a'; - end; - - procedure context_test is - begin - ut.expect(gv_var_1_temp, 'Some expectation').to_equal('na'); - end; - - procedure context_teardown is - begin - gv_var_1_temp := null; - end; - -end test_package_2;]'; - - execute immediate q'[create or replace package test_package_3 is - --%suite - --%suitepath(tests2) - --%rollback(auto) - - gv_glob_val number; - - --%beforeeach - procedure global_setup; - - --%aftereach - procedure global_teardown; - - --%test - --%rollback(auto) - procedure test1; - - --%test - --%beforetest(test2_setup) - --%aftertest(test2_teardown) - procedure test2; - - procedure test2_setup; - - procedure test2_teardown; - - --%test - --%disabled - procedure disabled_test; - -end test_package_3;]'; - - execute immediate q'[create or replace package body test_package_3 is - gv_var_1 number; - gv_var_1_temp number; - - procedure global_setup is - begin - gv_var_1 := 1; - gv_glob_val := 1; - end; - - procedure global_teardown is - begin - gv_var_1 := 0; - gv_glob_val := 0; - end; - - procedure test1 is - begin - ut.expect(gv_var_1).to_equal(1); - end; - - procedure test2 is - begin - ut.expect(gv_var_1).to_equal(2); - end; - - procedure test2_setup is - begin - gv_var_1_temp := gv_var_1; - gv_var_1 := 2; - end; - - procedure test2_teardown is - begin - gv_var_1 := gv_var_1_temp; - gv_var_1_temp := null; - end; - - procedure disabled_test is - begin - null; - end; - -end test_package_3;]'; - - execute immediate q'[create or replace package test_package_with_ctx is - - --%suite(test_package_with_ctx) - - gv_glob_val number; - - --%context(some_context) - --%displayname(Some context description) - - --%test - --%displayname(Test1 from test package 1) - procedure test1; - - --%endcontext - -end test_package_with_ctx;]'; - - execute immediate q'[create or replace package body test_package_with_ctx is - - procedure test1 is - begin - null; - end; - -end test_package_with_ctx;]'; - end; - - - procedure drop_dummy_packages is - pragma autonomous_transaction; - begin - execute immediate 'drop package test_package_1'; - execute immediate 'drop package test_package_2'; - execute immediate 'drop package test_package_3'; - execute immediate 'drop package test_package_with_ctx'; - end; - - procedure test_schema_run is - c_path constant varchar2(100) := USER; - l_objects_to_run ut3.ut_suite_items := ut3.ut_suite_items(); - l_all_objects_to_run ut3.ut_suite_items; - - l_test0_suite ut3.ut_logical_suite; - l_test1_suite ut3.ut_logical_suite; - l_test2_suite ut3.ut_logical_suite; - begin - --Act - l_all_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(c_path)); - - for i in 1..l_all_objects_to_run.count loop - if l_all_objects_to_run(i).name in ('tests', 'tests2') then - l_objects_to_run.extend; - l_objects_to_run(l_objects_to_run.last) := l_all_objects_to_run(i); - end if; - end loop; - - --Assert - ut.expect(l_objects_to_run.count).to_equal(2); - - for i in 1 .. 2 loop - l_test0_suite := treat(l_objects_to_run(i) as ut3.ut_logical_suite); - ut.expect(l_test0_suite.name in ('tests', 'tests2')).to_be_true; - - l_test1_suite := treat(l_test0_suite.items(1) as ut3.ut_logical_suite); - - case l_test0_suite.name - when 'tests' then - 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); - - ut.expect(l_test2_suite.name).to_equal('test_package_2'); - ut.expect(l_test2_suite.items.count).to_equal(3); - ut.expect(l_test2_suite.rollback_type).to_equal(ut3.ut_utils.gc_rollback_manual); - when 'tests2' then - ut.expect(l_test1_suite.name).to_equal('test_package_3'); - ut.expect(l_test1_suite.items.count).to_equal(3); - end case; - - end loop; - - end; - - procedure test_top2_by_name is - c_path varchar2(100) := USER||'.test_package_2'; - l_objects_to_run ut3.ut_suite_items; - - l_test0_suite ut3.ut_logical_suite; - l_test1_suite ut3.ut_logical_suite; - l_test2_suite ut3.ut_logical_suite; - begin - --Act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(c_path)); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - l_test0_suite := treat(l_objects_to_run(1) as ut3.ut_logical_suite); - - ut.expect(l_test0_suite.name).to_equal('tests'); - ut.expect(l_test0_suite.items.count).to_equal(1); - l_test1_suite := treat(l_test0_suite.items(1) as ut3.ut_logical_suite); - - ut.expect(l_test1_suite.name).to_equal('test_package_1'); - ut.expect(l_test1_suite.items.count).to_equal(1); - ut.expect(l_test1_suite.rollback_type).to_equal(ut3.ut_utils.gc_rollback_manual); - 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.rollback_type).to_equal(ut3.ut_utils.gc_rollback_manual); - ut.expect(l_test2_suite.items.count).to_equal(3); - end; - - procedure test_top2_bt_name_cur_user is - c_path varchar2(100) := 'test_package_2'; - l_objects_to_run ut3.ut_suite_items; - - l_test0_suite ut3.ut_logical_suite; - l_test1_suite ut3.ut_logical_suite; - l_test2_suite ut3.ut_logical_suite; - begin - --Act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(c_path)); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - l_test0_suite := treat(l_objects_to_run(1) as ut3.ut_logical_suite); - - ut.expect(l_test0_suite.name).to_equal('tests'); - ut.expect(l_test0_suite.items.count).to_equal(1); - l_test1_suite := treat(l_test0_suite.items(1) as ut3.ut_logical_suite); - - ut.expect(l_test1_suite.name).to_equal('test_package_1'); - ut.expect(l_test1_suite.items.count).to_equal(1); - ut.expect(l_test1_suite.rollback_type).to_equal(ut3.ut_utils.gc_rollback_manual); - 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.rollback_type).to_equal(ut3.ut_utils.gc_rollback_manual); - ut.expect(l_test2_suite.items.count).to_equal(3); - end; - - procedure test_by_path_to_subsuite is - c_path varchar2(100) := USER||':tests.test_package_1.test_package_2'; - l_objects_to_run ut3.ut_suite_items; - - l_test0_suite ut3.ut_logical_suite; - l_test1_suite ut3.ut_logical_suite; - l_test2_suite ut3.ut_logical_suite; - begin - --Act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(c_path)); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - l_test0_suite := treat(l_objects_to_run(1) as ut3.ut_logical_suite); - - ut.expect(l_test0_suite.name).to_equal('tests'); - ut.expect(l_test0_suite.items.count).to_equal(1); - l_test1_suite := treat(l_test0_suite.items(1) as ut3.ut_logical_suite); - - ut.expect(l_test1_suite.name).to_equal('test_package_1'); - ut.expect(l_test1_suite.items.count).to_equal(1); - 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); - end; - - procedure test_by_path_to_subsuite_cu is - c_path varchar2(100) := ':tests.test_package_1.test_package_2'; - l_objects_to_run ut3.ut_suite_items; - - l_test0_suite ut3.ut_logical_suite; - l_test1_suite ut3.ut_logical_suite; - l_test2_suite ut3.ut_logical_suite; - begin - --Act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(c_path)); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - l_test0_suite := treat(l_objects_to_run(1) as ut3.ut_logical_suite); - - ut.expect(l_test0_suite.name).to_equal('tests'); - ut.expect(l_test0_suite.items.count).to_equal(1); - l_test1_suite := treat(l_test0_suite.items(1) as ut3.ut_logical_suite); - - ut.expect(l_test1_suite.name).to_equal('test_package_1'); - ut.expect(l_test1_suite.items.count).to_equal(1); - 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); - end; - - procedure test_subsute_proc_by_path is - c_path varchar2(100) := USER||':tests.test_package_1.test_package_2.test2'; - l_objects_to_run ut3.ut_suite_items; - - l_test0_suite ut3.ut_logical_suite; - l_test1_suite ut3.ut_logical_suite; - l_test2_suite ut3.ut_logical_suite; - l_test_proc ut3.ut_test; - begin - --Act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(c_path)); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - l_test0_suite := treat(l_objects_to_run(1) as ut3.ut_logical_suite); - - ut.expect(l_test0_suite.name).to_equal('tests'); - ut.expect(l_test0_suite.items.count).to_equal(1); - l_test1_suite := treat(l_test0_suite.items(1) as ut3.ut_logical_suite); - - ut.expect(l_test1_suite.name).to_equal('test_package_1'); - ut.expect(l_test1_suite.rollback_type).to_equal(ut3.ut_utils.gc_rollback_manual); - ut.expect(l_test1_suite.items.count).to_equal(1); - 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.rollback_type).to_equal(ut3.ut_utils.gc_rollback_manual); - ut.expect(l_test2_suite.items.count).to_equal(1); - - l_test_proc := treat(l_test2_suite.items(1) as ut3.ut_test); - ut.expect(l_test_proc.name).to_equal('test2'); - ut.expect(l_test_proc.rollback_type).to_equal(ut3.ut_utils.gc_rollback_manual); - ut.expect(l_test_proc.before_test_list.count).to_be_greater_than(0); - ut.expect(l_test_proc.after_test_list.count).to_be_greater_than(0); - - end; - - procedure test_subsute_proc_by_path_cu is - c_path varchar2(100) := ':tests.test_package_1.test_package_2.test2'; - l_objects_to_run ut3.ut_suite_items; - - l_test0_suite ut3.ut_logical_suite; - l_test1_suite ut3.ut_logical_suite; - l_test2_suite ut3.ut_logical_suite; - l_test_proc ut3.ut_test; - begin - --Act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(c_path)); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - l_test0_suite := treat(l_objects_to_run(1) as ut3.ut_logical_suite); - - ut.expect(l_test0_suite.name).to_equal('tests'); - ut.expect(l_test0_suite.items.count).to_equal(1); - l_test1_suite := treat(l_test0_suite.items(1) as ut3.ut_logical_suite); - - ut.expect(l_test1_suite.name).to_equal('test_package_1'); - ut.expect(l_test1_suite.items.count).to_equal(1); - 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(1); - - l_test_proc := treat(l_test2_suite.items(1) as ut3.ut_test); - ut.expect(l_test_proc.name).to_equal('test2'); - ut.expect(l_test_proc.before_test_list.count).to_be_greater_than(0); - ut.expect(l_test_proc.after_test_list.count).to_be_greater_than(0); - end; - - procedure test_top_pack_by_name is - c_path varchar2(100) := USER||'.test_package_1'; - l_objects_to_run ut3.ut_suite_items; - - 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)); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - l_test0_suite := treat(l_objects_to_run(1) as ut3.ut_logical_suite); - - ut.expect(l_test0_suite.name).to_equal('tests'); - ut.expect(l_test0_suite.items.count).to_equal(1); - 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(1).name).to_equal('test1'); - ut.expect(l_test1_suite.items(1).description).to_equal('Test1 from test package 1'); - ut.expect(treat(l_test1_suite.items(1) as ut3.ut_test).before_test_list.count).to_equal(0); - ut.expect(treat(l_test1_suite.items(1) as ut3.ut_test).after_test_list.count).to_equal(0); - ut.expect(treat(l_test1_suite.items(1) as ut3.ut_test).before_each_list.count).to_be_greater_than(0); - ut.expect(treat(l_test1_suite.items(1) as ut3.ut_test).disabled_flag).to_equal(0); - - ut.expect(l_test1_suite.items(2).name).to_equal('test2'); - ut.expect(l_test1_suite.items(2).description).to_equal('Test2 from test package 1'); - ut.expect(treat(l_test1_suite.items(2) as ut3.ut_test).before_test_list.count).to_be_greater_than(0); - ut.expect(treat(l_test1_suite.items(2) as ut3.ut_test).after_test_list.count).to_be_greater_than(0); - 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 - c_path varchar2(100) := 'test_package_1'; - l_objects_to_run ut3.ut_suite_items; - - 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)); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - l_test0_suite := treat(l_objects_to_run(1) as ut3.ut_logical_suite); - - ut.expect(l_test0_suite.name).to_equal('tests'); - ut.expect(l_test0_suite.items.count).to_equal(1); - 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(1).name).to_equal('test1'); - ut.expect(l_test1_suite.items(1).description).to_equal('Test1 from test package 1'); - ut.expect(treat(l_test1_suite.items(1) as ut3.ut_test).before_test_list.count).to_equal(0); - ut.expect(treat(l_test1_suite.items(1) as ut3.ut_test).after_test_list.count).to_equal(0); - ut.expect(treat(l_test1_suite.items(1) as ut3.ut_test).before_each_list.count).to_be_greater_than(0); - ut.expect(treat(l_test1_suite.items(1) as ut3.ut_test).disabled_flag).to_equal(0); - - ut.expect(l_test1_suite.items(2).name).to_equal('test2'); - ut.expect(l_test1_suite.items(2).description).to_equal('Test2 from test package 1'); - ut.expect(treat(l_test1_suite.items(2) as ut3.ut_test).before_test_list.count).to_be_greater_than(0); - ut.expect(treat(l_test1_suite.items(2) as ut3.ut_test).after_test_list.count).to_be_greater_than(0); - 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 - c_path varchar2(100) := USER||':tests'; - l_objects_to_run ut3.ut_suite_items; - - l_test0_suite ut3.ut_logical_suite; - l_test1_suite ut3.ut_logical_suite; - l_test2_suite ut3.ut_logical_suite; - begin - --Act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(c_path)); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - l_test0_suite := treat(l_objects_to_run(1) as ut3.ut_logical_suite); - - ut.expect(l_test0_suite.name).to_equal('tests'); - ut.expect(l_test0_suite.items.count).to_equal(1); - l_test1_suite := treat(l_test0_suite.items(1) as ut3.ut_logical_suite); - - 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); - - 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_cu is - c_path varchar2(100) := ':tests'; - l_objects_to_run ut3.ut_suite_items; - - l_test0_suite ut3.ut_logical_suite; - l_test1_suite ut3.ut_logical_suite; - l_test2_suite ut3.ut_logical_suite; - begin - --Act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(c_path)); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - l_test0_suite := treat(l_objects_to_run(1) as ut3.ut_logical_suite); - - ut.expect(l_test0_suite.name).to_equal('tests'); - ut.expect(l_test0_suite.items.count).to_equal(1); - l_test1_suite := treat(l_test0_suite.items(1) as ut3.ut_logical_suite); - - 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); - - 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_pck_proc_by_path is - c_path varchar2(100) := USER||':tests.test_package_1.test2'; - l_objects_to_run ut3.ut_suite_items; - - l_test0_suite ut3.ut_logical_suite; - l_test1_suite ut3.ut_logical_suite; - l_test2_suite ut3.ut_logical_suite; - l_test_proc ut3.ut_test; - begin - --Act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(c_path)); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - l_test0_suite := treat(l_objects_to_run(1) as ut3.ut_logical_suite); - - ut.expect(l_test0_suite.name).to_equal('tests'); - ut.expect(l_test0_suite.items.count).to_equal(1); - l_test1_suite := treat(l_test0_suite.items(1) as ut3.ut_logical_suite); - - ut.expect(l_test1_suite.name).to_equal('test_package_1'); - ut.expect(l_test1_suite.items.count).to_equal(1); - l_test_proc := treat(l_test1_suite.items(1) as ut3.ut_test); - - ut.expect(l_test_proc.name).to_equal('test2'); - ut.expect(l_test_proc.description).to_equal('Test2 from test package 1'); - ut.expect(l_test_proc.before_test_list.count).to_be_greater_than(0); - ut.expect(l_test_proc.after_test_list.count).to_be_greater_than(0); - end; - - procedure test_top_pck_proc_by_path_cu is - c_path varchar2(100) := ':tests.test_package_1.test2'; - l_objects_to_run ut3.ut_suite_items; - - l_test0_suite ut3.ut_logical_suite; - l_test1_suite ut3.ut_logical_suite; - l_test2_suite ut3.ut_logical_suite; - l_test_proc ut3.ut_test; - begin - --Act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(c_path)); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - l_test0_suite := treat(l_objects_to_run(1) as ut3.ut_logical_suite); - - ut.expect(l_test0_suite.name).to_equal('tests'); - ut.expect(l_test0_suite.items.count).to_equal(1); - l_test1_suite := treat(l_test0_suite.items(1) as ut3.ut_logical_suite); - - ut.expect(l_test1_suite.name).to_equal('test_package_1'); - ut.expect(l_test1_suite.items.count).to_equal(1); - l_test_proc := treat(l_test1_suite.items(1) as ut3.ut_test); - - ut.expect(l_test_proc.name).to_equal('test2'); - ut.expect(l_test_proc.description).to_equal('Test2 from test package 1'); - ut.expect(l_test_proc.before_test_list.count).to_be_greater_than(0); - ut.expect(l_test_proc.after_test_list.count).to_be_greater_than(0); - end; - - procedure test_top_pkc_proc_by_name is - c_path varchar2(100) := USER||'.test_package_1.test2'; - l_objects_to_run ut3.ut_suite_items; - - l_test0_suite ut3.ut_logical_suite; - l_test1_suite ut3.ut_logical_suite; - l_test_proc ut3.ut_test; - begin - --Act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(c_path)); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - l_test0_suite := treat(l_objects_to_run(1) as ut3.ut_logical_suite); - - ut.expect(l_test0_suite.name).to_equal('tests'); - ut.expect(l_test0_suite.items.count).to_equal(1); - l_test1_suite := treat(l_test0_suite.items(1) as ut3.ut_logical_suite); - - ut.expect(l_test1_suite.name).to_equal('test_package_1'); - ut.expect(l_test1_suite.items.count).to_equal(1); - - l_test_proc := treat(l_test1_suite.items(1) as ut3.ut_test); - ut.expect(l_test_proc.name).to_equal('test2'); - ut.expect(l_test_proc.before_test_list.count).to_be_greater_than(0); - ut.expect(l_test_proc.after_test_list.count).to_be_greater_than(0); - end; - - procedure test_top_pkc_proc_by_name_cu is - c_path varchar2(100) := 'test_package_1.test2'; - l_objects_to_run ut3.ut_suite_items; - - l_test0_suite ut3.ut_logical_suite; - l_test1_suite ut3.ut_logical_suite; - l_test_proc ut3.ut_test; - begin - --Act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(c_path)); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - l_test0_suite := treat(l_objects_to_run(1) as ut3.ut_logical_suite); - - ut.expect(l_test0_suite.name).to_equal('tests'); - ut.expect(l_test0_suite.items.count).to_equal(1); - l_test1_suite := treat(l_test0_suite.items(1) as ut3.ut_logical_suite); - - ut.expect(l_test1_suite.name).to_equal('test_package_1'); - ut.expect(l_test1_suite.items.count).to_equal(1); - - l_test_proc := treat(l_test1_suite.items(1) as ut3.ut_test); - ut.expect(l_test_proc.name).to_equal('test2'); - ut.expect(l_test_proc.before_test_list.count).to_be_greater_than(0); - ut.expect(l_test_proc.after_test_list.count).to_be_greater_than(0); - end; - - procedure test_top_pkc_nosub_by_name is - c_path varchar2(100) := USER||'.test_package_3'; - l_objects_to_run ut3.ut_suite_items; - - l_test0_suite ut3.ut_logical_suite; - l_test1_suite ut3.ut_logical_suite; - l_test1 ut3.ut_test; - l_test3 ut3.ut_test; - begin - --Act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(c_path)); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - l_test0_suite := treat(l_objects_to_run(1) as ut3.ut_logical_suite); - - ut.expect(l_test0_suite.name).to_equal('tests2'); - ut.expect(l_test0_suite.items.count).to_equal(1); - l_test1_suite := treat(l_test0_suite.items(1) as ut3.ut_logical_suite); - - ut.expect(l_test1_suite.name).to_equal('test_package_3'); - ut.expect(l_test1_suite.items.count).to_equal(3); - - l_test1 := treat(l_test1_suite.items(1) as ut3.ut_test); - ut.expect(l_test1.name).to_equal('test1'); - ut.expect(l_test1.DISABLED_FLAG).to_equal(0); - - l_test3 := treat(l_test1_suite.items(3) as ut3.ut_test); - ut.expect(l_test3.name).to_equal('disabled_test'); - ut.expect(l_test3.DISABLED_FLAG).to_equal(1); - end; - - procedure test_top_pkc_nosub_by_name_cu is - c_path varchar2(100) := 'test_package_3'; - l_objects_to_run ut3.ut_suite_items; - - l_test0_suite ut3.ut_logical_suite; - l_test1_suite ut3.ut_logical_suite; - l_test1 ut3.ut_test; - l_test3 ut3.ut_test; - begin - --Act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(c_path)); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - l_test0_suite := treat(l_objects_to_run(1) as ut3.ut_logical_suite); - - ut.expect(l_test0_suite.name).to_equal('tests2'); - ut.expect(l_test0_suite.items.count).to_equal(1); - l_test1_suite := treat(l_test0_suite.items(1) as ut3.ut_logical_suite); - - ut.expect(l_test1_suite.name).to_equal('test_package_3'); - ut.expect(l_test1_suite.items.count).to_equal(3); - - l_test1 := treat(l_test1_suite.items(1) as ut3.ut_test); - ut.expect(l_test1.name).to_equal('test1'); - ut.expect(l_test1.DISABLED_FLAG).to_equal(0); - - l_test3 := treat(l_test1_suite.items(3) as ut3.ut_test); - ut.expect(l_test3.name).to_equal('disabled_test'); - ut.expect(l_test3.DISABLED_FLAG).to_equal(1); - end; - - procedure test_top_subpck_by_path is - c_path varchar2(100) := USER||':tests2.test_package_3'; - l_objects_to_run ut3.ut_suite_items; - - l_test0_suite ut3.ut_logical_suite; - l_test1_suite ut3.ut_logical_suite; - l_test1 ut3.ut_test; - l_test3 ut3.ut_test; - begin - --Act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(c_path)); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - l_test0_suite := treat(l_objects_to_run(1) as ut3.ut_logical_suite); - - ut.expect(l_test0_suite.name).to_equal('tests2'); - ut.expect(l_test0_suite.items.count).to_equal(1); - l_test1_suite := treat(l_test0_suite.items(1) as ut3.ut_logical_suite); - - ut.expect(l_test1_suite.name).to_equal('test_package_3'); - ut.expect(l_test1_suite.items.count).to_equal(3); - - l_test1 := treat(l_test1_suite.items(1) as ut3.ut_test); - ut.expect(l_test1.name).to_equal('test1'); - ut.expect(l_test1.DISABLED_FLAG).to_equal(0); - - l_test3 := treat(l_test1_suite.items(3) as ut3.ut_test); - ut.expect(l_test3.name).to_equal('disabled_test'); - ut.expect(l_test3.DISABLED_FLAG).to_equal(1); - end; - - procedure test_top_subpck_by_path_cu is - c_path varchar2(100) := ':tests2.test_package_3'; - l_objects_to_run ut3.ut_suite_items; - - l_test0_suite ut3.ut_logical_suite; - l_test1_suite ut3.ut_logical_suite; - l_test1 ut3.ut_test; - l_test3 ut3.ut_test; - begin - --Act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(c_path)); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - l_test0_suite := treat(l_objects_to_run(1) as ut3.ut_logical_suite); - - ut.expect(l_test0_suite.name).to_equal('tests2'); - ut.expect(l_test0_suite.items.count).to_equal(1); - l_test1_suite := treat(l_test0_suite.items(1) as ut3.ut_logical_suite); - - ut.expect(l_test1_suite.name).to_equal('test_package_3'); - ut.expect(l_test1_suite.items.count).to_equal(3); - - l_test1 := treat(l_test1_suite.items(1) as ut3.ut_test); - ut.expect(l_test1.name).to_equal('test1'); - ut.expect(l_test1.DISABLED_FLAG).to_equal(0); - - l_test3 := treat(l_test1_suite.items(3) as ut3.ut_test); - ut.expect(l_test3.name).to_equal('disabled_test'); - ut.expect(l_test3.DISABLED_FLAG).to_equal(1); - end; - - procedure test_search_invalid_pck is - 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_invalid_spec')); - - ut3.ut.expect(l_objects_to_run.count).to_be_greater_than(0); - ut3.ut.expect(l_objects_to_run(l_objects_to_run.first).object_name).to_equal('failing_invalid_spec'); - end; - - procedure compile_invalid_package is - ex_compilation_error exception; - pragma exception_init(ex_compilation_error,-24344); - pragma autonomous_transaction; - begin - begin - execute immediate q'[create or replace package failing_invalid_spec as - --%suite - gv_glob_val non_existing_table.id%type := 0; - - --%beforeall - procedure before_all; - --%test - procedure test1; - --%test - procedure test2; -end;]'; - exception when ex_compilation_error then null; - end; - begin - execute immediate q'[create or replace package body failing_invalid_spec as - procedure before_all is begin gv_glob_val := 1; end; - procedure test1 is begin ut.expect(1).to_equal(1); end; - procedure test2 is begin ut.expect(1).to_equal(1); end; -end;]'; - exception when ex_compilation_error then null; - end; - end; - procedure drop_invalid_package is - pragma autonomous_transaction; - begin - execute immediate 'drop package failing_invalid_spec'; - end; - - procedure test_search_nonexisting_pck is - 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'); - exception - when others then - ut.expect(sqlerrm).to_be_like('%failing_non_existing%'); - end; - - procedure test_search_nonexist_sch_pck is - 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'); - exception - when others then - ut.expect(sqlerrm).to_be_like('%ORA-44001: invalid schema%'); - end; - - procedure test_desc_with_comma is - l_objects_to_run ut3.ut_suite_items; - l_suite ut3.ut_suite; - l_test ut3.ut_test; - begin - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list('tst_package_to_be_dropped')); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - - l_suite := treat(l_objects_to_run(1) as ut3.ut_suite); - - ut.expect(l_suite.name).to_equal('tst_package_to_be_dropped'); - ut.expect(l_suite.description).to_equal('A suite description, though with comma, is assigned by suite_manager'); - ut.expect(l_suite.items.count).to_equal(2); - - l_test := treat(l_suite.items(1) as ut3.ut_test); - - 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'); - - end; - procedure setup_desc_with_comma is - pragma autonomous_transaction; - begin - execute immediate 'create or replace package tst_package_to_be_dropped as - --%suite(A suite description, though with comma, is assigned by suite_manager) - - --%test(A test description, though with comma, is assigned by suite_manager) - procedure test1; - - --%test - --%displayname(A test description, though with comma, is assigned by suite_manager) - procedure test2; -end;'; - - execute immediate '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;'; - end; - procedure clean_desc_with_comma is - pragma autonomous_transaction; - begin - begin - execute immediate 'drop package tst_package_to_be_dropped'; - exception - when ex_obj_doesnt_exist then - null; - end; - end; - - procedure test_inv_cache_on_drop is - l_test_report ut3.ut_varchar2_list; - begin - - select * bulk collect into l_test_report from table(ut3.ut.run(USER||'.tst_package_to_be_dropped')); - - -- drop package - clean_inv_cache_on_drop; - - begin - select * bulk collect into l_test_report from table(ut3.ut.run(user || '.tst_package_to_be_dropped')); - 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%'); - end; - - end; - procedure setup_inv_cache_on_drop is - pragma autonomous_transaction; - begin - execute immediate 'create or replace package tst_package_to_be_dropped as - --%suite - - --%test - procedure test1; -end;'; - - execute immediate '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;'; - end; - - procedure clean_inv_cache_on_drop is - pragma autonomous_transaction; - begin - execute immediate 'drop package tst_package_to_be_dropped'; - exception - when ex_obj_doesnt_exist then - null; - end; - - procedure test_inv_pck_bodies is - l_test_report ut3.ut_varchar2_list; - begin - - select * bulk collect into l_test_report from table(ut3.ut.run(USER||'.test_dependencies')); - - ut.expect(l_test_report(l_test_report.count-1)).to_be_like('1 test_, 0 failed, 0 errored, 0 disabled, 0 warning(s)'); - --execute immediate 'select * from table(ut3.ut.run(''UT3.test_dependencies'', ut3.utplsql_test_reporter()))' into l_result; - --- ut.expect(l_result).to_equal(ut3.ut_utils.gc_success); - end; - procedure setup_inv_pck_bodies is - pragma autonomous_transaction; - begin - execute immediate 'create table test_dependency_table (id integer)'; - execute immediate 'create or replace package test_dependencies as - -- %suite - - -- %test - procedure dependant; -end;'; - execute immediate 'create or replace package body test_dependencies as - gc_dependant_variable test_dependency_table.id%type; - procedure dependant is begin null; end; -end;'; - - execute immediate 'alter table test_dependency_table modify id number'; - - end; - procedure clean_inv_pck_bodies is - pragma autonomous_transaction; - begin - execute immediate 'drop table test_dependency_table'; - execute immediate 'drop package test_dependencies'; - end; - - procedure test_pck_with_dollar is - l_objects_to_run ut3.ut_suite_items; - l_suite ut3.ut_suite; - begin - --act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list('tst_package_with$dollar')); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - - l_suite := treat(l_objects_to_run(1) as ut3.ut_suite); - ut.expect(l_suite.name).to_equal('tst_package_with$dollar'); - end; - procedure setup_pck_with_dollar is - pragma autonomous_transaction; - begin - execute immediate 'create or replace package tst_package_with$dollar as - --%suite - - --%test - procedure test1; -end;'; - - execute immediate 'create or replace package body tst_package_with$dollar as - procedure test1 is begin ut.expect(1).to_equal(1); end; - procedure test2 is begin ut.expect(1).to_equal(1); end; -end;'; - end; - procedure clean_pck_with_dollar is - pragma autonomous_transaction; - begin - execute immediate 'drop package tst_package_with$dollar'; - end; - - - procedure test_pck_with_hash is - l_objects_to_run ut3.ut_suite_items; - l_suite ut3.ut_suite; - begin - --act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list('tst_package_with#hash')); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - - l_suite := treat(l_objects_to_run(1) as ut3.ut_suite); - ut.expect(l_suite.name).to_equal('tst_package_with#hash'); - end; - procedure setup_pck_with_hash is - pragma autonomous_transaction; - begin - execute immediate 'create or replace package tst_package_with#hash as - --%suite - - --%test - procedure test1; -end;'; - - execute immediate 'create or replace package body tst_package_with#hash as - procedure test1 is begin ut.expect(1).to_equal(1); end; - procedure test2 is begin ut.expect(1).to_equal(1); end; -end;'; - end; - procedure clean_pck_with_hash is - pragma autonomous_transaction; - begin - execute immediate 'drop package tst_package_with#hash'; - end; - - - procedure test_test_with_dollar is - l_objects_to_run ut3.ut_suite_items; - l_suite ut3.ut_suite; - l_test ut3.ut_test; - begin - --act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list('tst_package_with_dollar_test.test$1')); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - - l_suite := treat(l_objects_to_run(1) as ut3.ut_suite); - - ut.expect(l_suite.name).to_equal('tst_package_with_dollar_test'); - ut.expect(l_suite.items.count).to_equal(1); - - l_test := treat(l_suite.items(1) as ut3.ut_test); - - ut.expect(l_test.name).to_equal('test$1'); - - end; - procedure setup_test_with_dollar is - pragma autonomous_transaction; - begin - execute immediate 'create or replace package tst_package_with_dollar_test as - --%suite - - --%test - procedure test$1; -end;'; - - execute immediate 'create or replace package body tst_package_with_dollar_test as - procedure test$1 is begin ut.expect(1).to_equal(1); end; -end;'; - end; - procedure clean_test_with_dollar is - pragma autonomous_transaction; - begin - execute immediate 'drop package tst_package_with_dollar_test'; - end; - - procedure test_test_with_hash is - l_objects_to_run ut3.ut_suite_items; - l_suite ut3.ut_suite; - l_test ut3.ut_test; - begin - --act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list('tst_package_with_hash_test.test#1')); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - - l_suite := treat(l_objects_to_run(1) as ut3.ut_suite); - - ut.expect(l_suite.name).to_equal('tst_package_with_hash_test'); - ut.expect(l_suite.items.count).to_equal(1); - - l_test := treat(l_suite.items(1) as ut3.ut_test); - - ut.expect(l_test.name).to_equal('test#1'); - - end; - procedure setup_test_with_hash is - pragma autonomous_transaction; - begin - execute immediate 'create or replace package tst_package_with_hash_test as - --%suite - - --%test - procedure test#1; -end;'; - - execute immediate 'create or replace package body tst_package_with_hash_test as - procedure test#1 is begin ut.expect(1).to_equal(1); end; -end;'; - end; - procedure clean_test_with_hash is - pragma autonomous_transaction; - begin - execute immediate 'drop package tst_package_with_hash_test'; - end; - - procedure test_empty_suite_path is - l_objects_to_run ut3.ut_suite_items; - l_suite ut3.ut_suite; - begin - - --act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.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 ut3.ut_suite); - - ut.expect(l_suite.name).to_equal('tst_empty_suite_path'); - end; - - procedure setup_empty_suite_path is - pragma autonomous_transaction; - begin - execute immediate 'create or replace package tst_empty_suite_path as - --%suite - --%suitepath - - --%test - procedure test1; -end;'; - execute immediate 'create or replace package body tst_empty_suite_path as - procedure test1 is begin ut.expect(1).to_equal(1); end; -end;'; - end; - - procedure clean_empty_suite_path is - pragma autonomous_transaction; - begin - execute immediate 'drop package tst_empty_suite_path'; - end; - - procedure test_pck_with_same_path is - l_objects_to_run ut3.ut_suite_items; - l_suite1 ut3.ut_logical_suite; - l_suite2 ut3.ut_logical_suite; - l_suite3 ut3.ut_suite; - begin - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(':test1.test2$.test_package_same_1')); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - - l_suite1 := treat(l_objects_to_run(1) as ut3.ut_logical_suite); - ut.expect(l_suite1.name).to_equal('test1'); - ut.expect(l_suite1.items.count).to_equal(1); - - l_suite2 := treat(l_suite1.items(1) as ut3.ut_logical_suite); - ut.expect(l_suite2.name).to_equal('test2$'); - ut.expect(l_suite2.items.count).to_equal(1); - - l_suite3 := treat(l_suite2.items(1) as ut3.ut_suite); - ut.expect(l_suite3.name).to_equal('test_package_same_1'); - end; - - procedure setup_pck_with_same_path is - pragma autonomous_transaction; - begin - execute immediate 'create or replace package test_package_same_1 as - --%suite - --%suitepath(test1.test2$) - - --%test - procedure test1; -end;'; - execute immediate 'create or replace package body test_package_same_1 as - procedure test1 is begin null; end; -end;'; - execute immediate 'create or replace package test_package_same_1_a as - --%suite - --%suitepath(test1.test2$) - - --%test - procedure test1; -end;'; - execute immediate 'create or replace package body test_package_same_1_a as - procedure test1 is begin null; end; -end;'; - end; - - procedure clean_pck_with_same_path is - pragma autonomous_transaction; - begin - execute immediate 'drop package test_package_same_1'; - execute immediate 'drop package test_package_same_1_a'; - end; - - procedure setup_disabled_pck is - pragma autonomous_transaction; - begin - execute immediate q'[create or replace package test_disabled_floating as - --%suite - - --%test - procedure test1; - - --%disabled - - --%test - procedure test2; - -end;]'; - end; - - procedure clean_disabled_pck is - pragma autonomous_transaction; - begin - execute immediate 'drop package test_disabled_floating'; - end; - - procedure disable_suite_floating_annot is - l_objects_to_run ut3.ut_suite_items; - l_suite ut3.ut_suite; - begin - --Arrange - setup_disabled_pck; - --Act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list('test_disabled_floating')); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - l_suite := treat(l_objects_to_run(1) as ut3.ut_suite); - ut.expect(l_suite.name).to_equal('test_disabled_floating'); - ut.expect(l_suite.get_disabled_flag()).to_be_true(); - - clean_disabled_pck; - end; - - procedure pck_proc_in_ctx_by_name is - c_path varchar2(100) := USER||'.test_package_with_ctx.test1'; - l_objects_to_run ut3.ut_suite_items; - - l_test_suite ut3.ut_logical_suite; - l_ctx_suite ut3.ut_logical_suite; - l_test_proc ut3.ut_test; - begin - --Act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(c_path)); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - - l_test_suite := treat(l_objects_to_run(1) as ut3.ut_logical_suite); - ut.expect(l_test_suite.name).to_equal('test_package_with_ctx'); - ut.expect(l_test_suite.items.count).to_equal(1); - - l_ctx_suite := treat(l_test_suite.items(1) as ut3.ut_logical_suite); - ut.expect(l_ctx_suite.name).to_equal('some_context'); - ut.expect(l_ctx_suite.description).to_equal('Some context description'); - ut.expect(l_ctx_suite.items.count).to_equal(1); - - l_test_proc := treat(l_ctx_suite.items(1) as ut3.ut_test); - ut.expect(l_test_proc.name).to_equal('test1'); - end; - - procedure pck_proc_in_ctx_by_path is - c_path varchar2(100) := USER||':test_package_with_ctx.some_context.test1'; - l_objects_to_run ut3.ut_suite_items; - - l_test_suite ut3.ut_logical_suite; - l_ctx_suite ut3.ut_logical_suite; - l_test_proc ut3.ut_test; - begin - --Act - l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(c_path)); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - - l_test_suite := treat(l_objects_to_run(1) as ut3.ut_logical_suite); - ut.expect(l_test_suite.name).to_equal('test_package_with_ctx'); - ut.expect(l_test_suite.items.count).to_equal(1); - - l_ctx_suite := treat(l_test_suite.items(1) as ut3.ut_logical_suite); - ut.expect(l_ctx_suite.name).to_equal('some_context'); - ut.expect(l_ctx_suite.description).to_equal('Some context description'); - ut.expect(l_ctx_suite.items.count).to_equal(1); - - l_test_proc := treat(l_ctx_suite.items(1) as ut3.ut_test); - ut.expect(l_test_proc.name).to_equal('test1'); - end; - -end test_suite_manager; -/ diff --git a/test/core/test_ut_executable.pkb b/test/core/test_ut_executable.pkb deleted file mode 100644 index 2d4cde518..000000000 --- a/test/core/test_ut_executable.pkb +++ /dev/null @@ -1,105 +0,0 @@ -create or replace package body test_ut_executable is - - g_dbms_output_text varchar2(30) := 'Some output from procedure'; - - procedure exec_schema_package_proc is - l_executable ut3.ut_executable; - l_test ut3.ut_test; - l_result boolean; - begin - --Arrange - l_test := ut3.ut_test(a_object_name => 'test_ut_executable',a_name => 'test_ut_executable'); - 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); - --Assert - ut.expect(l_result).to_be_true; - ut.expect(l_executable.serveroutput).to_be_null; - ut.expect(l_executable.get_error_stack_trace()).to_be_null; - end; - - procedure exec_package_proc_output is - l_executable ut3.ut_executable; - l_test ut3.ut_test; - l_result boolean; - begin - --Arrange - l_test := ut3.ut_test(a_object_name => 'test_ut_executable',a_name => 'test_ut_executable'); - 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); - --Assert - ut.expect(l_result).to_be_true; - ut.expect(l_executable.serveroutput).to_equal(to_clob(g_dbms_output_text||chr(10))); - ut.expect(l_executable.get_error_stack_trace()).to_be_null; - end; - - procedure exec_failing_proc is - l_executable ut3.ut_executable; - l_test ut3.ut_test; - l_result boolean; - begin - --Arrange - l_test := ut3.ut_test(a_object_name => 'test_ut_executable',a_name => 'test_ut_executable'); - 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); - --Assert - ut.expect(l_result).to_be_false; - ut.expect(l_executable.serveroutput).to_be_null; - ut.expect(l_executable.get_error_stack_trace()).to_be_like('ORA-06501: PL/SQL: program error%'); - end; - - procedure modify_stateful_package is - l_job_name varchar2(30) := 'recreate_stateful_package'; - l_cnt integer := 1; - pragma autonomous_transaction; - begin - dbms_scheduler.create_job( - job_name => l_job_name, - job_type => 'PLSQL_BLOCK', - job_action => q'/ - begin - execute immediate q'[ - create or replace package stateful_package as - g_state varchar2(3) := 'abc'; - end;]'; - end;/', - start_date => localtimestamp, - enabled => TRUE, - auto_drop => TRUE, - comments => 'one-time job' - ); - dbms_lock.sleep(0.4); - while l_cnt > 0 loop - select count(1) into l_cnt - from dba_scheduler_running_jobs srj - where srj.job_name = l_job_name; - end loop; - end; - - 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( 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'); - end; - - procedure passing_proc is - begin - null; - end; - - procedure output_proc is - begin - dbms_output.put_line(g_dbms_output_text); - end; - - procedure throwing_proc is - begin - raise program_error; - end; - -end; -/ diff --git a/test/core/test_ut_suite.pkb b/test/core/test_ut_suite.pkb deleted file mode 100644 index c66e25af3..000000000 --- a/test/core/test_ut_suite.pkb +++ /dev/null @@ -1,136 +0,0 @@ -create or replace package body test_ut_suite is - - procedure cleanup_package_state is - begin - ut_example_tests.g_number := null; - end; - - procedure disabled_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.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')); - --Act - l_suite.do_execute(); - --Assert - ut.expect(ut_example_tests.g_number).to_be_null; - ut.expect(l_suite.result).to_equal(ut3.ut_utils.gc_disabled); - ut.expect(l_suite.results_count.disabled_count).to_equal(2); - ut.expect(l_suite.results_count.warnings_count).to_equal(0); - ut.expect(l_suite.results_count.success_count).to_equal(0); - ut.expect(l_suite.results_count.failure_count).to_equal(0); - ut.expect(l_suite.results_count.errored_count).to_equal(0); - end; - - procedure beforeall_errors 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.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')); - --Act - l_suite.do_execute(); - --Assert - ut.expect(ut_example_tests.g_number).to_be_null; - ut.expect(l_suite.result).to_equal(ut3.ut_utils.gc_error); - ut.expect(l_suite.results_count.disabled_count).to_equal(0); - ut.expect(l_suite.results_count.warnings_count).to_equal(0); - ut.expect(l_suite.results_count.success_count).to_equal(0); - ut.expect(l_suite.results_count.failure_count).to_equal(0); - ut.expect(l_suite.results_count.errored_count).to_equal(1); - end; - - procedure aftereall_errors 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.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')); - --Act - l_suite.do_execute(); - --Assert - ut.expect(ut_example_tests.g_number).to_equal(1); - ut.expect(l_suite.result).to_equal(ut3.ut_utils.gc_success); - ut.expect(l_suite.results_count.disabled_count).to_equal(0); - ut.expect(l_suite.results_count.warnings_count).to_equal(1); - ut.expect(l_suite.results_count.success_count).to_equal(2); - ut.expect(l_suite.results_count.failure_count).to_equal(0); - ut.expect(l_suite.results_count.errored_count).to_equal(0); - end; - - 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.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*/)); - --Act - l_suite.do_execute(); - --Assert - ut.expect(l_suite.result).to_equal(ut3.ut_utils.gc_error); - end; - - 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.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*/)); - --Act - l_suite.do_execute(); - --Assert - ut.expect(l_suite.result).to_equal(ut3.ut_utils.gc_error); - end; - - procedure test_rollback_type(a_procedure_name varchar2, a_rollback_type integer, a_expectation ut3_latest_release.ut_matcher) is - l_suite ut3.ut_suite; - 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.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.set_rollback_type(a_rollback_type); - - --Act - l_suite.do_execute(); - - --Assert - ut.expect(core.get_value(q'[ut_transaction_control.count_rows('t')]')).to_( a_expectation ); - ut.expect(core.get_value(q'[ut_transaction_control.count_rows('s')]')).to_( a_expectation ); - end; - - procedure rollback_auto is - begin - test_rollback_type('test', ut3.ut_utils.gc_rollback_auto, equal(0) ); - end; - - procedure rollback_auto_on_failure is - begin - test_rollback_type('test_failure', ut3.ut_utils.gc_rollback_auto, equal(0) ); - end; - - procedure rollback_manual is - begin - test_rollback_type('test', ut3.ut_utils.gc_rollback_manual, be_greater_than(0) ); - end; - - procedure rollback_manual_on_failure is - begin - test_rollback_type('test_failure', ut3.ut_utils.gc_rollback_manual, be_greater_than(0) ); - end; -end; -/ \ No newline at end of file diff --git a/test/core/test_ut_test.pkb b/test/core/test_ut_test.pkb deleted file mode 100644 index ecce27c3c..000000000 --- a/test/core/test_ut_test.pkb +++ /dev/null @@ -1,131 +0,0 @@ -create or replace package body test_ut_test is - - procedure cleanup_package_state is - begin - ut_example_tests.g_number := null; - end; - - procedure disabled_test is - l_suite ut3.ut_suite; - l_test ut3.ut_test; - begin - --Arrange - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS'); - 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(l_suite.items.last).disabled_flag := ut3.ut_utils.boolean_to_int(true); - --Act - l_suite.do_execute(); - --Assert - ut.expect(ut_example_tests.g_number).to_equal(1); - ut.expect(l_suite.result).to_equal(ut3.ut_utils.gc_success); - ut.expect(l_suite.results_count.disabled_count).to_equal(1); - ut.expect(l_suite.results_count.warnings_count).to_equal(0); - ut.expect(l_suite.results_count.success_count).to_equal(1); - ut.expect(l_suite.results_count.failure_count).to_equal(0); - ut.expect(l_suite.results_count.errored_count).to_equal(0); - end; - - procedure aftertest_errors is - l_suite ut3.ut_suite; - l_test ut3.ut_test; - begin - --Arrange - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS'); - 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.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')); - --Act - l_suite.do_execute(); - --Assert - ut.expect(ut_example_tests.g_number).to_equal(3); - ut.expect(l_suite.result).to_equal(ut3.ut_utils.gc_error); - ut.expect(l_suite.results_count.disabled_count).to_equal(0); - ut.expect(l_suite.results_count.warnings_count).to_equal(0); - ut.expect(l_suite.results_count.success_count).to_equal(1); - ut.expect(l_suite.results_count.failure_count).to_equal(0); - ut.expect(l_suite.results_count.errored_count).to_equal(1); - end; - - procedure aftereach_errors is - l_suite ut3.ut_suite; - l_test ut3.ut_test; - begin - --Arrange - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => '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.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')); - --Act - l_suite.do_execute(); - --Assert - ut.expect(ut_example_tests.g_number).to_equal(3); - ut.expect(l_suite.result).to_equal(ut3.ut_utils.gc_error); - ut.expect(l_suite.results_count.disabled_count).to_equal(0); - ut.expect(l_suite.results_count.warnings_count).to_equal(0); - ut.expect(l_suite.results_count.success_count).to_equal(1); - ut.expect(l_suite.results_count.failure_count).to_equal(0); - ut.expect(l_suite.results_count.errored_count).to_equal(1); - end; - - procedure beforetest_errors is - l_suite ut3.ut_suite; - l_test ut3.ut_test; - begin - --Arrange - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => '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.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')); - --Act - l_suite.do_execute(); - --Assert - ut.expect(ut_example_tests.g_number).to_equal(2); - ut.expect(l_suite.result).to_equal(ut3.ut_utils.gc_error); - ut.expect(l_suite.results_count.disabled_count).to_equal(0); - ut.expect(l_suite.results_count.warnings_count).to_equal(0); - ut.expect(l_suite.results_count.success_count).to_equal(1); - ut.expect(l_suite.results_count.failure_count).to_equal(0); - ut.expect(l_suite.results_count.errored_count).to_equal(1); - end; - - procedure beforeeach_errors is - l_suite ut3.ut_suite; - l_test ut3.ut_test; - begin - --Arrange - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => '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.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')); - --Act - l_suite.do_execute(); - --Assert - ut.expect(ut_example_tests.g_number).to_equal(2); - ut.expect(l_suite.result).to_equal(ut3.ut_utils.gc_error); - ut.expect(l_suite.results_count.disabled_count).to_equal(0); - ut.expect(l_suite.results_count.warnings_count).to_equal(0); - ut.expect(l_suite.results_count.success_count).to_equal(1); - ut.expect(l_suite.results_count.failure_count).to_equal(0); - ut.expect(l_suite.results_count.errored_count).to_equal(1); - end; - -end; -/ diff --git a/test/core/test_ut_test.pks b/test/core/test_ut_test.pks deleted file mode 100644 index de6107326..000000000 --- a/test/core/test_ut_test.pks +++ /dev/null @@ -1,26 +0,0 @@ -create or replace package test_ut_test is - - --%suite(ut_test) - --%suitepath(utplsql.core) - - --%beforeeach - procedure cleanup_package_state; - - --%test(Disabled flag for a test skips the tests execution in suite) - procedure disabled_test; - - --%test(Marks test as errored if aftertest raises exception) - procedure aftertest_errors; - - --%test(Marks each test as errored if aftereach raises exception) - procedure aftereach_errors; - - --%test(Marks test as errored if beforetest raises exception) - procedure beforetest_errors; - - --%test(Marks each test as errored if beforeeach raises exception) - procedure beforeeach_errors; - - -end; -/ diff --git a/test/helpers/test_dummy_object_list.tps b/test/helpers/test_dummy_object_list.tps deleted file mode 100644 index 67bba558e..000000000 --- a/test/helpers/test_dummy_object_list.tps +++ /dev/null @@ -1,2 +0,0 @@ -create or replace type test_dummy_object_list as table of test_dummy_object -/ diff --git a/test/helpers/ut_example_tests.pkb b/test/helpers/ut_example_tests.pkb deleted file mode 100644 index 5059103b6..000000000 --- a/test/helpers/ut_example_tests.pkb +++ /dev/null @@ -1,20 +0,0 @@ -create or replace package body ut_example_tests -as - - procedure set_g_number_0 as - begin - g_number := 0; - end; - - procedure add_1_to_g_number as - begin - g_number := g_number + 1; - end; - - procedure failing_procedure as - begin - g_number := 1 / 0; - end; - -end; -/ diff --git a/test/helpers/ut_example_tests.pks b/test/helpers/ut_example_tests.pks deleted file mode 100644 index 7ff75ce12..000000000 --- a/test/helpers/ut_example_tests.pks +++ /dev/null @@ -1,8 +0,0 @@ -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; -end; -/ diff --git a/test/helpers/ut_with_invalid_body.pkb b/test/helpers/ut_with_invalid_body.pkb deleted file mode 100644 index e265bf8de..000000000 --- a/test/helpers/ut_with_invalid_body.pkb +++ /dev/null @@ -1,4 +0,0 @@ -create or replace package body ut_with_invalid_body as - procedure test1; -end; -/ \ No newline at end of file diff --git a/test/helpers/ut_with_invalid_body.pks b/test/helpers/ut_with_invalid_body.pks deleted file mode 100644 index 702affb59..000000000 --- a/test/helpers/ut_with_invalid_body.pks +++ /dev/null @@ -1,4 +0,0 @@ -create or replace package ut_with_invalid_body as - procedure test1; -end; -/ \ No newline at end of file diff --git a/test/helpers/ut_without_body.pks b/test/helpers/ut_without_body.pks deleted file mode 100644 index 45a3c50d4..000000000 --- a/test/helpers/ut_without_body.pks +++ /dev/null @@ -1,4 +0,0 @@ -create or replace package ut_without_body as - procedure test1; -end; -/ \ No newline at end of file diff --git a/test/install_and_run_tests.sh b/test/install_and_run_tests.sh old mode 100644 new mode 100755 index a1e5e0849..04f51fb3c --- a/test/install_and_run_tests.sh +++ b/test/install_and_run_tests.sh @@ -1,34 +1,9 @@ #!/bin/bash set -ev - #goto git root directory git rev-parse && cd "$(git rev-parse --show-cdup)" - - cd test -time "$SQLCLI" ${UT3_TESTER}/${UT3_TESTER_PASSWORD}@//${CONNECTION_STR} @install_tests.sql - -cd .. - -time utPLSQL-cli/bin/utplsql run ${UT3_TESTER}/${UT3_TESTER_PASSWORD}@${CONNECTION_STR} \ --source_path=source -owner=ut3 \ --test_path=test -c \ --f=ut_documentation_reporter -o=test_results.log -s \ --f=ut_coverage_sonar_reporter -o=coverage.xml \ --f=ut_coverage_html_reporter -o=coverage.html \ --f=ut_coveralls_reporter -o=coverage.json \ --f=ut_sonar_test_reporter -o=test_results.xml \ --f=ut_junit_reporter -o=junit_test_results.xml \ --f=ut_tfs_junit_reporter -o=tfs_test_results.xml \ --scc - -status_line_regex="^[0-9]+ tests, ([0-9]+) failed, ([0-9]+) errored.*" - -#cat coverage.xml -#cat test_results.xml - -RC=$(cat test_results.log | grep -E "${status_line_regex}" | sed -re "s/${status_line_regex}/\1\2/") - -exit $RC +time . ./${DIR}/install_tests.sh +time . ./${DIR}/run_tests.sh diff --git a/test/install_tests.sh b/test/install_tests.sh new file mode 100755 index 000000000..1b97ec33d --- /dev/null +++ b/test/install_tests.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -ev + +SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +cd ${SCRIPT_DIR} + + +"$SQLCLI" UT3_TESTER_HELPER/ut3@//${CONNECTION_STR} @install_ut3_tester_helper.sql + +"$SQLCLI" UT3_USER/ut3@//${CONNECTION_STR} @install_ut3_user_tests.sql + +"$SQLCLI" UT3_TESTER/ut3@//${CONNECTION_STR} @install_ut3_tester_tests.sql + diff --git a/test/install_tests.sql b/test/install_tests.sql deleted file mode 100644 index 2aa60692c..000000000 --- a/test/install_tests.sql +++ /dev/null @@ -1,144 +0,0 @@ -set define off -whenever sqlerror exit failure rollback -whenever oserror exit failure rollback - -alter session set plsql_optimize_level=0; ---Install helpers -@@helpers/ut_test_table.sql -@@helpers/ut_example_tests.pks -@@helpers/ut_example_tests.pkb -@@helpers/ut_without_body.pks -@@helpers/ut_with_invalid_body.pks -@@helpers/ut_with_invalid_body.pkb -@@helpers/other_dummy_object.tps -@@helpers/test_dummy_object.tps -@@helpers/test_dummy_object_list.tps - ---Install tests -@@core.pks -@@api/test_ut_runner.pks -@@api/test_ut_run.pks -@@core/test_ut_utils.pks -@@core/test_ut_suite.pks -@@core/test_ut_test.pks -@@core/annotations/test_annotation_parser.pks -@@core/annotations/test_annotation_manager.pks -@@core/annotations/test_before_after_test_annotation.pks -@@core/expectations/test_expectation_processor.pks -@@core/expectations/test_matchers.pks -@@core/test_output_buffer.pks -@@core/test_file_mapper.pks -@@core/test_suite_manager.pks -@@core/test_ut_executable.pks -@@core/test_suite_builder.pks -@@core/reporters.pks -@@core/reporters/test_coverage.pks -set define on -@@install_above_12_1.sql 'core/reporters/test_extended_coverage.pks' -@@install_above_12_1.sql 'core/reporters/test_coverage/test_html_extended_reporter.pks' -set define off -@@core/reporters/test_coverage/test_coverage_sonar_reporter.pks -@@core/reporters/test_coverage/test_coveralls_reporter.pks -@@core/reporters/test_coverage/test_cov_cobertura_reporter.pks -@@core/reporters/test_junit_reporter.pks -set define on -@@install_below_12_2.sql 'core/reporters/test_coverage/test_html_proftab_reporter.pks' -set define off -@@core/reporters/test_tfs_junit_reporter.pks -@@core/reporters/test_documentation_reporter.pks -@@core/reporters/test_sonar_test_reporter.pks -@@core/reporters/test_teamcity_reporter.pks -@@core/expectations.pks -@@core/expectations/binary/test_be_greater_or_equal.pks -@@core/expectations/binary/test_be_greater_than.pks -@@core/expectations/binary/test_be_less_or_equal.pks -@@core/expectations/binary/test_equal.pks -@@core/expectations/binary/test_expect_to_be_less_than.pks -@@core/expectations/unary/test_expect_to_be_empty.pks -@@core/expectations/unary/test_expect_to_have_count.pks -@@core/expectations/unary/test_expect_not_to_be_null.pks -@@core/expectations/unary/test_expect_to_be_not_null.pks -@@core/expectations/unary/test_expect_to_be_null.pks -@@core/expectations/unary/test_expect_to_be_true_false.pks -@@core/expectations/test_expectations_cursor.pks -@@core/expectations/test_expectation_anydata.pks -@@core/annotations/test_annot_throws_exception.pks - -@@core.pkb -@@api/test_ut_runner.pkb -@@api/test_ut_run.pkb -@@core/test_ut_utils.pkb -@@core/test_ut_suite.pkb -@@core/test_ut_test.pkb -@@core/annotations/test_annotation_parser.pkb -@@core/annotations/test_annotation_manager.pkb -@@core/expectations/test_expectation_processor.pkb -@@core/expectations/test_matchers.pkb -@@core/annotations/test_before_after_test_annotation.pkb -@@core/test_output_buffer.pkb -@@core/test_file_mapper.pkb -@@core/test_suite_manager.pkb -@@core/test_ut_executable.pkb -@@core/test_suite_builder.pkb -@@core/reporters.pkb -@@core/reporters/test_coverage.pkb -set define on -@@install_above_12_1.sql 'core/reporters/test_extended_coverage.pkb' -@@install_above_12_1.sql 'core/reporters/test_coverage/test_html_extended_reporter.pkb' -set define off -@@core/reporters/test_coverage/test_coverage_sonar_reporter.pkb -@@core/reporters/test_coverage/test_coveralls_reporter.pkb -@@core/reporters/test_coverage/test_cov_cobertura_reporter.pkb -@@core/reporters/test_junit_reporter.pkb -set define on -@@install_below_12_2.sql 'core/reporters/test_coverage/test_html_proftab_reporter.pkb' -set define off -@@core/reporters/test_tfs_junit_reporter.pkb -@@core/reporters/test_documentation_reporter.pkb -@@core/reporters/test_sonar_test_reporter.pkb -@@core/reporters/test_teamcity_reporter.pkb -@@core/expectations.pkb -@@core/expectations/binary/test_be_greater_or_equal.pkb -@@core/expectations/binary/test_be_greater_than.pkb -@@core/expectations/binary/test_be_less_or_equal.pkb -@@core/expectations/binary/test_equal.pkb -@@core/expectations/binary/test_expect_to_be_less_than.pkb -@@core/expectations/unary/test_expect_to_be_empty.pkb -@@core/expectations/unary/test_expect_to_have_count.pkb -@@core/expectations/unary/test_expect_not_to_be_null.pkb -@@core/expectations/unary/test_expect_to_be_not_null.pkb -@@core/expectations/unary/test_expect_to_be_null.pkb -@@core/expectations/unary/test_expect_to_be_true_false.pkb -@@core/expectations/test_expectations_cursor.pkb -@@core/expectations/test_expectation_anydata.pkb -@@core/annotations/test_annot_throws_exception.pkb - -set linesize 200 -set define on -set verify off -column text format a100 -column error_count noprint new_value error_count - -prompt Validating installation - -set heading on -select type, name, sequence, line, position, text, count(1) over() error_count - from all_errors - where owner = USER - and name not like 'BIN$%' --not recycled - and name != 'UT_WITH_INVALID_BODY' - -- errors only. ignore warnings - and attribute = 'ERROR' - order by name, type, sequence -/ - -begin - if to_number('&&error_count') > 0 then - raise_application_error(-20000, 'Not all sources were successfully installed.'); - else - dbms_output.put_line('Installation completed successfully'); - end if; -end; -/ - -exit; diff --git a/test/install_ut3_tester_helper.sql b/test/install_ut3_tester_helper.sql new file mode 100644 index 000000000..b78221627 --- /dev/null +++ b/test/install_ut3_tester_helper.sql @@ -0,0 +1,74 @@ +set define off +whenever sqlerror exit failure rollback +whenever oserror exit failure rollback + +alter session set plsql_optimize_level=0; +--Install ut3_tester_helper +@@ut3_tester_helper/test_dummy_object.tps +@@ut3_tester_helper/other_dummy_object.tps +@@ut3_tester_helper/test_dummy_nested_object.tps +@@ut3_tester_helper/test_dummy_double_nested_object.tps +@@ut3_tester_helper/test_dummy_object_list.tps +@@ut3_tester_helper/test_dummy_nested_object_list.tps +@@ut3_tester_helper/test_dummy_double_nested_list.tps +@@ut3_tester_helper/test_dummy_dble_nest_lst_obj.tps +@@ut3_tester_helper/test_tab_varchar2.tps +@@ut3_tester_helper/test_tab_varray.tps +@@ut3_tester_helper/test_nested_tab_varray.tps +@@ut3_tester_helper/test_dummy_number.tps +@@ut3_tester_helper/ut_test_table.sql +@@ut3_tester_helper/test_event_object.tps +@@ut3_tester_helper/test_event_list.tps + +@@ut3_tester_helper/main_helper.pks +@@ut3_tester_helper/run_helper.pks +@@ut3_tester_helper/coverage_helper.pks +@@ut3_tester_helper/expectations_helper.pks +@@ut3_tester_helper/ut_example_tests.pks + +@@ut3_tester_helper/main_helper.pkb +@@ut3_tester_helper/run_helper.pkb +@@ut3_tester_helper/coverage_helper.pkb +@@ut3_tester_helper/expectations_helper.pkb +@@ut3_tester_helper/ut_example_tests.pkb + +@@ut3_tester_helper/annotation_cache_helper.pks +@@ut3_tester_helper/annotation_cache_helper.pkb +create or replace synonym ut3_tester.annotation_cache_helper for ut3_tester_helper.annotation_cache_helper; +create or replace synonym ut3_user.coverage_helper for ut3_tester_helper.coverage_helper; + +set linesize 200 +set define on +set verify off +column text format a100 +column error_count noprint new_value error_count + +prompt Validating installation + +set heading on +select type, name, sequence, line, position, text, count(1) over() error_count + from all_errors + where owner = USER + and name not like 'BIN$%' --not recycled + and name != 'UT_WITH_INVALID_BODY' + -- errors only. ignore warnings + and attribute = 'ERROR' + order by name, type, sequence +/ + +begin + if to_number('&&error_count') > 0 then + raise_application_error(-20000, 'Not all sources were successfully installed.'); + else + dbms_output.put_line('Installation completed successfully'); + end if; + + for i in ( select object_name from user_objects t where t.object_type in ('PACKAGE','TYPE')) + loop + execute immediate 'grant execute on '||i.object_name||' to PUBLIC'; + end loop; + +end; +/ + +exit; diff --git a/test/install_ut3_tester_tests.sql b/test/install_ut3_tester_tests.sql new file mode 100644 index 000000000..cc96b2b64 --- /dev/null +++ b/test/install_ut3_tester_tests.sql @@ -0,0 +1,78 @@ +set define off +whenever sqlerror exit failure rollback +whenever oserror exit failure rollback + +alter session set plsql_optimize_level=0; + +@@common_helper/utplsql.pks +@@common_helper/utplsql.pkb + +--Install tests +@@ut3_tester/core.pks +@@ut3_tester/core/annotations/test_before_after_annotations.pks +@@ut3_tester/core/annotations/test_annotation_parser.pks +@@ut3_tester/core/annotations/test_annot_throws_exception.pks +@@ut3_tester/core/annotations/test_annotation_manager.pks +@@ut3_tester/core/annotations/test_annotation_cache.pks +@@ut3_tester/core/annotations/test_annot_disabled_reason.pks +@@ut3_tester/core/expectations/test_expectation_processor.pks +@@ut3_tester/core/test_ut_utils.pks +@@ut3_tester/core/test_ut_suite_tag_filter.pks +@@ut3_tester/core/test_ut_test.pks +@@ut3_tester/core/test_ut_suite.pks +@@ut3_tester/core/test_ut_executable.pks +@@ut3_tester/core/test_suite_manager.pks +@@ut3_tester/core/test_file_mapper.pks +@@ut3_tester/core/test_output_buffer.pks +@@ut3_tester/core/test_suite_builder.pks + + +@@ut3_tester/core.pkb +@@ut3_tester/core/annotations/test_before_after_annotations.pkb +@@ut3_tester/core/annotations/test_annotation_parser.pkb +@@ut3_tester/core/annotations/test_annotation_manager.pkb +@@ut3_tester/core/annotations/test_annot_throws_exception.pkb +@@ut3_tester/core/annotations/test_annotation_cache.pkb +@@ut3_tester/core/annotations/test_annot_disabled_reason.pkb +@@ut3_tester/core/expectations/test_expectation_processor.pkb +@@ut3_tester/core/test_ut_utils.pkb +@@ut3_tester/core/test_ut_suite_tag_filter.pkb +@@ut3_tester/core/test_ut_test.pkb +@@ut3_tester/core/test_ut_suite.pkb +@@ut3_tester/core/test_ut_executable.pkb +@@ut3_tester/core/test_suite_manager.pkb +@@ut3_tester/core/test_file_mapper.pkb +@@ut3_tester/core/test_output_buffer.pkb +@@ut3_tester/core/test_suite_builder.pkb + + + +set linesize 200 +set define on +set verify off +column text format a100 +column error_count noprint new_value error_count + +prompt Validating installation + +set heading on +select type, name, sequence, line, position, text, count(1) over() error_count + from all_errors + where owner = USER + and name not like 'BIN$%' --not recycled + and name != 'UT_WITH_INVALID_BODY' + -- errors only. ignore warnings + and attribute = 'ERROR' + order by name, type, sequence +/ + +begin + if to_number('&&error_count') > 0 then + raise_application_error(-20000, 'Not all sources were successfully installed.'); + else + dbms_output.put_line('Installation completed successfully'); + end if; +end; +/ + +exit; diff --git a/test/install_ut3_user_tests.sql b/test/install_ut3_user_tests.sql new file mode 100644 index 000000000..ad7f014bc --- /dev/null +++ b/test/install_ut3_user_tests.sql @@ -0,0 +1,136 @@ +set define off +whenever sqlerror exit failure rollback +whenever oserror exit failure rollback + +alter session set plsql_optimize_level=0; + +@@common_helper/utplsql.pks +@@common_helper/utplsql.pkb + +prompt Install user tests +@@ut3_user/helpers/some_item.tps +@@ut3_user/helpers/some_items.tps +@@ut3_user/helpers/some_object.tps +@@ut3_user/test_user.pks +@@ut3_user/expectations.pks +@@ut3_user/expectations.pkb +@@ut3_user/expectations/unary/test_expect_not_to_be_null.pks +@@ut3_user/expectations/unary/test_expect_to_be_null.pks +@@ut3_user/expectations/unary/test_expect_to_be_empty.pks +@@ut3_user/expectations/unary/test_expect_to_have_count.pks +@@ut3_user/expectations/unary/test_expect_to_be_true_false.pks +@@ut3_user/expectations/unary/test_expect_to_be_not_null.pks +@@ut3_user/expectations/binary/test_equal.pks +@@ut3_user/expectations/binary/test_expect_to_be_less_than.pks +@@ut3_user/expectations/binary/test_be_less_or_equal.pks +@@ut3_user/expectations/binary/test_be_greater_or_equal.pks +@@ut3_user/expectations/binary/test_be_greater_than.pks +@@ut3_user/expectations/binary/test_to_be_within.pks +@@ut3_user/expectations/binary/test_to_be_within_pct.pks +@@ut3_user/expectations/test_matchers.pks +@@ut3_user/expectations/test_expectation_anydata.pks +@@ut3_user/expectations/test_expectations_cursor.pks +set define on +@@install_above_12_1.sql 'ut3_user/expectations/test_expectations_json.pks' +set define off +@@ut3_user/api/test_ut_runner.pks +@@ut3_user/api/test_ut_run.pks +@@ut3_user/reporters.pks +@@ut3_user/reporters/test_tfs_junit_reporter.pks +@@ut3_user/reporters/test_teamcity_reporter.pks +@@ut3_user/reporters/test_sonar_test_reporter.pks +@@ut3_user/reporters/test_junit_reporter.pks +@@ut3_user/reporters/test_documentation_reporter.pks +@@ut3_user/reporters/test_debug_reporter.pks +@@ut3_user/reporters/test_realtime_reporter.pks +@@ut3_user/reporters/test_coverage.pks +@@ut3_user/reporters/test_coverage/test_coverage_standalone.pks +set define on +@@ut3_user/reporters/test_coverage/test_extended_coverage.pks +@@ut3_user/reporters/test_coverage/test_html_coverage_reporter.pks +set define off +@@ut3_user/reporters/test_coverage/test_coveralls_reporter.pks +@@ut3_user/reporters/test_coverage/test_cov_cobertura_reporter.pks +@@ut3_user/reporters/test_coverage/test_coverage_sonar_reporter.pks +set define on +@@ut3_user/reporters/test_coverage/test_proftab_coverage.pks +set define off + +@@ut3_user/test_user.pkb +@@ut3_user/expectations/unary/test_expect_not_to_be_null.pkb +@@ut3_user/expectations/unary/test_expect_to_be_null.pkb +@@ut3_user/expectations/unary/test_expect_to_be_empty.pkb +@@ut3_user/expectations/unary/test_expect_to_have_count.pkb +@@ut3_user/expectations/unary/test_expect_to_be_true_false.pkb +@@ut3_user/expectations/unary/test_expect_to_be_not_null.pkb +@@ut3_user/expectations/binary/test_equal.pkb +@@ut3_user/expectations/binary/test_expect_to_be_less_than.pkb +@@ut3_user/expectations/binary/test_be_less_or_equal.pkb +@@ut3_user/expectations/binary/test_be_greater_or_equal.pkb +@@ut3_user/expectations/binary/test_be_greater_than.pkb +@@ut3_user/expectations/binary/test_to_be_within.pkb +@@ut3_user/expectations/binary/test_to_be_within_pct.pkb +@@ut3_user/expectations/test_matchers.pkb +@@ut3_user/expectations/test_expectation_anydata.pkb +@@ut3_user/expectations/test_expectations_cursor.pkb +set define on +@@install_above_12_1.sql 'ut3_user/expectations/test_expectations_json.pkb' +set define off +@@ut3_user/api/test_ut_runner.pkb +@@ut3_user/api/test_ut_run.pkb +@@ut3_user/reporters.pkb +@@ut3_user/reporters/test_tfs_junit_reporter.pkb +@@ut3_user/reporters/test_teamcity_reporter.pkb +@@ut3_user/reporters/test_sonar_test_reporter.pkb +@@ut3_user/reporters/test_junit_reporter.pkb +@@ut3_user/reporters/test_documentation_reporter.pkb +@@ut3_user/reporters/test_debug_reporter.pkb +@@ut3_user/reporters/test_realtime_reporter.pkb +@@ut3_user/reporters/test_coverage/test_coverage_standalone.pkb +set define on +@@ut3_user/reporters/test_coverage/test_extended_coverage.pkb +@@ut3_user/reporters/test_coverage/test_html_coverage_reporter.pkb +set define off +@@ut3_user/reporters/test_coverage/test_coveralls_reporter.pkb +@@ut3_user/reporters/test_coverage/test_cov_cobertura_reporter.pkb +@@ut3_user/reporters/test_coverage/test_coverage_sonar_reporter.pkb +set define on +@@ut3_user/reporters/test_coverage/test_proftab_coverage.pkb +set define off + + +set linesize 200 +set define on +set verify off +column text format a100 +column error_count noprint new_value error_count + +prompt Validating installation + +set heading on +select type, name, sequence, line, position, text, count(1) over() error_count + from all_errors + where owner = USER + and name not like 'BIN$%' --not recycled + and name != 'UT_WITH_INVALID_BODY' + -- errors only. ignore warnings + and attribute = 'ERROR' + order by name, type, sequence +/ + +begin + if to_number('&&error_count') > 0 then + raise_application_error(-20000, 'Not all sources were successfully installed.'); + else + dbms_output.put_line('Installation completed successfully'); + end if; + + for i in ( select object_name from user_objects t where t.object_type = 'PACKAGE') + loop + execute immediate 'grant execute on '||i.object_name||' to UT3_TESTER'; + end loop; + +end; +/ + +exit; diff --git a/test/run_tests.sh b/test/run_tests.sh new file mode 100755 index 000000000..118bab920 --- /dev/null +++ b/test/run_tests.sh @@ -0,0 +1,22 @@ +#!/bin/bash +set -ev + +#goto git root directory +git rev-parse && cd "$(git rev-parse --show-cdup)" + +time utPLSQL-cli/bin/utplsql run UT3_TESTER_HELPER/ut3@${CONNECTION_STR} \ +-source_path=source -owner=ut3_develop \ +-p='ut3_tester,ut3_user' \ +-test_path=test -c \ + -regex_expression="test/(\w+)(/(\w+))*/(\w+)\.(.{3})$" \ + -owner_subexpression=1 \ + -type_subexpression=5 \ + -name_subexpression=4 \ +-f=ut_coverage_sonar_reporter -o=coverage.xml \ +-f=ut_coverage_cobertura_reporter -o=cobertura.xml \ +-f=ut_coverage_html_reporter -o=coverage.html \ +-f=ut_coveralls_reporter -o=coverage.json \ +-f=ut_sonar_test_reporter -o=test_results.xml \ +-f=ut_junit_reporter -o=junit_test_results.xml \ +-f=ut_tfs_junit_reporter -o=tfs_test_results.xml \ +-f=ut_documentation_reporter -o=test_results.log -s diff --git a/test/ut3_tester/core.pkb b/test/ut3_tester/core.pkb new file mode 100644 index 000000000..41b6b10d1 --- /dev/null +++ b/test/ut3_tester/core.pkb @@ -0,0 +1,11 @@ +create or replace package body core is + + procedure global_setup is + begin + ut3_tester_helper.coverage_helper.set_develop_mode(); + --improve performance of test execution by disabling all compiler optimizations + ut3_tester_helper.main_helper.execute_autonomous('ALTER SESSION SET PLSQL_OPTIMIZE_LEVEL=0'); + end; + +end; +/ diff --git a/test/ut3_tester/core.pks b/test/ut3_tester/core.pks new file mode 100644 index 000000000..4565c47f3 --- /dev/null +++ b/test/ut3_tester/core.pks @@ -0,0 +1,10 @@ +create or replace package core is + + --%suite + --%suitepath(utplsql.ut3_tester) + + --%beforeall + procedure global_setup; + +end; +/ diff --git a/test/ut3_tester/core/annotations/test_annot_disabled_reason.pkb b/test/ut3_tester/core/annotations/test_annot_disabled_reason.pkb new file mode 100644 index 000000000..7f1e068a8 --- /dev/null +++ b/test/ut3_tester/core/annotations/test_annot_disabled_reason.pkb @@ -0,0 +1,484 @@ +create or replace package body test_annot_disabled_reason +is + + + procedure compile_dummy_packages is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package test_package_1 is + + --%suite + --%displayname(disable_test_suite_level) + --%suitepath(tests) + --%rollback(manual) + + --%disabled( Tests are disabled on suite level ) + + --%context( First context ) + + --%test(Test1 from test package 1) + procedure test1; + + --%test(Test2 from test package 1) + procedure test2; + + --%endcontext + + --%context( Second context ) + + --%test(Test3 from test package 1) + procedure test3; + + --%test(Test4 from test package 1) + procedure test4; + + --%endcontext + +end test_package_1;]'; + + execute immediate q'[create or replace package body test_package_1 is + + procedure test1 is + begin + ut.expect(1).to_equal(1); + end; + + procedure test2 is + begin + ut.expect(2).to_equal(2); + end; + + procedure test3 is + begin + ut.expect(1).to_equal(1); + end; + + procedure test4 is + begin + ut.expect(2).to_equal(2); + end; + +end test_package_1;]'; + + execute immediate q'[create or replace package test_package_2 is + + --%suite + --%displayname(Disable on context level) + --%suitepath(tests) + --%rollback(manual) + + --%context( First context ) + + --%disabled( Tests and disabled on first context level ) + + --%test(Test1 from test package 2) + procedure test1; + + --%test(Test2 from test package 2) + procedure test2; + + --%endcontext + + --%context( Second context ) + + --%test(Test3 from test package 2) + procedure test3; + + --%test(Test4 from test package 3) + procedure test4; + + --%endcontext + +end test_package_2;]'; + + execute immediate q'[create or replace package body test_package_2 is + + procedure test1 is + begin + ut.expect(1).to_equal(1); + end; + + procedure test2 is + begin + ut.expect(2).to_equal(2); + end; + + procedure test3 is + begin + ut.expect(1).to_equal(1); + end; + + procedure test4 is + begin + ut.expect(2).to_equal(2); + end; + +end test_package_2;]'; + + execute immediate q'[create or replace package testing_package_3 is + + --%suite + --%displayname(Disable tests on test level) + --%suitepath(tests) + --%rollback(manual) + + --%context( First context ) + + --%test(Test1 from test package 3) + --%disabled( Test1 disabled from first context ) + procedure test1; + + --%test(Test2 from test package 3) + procedure test2; + + --%endcontext + + --%context( Second context ) + + --%test(Test3 from test package 3) + procedure test3; + + --%test(Test4 from test package 3) + --%disabled( Test4 disabled from second context ) + procedure test4; + + --%endcontext + +end testing_package_3;]'; + + execute immediate q'[create or replace package body testing_package_3 is + + procedure test1 is + begin + ut.expect(1).to_equal(1); + end; + + procedure test2 is + begin + ut.expect(2).to_equal(2); + end; + + procedure test3 is + begin + ut.expect(1).to_equal(1); + end; + + procedure test4 is + begin + ut.expect(2).to_equal(2); + end; + +end testing_package_3;]'; + + execute immediate q'[create or replace package test_package_4 is + + --%suite + --%displayname(Disable reason is very long or have special characters) + --%suitepath(tests) + --%rollback(manual) + + + --%test(Test1 from test package 4) + --%disabled( $#?!%*&-/\^ ) + procedure test1; + + --%test(Test2 from test package 4) + --%disabled(verylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtext) + procedure test2; + +end test_package_4;]'; + + execute immediate q'[create or replace package body test_package_4 is + + procedure test1 is + begin + ut.expect(1).to_equal(1); + end; + + procedure test2 is + begin + ut.expect(2).to_equal(2); + end; + +end test_package_4;]'; + + execute immediate q'[create or replace package test_package_5 is + + --%suite + --%displayname(Disable tests on suite level overriding rest) + --%suitepath(tests) + --%rollback(manual) + + --%disabled( Disable on suite level ) + + --%context( First context ) + + --%disabled( Disable on 1st context level ) + + --%test(Test1 from test package 3) + --%disabled( Disable on 1st test level ) + procedure test1; + + --%test(Test2 from test package 3) + --%disabled( Disable on 2nd test level ) + procedure test2; + + --%endcontext + + --%context( Second context ) + + --%disabled( Disable on 2nd context level ) + + --%test(Test3 from test package 3) + --%disabled( Disable on 3rd test level ) + procedure test3; + + --%test(Test4 from test package 3) + --%disabled( Disable on 4th test level ) + procedure test4; + + --%endcontext + +end test_package_5;]'; + + execute immediate q'[create or replace package body test_package_5 is + + procedure test1 is + begin + ut.expect(1).to_equal(1); + end; + + procedure test2 is + begin + ut.expect(2).to_equal(2); + end; + + procedure test3 is + begin + ut.expect(1).to_equal(1); + end; + + procedure test4 is + begin + ut.expect(2).to_equal(2); + end; + +end test_package_5;]'; + + execute immediate q'[create or replace package test_package_6 is + + --%suite + --%displayname(Disable tests on each of ctx level overriding rest) + --%suitepath(tests) + --%rollback(manual) + + --%context( First context ) + + --%disabled( Disable on 1st context level ) + + --%test(Test1 from test package 3) + --%disabled( Disable on 1st test level ) + procedure test1; + + --%test(Test2 from test package 3) + --%disabled( Disable on 2nd test level ) + procedure test2; + + --%endcontext + + --%context( Second context ) + + --%disabled( Disable on 2nd context level ) + + --%test(Test3 from test package 3) + --%disabled( Disable on 3rd test level ) + procedure test3; + + --%test(Test4 from test package 3) + --%disabled( Disable on 4th test level ) + procedure test4; + + --%endcontext + +end test_package_6;]'; + + execute immediate q'[create or replace package body test_package_6 is + + procedure test1 is + begin + ut.expect(1).to_equal(1); + end; + + procedure test2 is + begin + ut.expect(2).to_equal(2); + end; + + procedure test3 is + begin + ut.expect(1).to_equal(1); + end; + + procedure test4 is + begin + ut.expect(2).to_equal(2); + end; + +end test_package_6;]'; + + end; + + + procedure drop_dummy_packages is + pragma autonomous_transaction; + begin + execute immediate 'drop package test_package_1'; + execute immediate 'drop package test_package_2'; + execute immediate 'drop package testing_package_3'; + execute immediate 'drop package test_package_4'; + execute immediate 'drop package test_package_5'; + execute immediate 'drop package test_package_6'; + end; + + procedure test_disable_on_suite_level is + l_test_results ut3_develop.ut_varchar2_list; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + --Act + + select * bulk collect into l_test_results from table(ut3_develop.ut.run((sys_context('USERENV', 'CURRENT_USER')||'.test_package_1'))); + + l_actual_message := ut3_develop.ut_utils.table_to_clob(l_test_results); + + l_expected_message := q'[%tests +%disable_test_suite_level +%First context +%Test1 from test package 1 [0 sec] (DISABLED - Tests are disabled on suite level) +%Test2 from test package 1 [0 sec] (DISABLED - Tests are disabled on suite level) +%Second context +%Test3 from test package 1 [0 sec] (DISABLED - Tests are disabled on suite level) +%Test4 from test package 1 [0 sec] (DISABLED - Tests are disabled on suite level)%]'; + ut.expect(l_actual_message).to_be_like(l_expected_message); + + end; + + procedure test_dis_on_1st_ctx_level is + l_test_results ut3_develop.ut_varchar2_list; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + --Act + + select * bulk collect into l_test_results from table(ut3_develop.ut.run((sys_context('USERENV', 'CURRENT_USER')||'.test_package_2'))); + + l_actual_message := ut3_develop.ut_utils.table_to_clob(l_test_results); + + l_expected_message := q'[%tests +%Disable on context level +%First context +%Test1 from test package 2 [0 sec] (DISABLED - Tests and disabled on first context level) +%Test2 from test package 2 [0 sec] (DISABLED - Tests and disabled on first context level) +%Second context +%Test3 from test package 2 [% sec] +%Test4 from test package 3 [% sec]%]'; + + ut.expect(l_actual_message).to_be_like(l_expected_message); + + end; + + procedure test_disable_tests_level is + l_test_results ut3_develop.ut_varchar2_list; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + --Act + + select * bulk collect into l_test_results from table(ut3_develop.ut.run((sys_context('USERENV', 'CURRENT_USER')||'.testing_package_3'))); + + l_actual_message := ut3_develop.ut_utils.table_to_clob(l_test_results); + + l_expected_message := q'[%tests +%Disable tests on test level +%First context +%Test1 from test package 3 [0 sec] (DISABLED - Test1 disabled from first context) +%Test2 from test package 3 [% sec] +%Second context +%Test3 from test package 3 [% sec] +%Test4 from test package 3 [0 sec] (DISABLED - Test4 disabled from second context)%]'; + + ut.expect(l_actual_message).to_be_like(l_expected_message); + + + end; + + procedure test_long_text_spec_chr is + l_test_results ut3_develop.ut_varchar2_list; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + --Act + + select * bulk collect into l_test_results from table(ut3_develop.ut.run((sys_context('USERENV', 'CURRENT_USER')||'.test_package_4'))); + + l_actual_message := ut3_develop.ut_utils.table_to_clob(l_test_results); + + l_expected_message := q'[%tests +%Disable reason is very long or have special characters +%Test1 from test package 4 [0 sec] (DISABLED - $#?!%*&-/\^) +%Test2 from test package 4 [0 sec] (DISABLED - verylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtext)%]'; + + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure test_disable_suite_ctx_tst is + l_test_results ut3_develop.ut_varchar2_list; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + --Act + + select * bulk collect into l_test_results from table(ut3_develop.ut.run((sys_context('USERENV', 'CURRENT_USER')||'.test_package_5'))); + + l_actual_message := ut3_develop.ut_utils.table_to_clob(l_test_results); + + l_expected_message := q'[%tests +%Disable tests on suite level overriding rest +%First context +%Test1 from test package 3 [0 sec] (DISABLED - Disable on suite level) +%Test2 from test package 3 [0 sec] (DISABLED - Disable on suite level) +%Second context +%Test3 from test package 3 [0 sec] (DISABLED - Disable on suite level) +%Test4 from test package 3 [0 sec] (DISABLED - Disable on suite level)%]'; + + ut.expect(l_actual_message).to_be_like(l_expected_message); + + + end; + + procedure test_disable_ctx_tst is + l_test_results ut3_develop.ut_varchar2_list; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + --Act + + select * bulk collect into l_test_results from table(ut3_develop.ut.run((sys_context('USERENV', 'CURRENT_USER')||'.test_package_6'))); + + l_actual_message := ut3_develop.ut_utils.table_to_clob(l_test_results); + + l_expected_message := q'[%tests +%Disable tests on each of ctx level overriding rest +%First context +%Test1 from test package 3 [0 sec] (DISABLED - Disable on 1st context level) +%Test2 from test package 3 [0 sec] (DISABLED - Disable on 1st context level) +%Second context +%Test3 from test package 3 [0 sec] (DISABLED - Disable on 2nd context level) +%Test4 from test package 3 [0 sec] (DISABLED - Disable on 2nd context level)%]'; + + ut.expect(l_actual_message).to_be_like(l_expected_message); + + end; + +end; +/ diff --git a/test/ut3_tester/core/annotations/test_annot_disabled_reason.pks b/test/ut3_tester/core/annotations/test_annot_disabled_reason.pks new file mode 100644 index 000000000..cae5da1ee --- /dev/null +++ b/test/ut3_tester/core/annotations/test_annot_disabled_reason.pks @@ -0,0 +1,31 @@ +create or replace package test_annot_disabled_reason +is + --%suite(annotations - disabled) + --%suitepath(utplsql.ut3_tester.core.annotations) + + --%beforeall + procedure compile_dummy_packages; + + --%afterall + procedure drop_dummy_packages; + + --%test(Disable all tests under the suite displaying suite level reason) + procedure test_disable_on_suite_level; + + --%test(Disable all tests under one of two contexts displaying context level reason) + procedure test_dis_on_1st_ctx_level; + + --%test(Disable a single tests from each of the contexts displaying test level reason) + procedure test_disable_tests_level; + + --%test(Disable tests with reason using special characters and long reason) + procedure test_long_text_spec_chr; + + --%test(Disable tests on suite , context and test level and display suite level reason) + procedure test_disable_suite_ctx_tst; + + --%test(Disable tests on context and test level and display context level reason) + procedure test_disable_ctx_tst; + +end; +/ diff --git a/test/ut3_tester/core/annotations/test_annot_throws_exception.pkb b/test/ut3_tester/core/annotations/test_annot_throws_exception.pkb new file mode 100644 index 000000000..ac51d3a49 --- /dev/null +++ b/test/ut3_tester/core/annotations/test_annot_throws_exception.pkb @@ -0,0 +1,405 @@ +create or replace package body test_annot_throws_exception +is + g_tests_results clob; + + procedure recollect_tests_results is + pragma autonomous_transaction; + + l_package_spec varchar2(32737); + l_package_body varchar2(32737); + l_exception_spec varchar2(32737); + l_test_results ut3_develop.ut_varchar2_list; + begin + l_exception_spec := q'[ + create or replace package exc_pkg is + c_e_single_exc constant number := -20200; + c_e_dummy constant varchar2(10) := 'dummy'; + c_e_varch_exc constant varchar2(10) := '-20201'; + c_e_list_1 number := -20202; + c_e_list_2 constant number := -20203; + c_e_diff_exc constant number := -20204; + c_e_mix_list constant number := -20205; + c_e_mix_missin constant number := -20206; + c_e_positive constant number := 20207; + + e_some_exception exception; + pragma exception_init(e_some_exception, -20207); + + end;]'; + + l_package_spec := ' + create package annotated_package_with_throws is + --%suite(Dummy package to test annotation throws) + + --%test(Throws same annotated exception) + --%throws(-20145) + procedure raised_same_exception; + + --%test(Throws one of the listed exceptions) + --%throws(-20145,-20146, -20189 ,-20563) + procedure raised_one_listed_exception; + + --%test(Leading zero is ignored in exception list) + --%throws(-01476) + procedure leading_0_exception_no; + + --%test(Throws diff exception) + --%throws(-20144) + procedure raised_diff_exception; + + --%test(Throws empty) + --%throws() + procedure empty_throws; + + --%test(Ignores annotation and fails when exception was thrown) + --%throws(hello,784#,0-=234,,u1234) + procedure bad_paramters_with_except; + + --%test(Ignores annotation and succeeds when no exception thrown) + --%throws(hello,784#,0-=234,,u1234) + procedure bad_paramters_without_except; + + --%test(Ignores annotation for positive exception number value) + --%throws(20001) + procedure positive_exception_number; + + --%test(Ignores annotation for positive exception number variable) + --%throws(exc_pkg.c_e_positive) + procedure positive_exception_number_var; + + --%test(Detects a valid exception number within many invalid ones) + --%throws(7894562, operaqk, -=1, -1, pow74d, posdfk3) + procedure one_valid_exception_number; + + --%test(Gives failure when a exception is expected and nothing is thrown) + --%throws(-20459, -20136, -20145) + procedure nothing_thrown; + + --%test(Single exception defined as a constant number in package) + --%throws(exc_pkg.c_e_single_exc) + procedure single_exc_const_pkg; + + --%test(Gives success when one of annotated exception using constant is thrown) + --%throws(exc_pkg.c_e_list_1,exc_pkg.c_e_list_2) + procedure list_of_exc_constant; + + --%test(Gives failure when the raised exception is different that the annotated one using variable) + --%throws(exc_pkg.c_e_diff_exc) + procedure fail_not_match_exc; + + --%test(Success when one of exception from mixed list of number and constant is thrown) + --%throws(exc_pkg.c_e_mix_list,-20105) + procedure mixed_exc_list; + + --%test(Success when match exception even if other variable on list dont exists) + --%throws(exc_pkg.c_e_mix_missin,utter_rubbish) + procedure mixed_list_notexi; + + --%test(Success resolve and match named exception defined in pragma exception init) + --%throws(exc_pkg.e_some_exception) + procedure named_exc_pragma; + + --%test(Success resolve and match oracle named exception) + --%throws(NO_DATA_FOUND) + procedure named_exc_ora; + + --%test(Success resolve and match oracle named exception dup val index) + --%throws(DUP_VAL_ON_INDEX) + procedure named_exc_ora_dup_ind; + + --%test(Success map no data 100 to -1403) + --%throws(-1403) + procedure nodata_exc_ora; + + --%test(Success for exception defined as varchar) + --%throws(exc_pkg.c_e_varch_exc) + procedure defined_varchar_exc; + + --%test(Non existing constant exception) + --%throws(dummy.c_dummy); + procedure non_existing_const; + + --%test(Bad exception constant) + --%throws(exc_pkg.c_e_dummy); + procedure bad_exc_const; + end; + '; + + l_package_body := ' + create package body annotated_package_with_throws is + procedure raised_same_exception is + begin + raise_application_error(-20145, ''Test error''); + end; + + procedure raised_one_listed_exception is + begin + raise_application_error(-20189, ''Test error''); + end; + + procedure leading_0_exception_no is + x integer; + begin + x := 1 / 0; + end; + + procedure raised_diff_exception is + begin + raise_application_error(-20143, ''Test error''); + end; + + procedure empty_throws is + begin + raise_application_error(-20143, ''Test error''); + end; + + procedure bad_paramters_with_except is + begin + raise_application_error(-20143, ''Test error''); + end; + + procedure bad_paramters_without_except is + begin + null; + end; + + procedure positive_exception_number is + begin + null; + end; + + procedure positive_exception_number_var is + begin + null; + end; + + procedure one_valid_exception_number is + begin + raise dup_val_on_index; + end; + + procedure nothing_thrown is + begin + null; + end; + + procedure single_exc_const_pkg is + begin + raise_application_error(exc_pkg.c_e_single_exc,''Test''); + end; + + procedure list_of_exc_constant is + begin + raise_application_error(exc_pkg.c_e_list_1,''Test''); + end; + + procedure fail_not_match_exc is + begin + raise NO_DATA_FOUND; + end; + + procedure mixed_exc_list is + begin + raise_application_error(exc_pkg.c_e_mix_list,''Test''); + end; + + procedure mixed_list_notexi is + begin + raise_application_error(exc_pkg.c_e_mix_missin,''Test''); + end; + + procedure named_exc_pragma is + begin + raise exc_pkg.e_some_exception; + end; + + procedure named_exc_ora is + begin + raise NO_DATA_FOUND; + end; + + procedure named_exc_ora_dup_ind is + begin + raise DUP_VAL_ON_INDEX; + end; + + procedure nodata_exc_ora is + begin + raise NO_DATA_FOUND; + end; + + procedure defined_varchar_exc is + begin + raise_application_error(exc_pkg.c_e_varch_exc,''Test''); + end; + + procedure non_existing_const is + begin + raise_application_error(-20143, ''Test error''); + end; + + procedure bad_exc_const is + begin + raise_application_error(-20143, ''Test error''); + end; + + end; + '; + + execute immediate l_exception_spec; + execute immediate l_package_spec; + execute immediate l_package_body; + + + select * bulk collect into l_test_results from table(ut3_develop.ut.run(('annotated_package_with_throws'))); + + g_tests_results := ut3_develop.ut_utils.table_to_clob(l_test_results); + end; + + procedure throws_same_annotated_except is + begin + ut.expect(g_tests_results).to_match('^\s*Throws same annotated exception \[[,\.0-9]+ sec\]\s*$','m'); + ut.expect(g_tests_results).not_to_match('raised_same_exception'); + end; + + procedure throws_one_of_annotated_excpt is + begin + ut.expect(g_tests_results).to_match('^\s*Throws one of the listed exceptions \[[,\.0-9]+ sec\]\s*$','m'); + ut.expect(g_tests_results).not_to_match('raised_one_listed_exception'); + end; + + procedure throws_with_leading_zero is + begin + ut.expect(g_tests_results).to_match('^\s*Leading zero is ignored in exception list \[[,\.0-9]+ sec\]\s*$','m'); + ut.expect(g_tests_results).not_to_match('leading_0_exception_no'); + end; + + procedure throws_diff_annotated_except is + begin + ut.expect(g_tests_results).to_match('^\s*Throws diff exception \[[,\.0-9]+ sec\] \(FAILED - [0-9]+\)\s*$','m'); + ut.expect(g_tests_results).to_match('raised_diff_exception\s+Actual: -20143 was expected to equal: -20144\s+ORA-20143: Test error\s+ORA-06512: at "UT3_TESTER.ANNOTATED_PACKAGE_WITH_THROWS"'); + end; + + procedure throws_empty is + begin + ut.expect(g_tests_results).to_match('^\s*Throws empty \[[,\.0-9]+ sec\] \(FAILED - [0-9]+\)\s*$','m'); + ut.expect(g_tests_results).to_match('empty_throws\s*ORA-20143: Test error\s*ORA-06512: at "UT3_TESTER.ANNOTATED_PACKAGE_WITH_THROWS"'); + end; + + procedure bad_paramters_with_except is + begin + ut.expect(g_tests_results).to_match('^\s*Ignores annotation and fails when exception was thrown \[[,\.0-9]+ sec\] \(FAILED - [0-9]+\)\s*$','m'); + ut.expect(g_tests_results).to_match('bad_paramters_with_except\s*ORA-20143: Test error\s*ORA-06512: at "UT3_TESTER.ANNOTATED_PACKAGE_WITH_THROWS"'); + end; + + procedure bad_paramters_without_except is + begin + ut.expect(g_tests_results).to_match('^\s*Ignores annotation and succeeds when no exception thrown \[[,\.0-9]+ sec\]\s*$','m'); + ut.expect(g_tests_results).to_match('bad_paramters_without_except\s*Invalid parameter value ".*" for "--%throws" annotation. Parameter ignored.','m'); + end; + + procedure positive_exception_number is + begin + ut.expect(g_tests_results).to_match('^\s*Ignores annotation for positive exception number value \[[,\.0-9]+ sec\]\s*$','m'); + ut.expect(g_tests_results).to_match('positive_exception_number\s*Invalid parameter value "20001" for "--%throws" annotation. Exception value must be a negative integer. Parameter ignored.','m'); + end; + + procedure positive_exception_number_var is + begin + ut.expect(g_tests_results).to_match('^\s*Ignores annotation for positive exception number variable \[[,\.0-9]+ sec\]\s*$','m'); + ut.expect(g_tests_results).to_match('positive_exception_number_var\s*Invalid parameter value ".*" for "--%throws" annotation. Exception value must be a negative integer. Parameter ignored.','m'); + end; + + procedure one_valid_exception_number is + begin + ut.expect(g_tests_results).to_match('^\s*Detects a valid exception number within many invalid ones \[[\.0-9]+ sec\]\s*$','m'); + ut.expect(g_tests_results).to_match('one_valid_exception_number\s*Invalid parameter value ".*" for "--%throws" annotation. Parameter ignored.','m'); + end; + + procedure nothing_thrown is + begin + ut.expect(g_tests_results).to_match('^\s*Gives failure when a exception is expected and nothing is thrown \[[,\.0-9]+ sec\] \(FAILED - [0-9]+\)\s*$','m'); + ut.expect(g_tests_results).to_match('nothing_thrown\s*Expected one of exceptions \(-20459, -20136, -20145\) but nothing was raised.'); + end; + + procedure single_exc_const_pkg is + begin + ut.expect(g_tests_results).to_match('^\s*Single exception defined as a constant number in package \[[,\.0-9]+ sec\]\s*$','m'); + ut.expect(g_tests_results).not_to_match('single_exc_const_pkg'); + end; + + procedure list_of_exc_constant is + begin + ut.expect(g_tests_results).to_match('^\s*Gives success when one of annotated exception using constant is thrown \[[,\.0-9]+ sec\]\s*$','m'); + ut.expect(g_tests_results).not_to_match('list_of_exc_constant'); + end; + + procedure fail_not_match_exc is + begin + ut.expect(g_tests_results).to_match('^\s*Gives failure when the raised exception is different that the annotated one using variable \[[,\.0-9]+ sec\] \(FAILED - [0-9]+\)\s*$','m'); + ut.expect(g_tests_results).to_match('fail_not_match_exc\s+Actual: -1403 was expected to equal: -20204\s+ORA-01403: no data found\s+ORA-06512: at "UT3_TESTER.ANNOTATED_PACKAGE_WITH_THROWS"'); + end; + + procedure mixed_exc_list is + begin + ut.expect(g_tests_results).to_match('^\s*Success when one of exception from mixed list of number and constant is thrown \[[,\.0-9]+ sec\]\s*$','m'); + ut.expect(g_tests_results).not_to_match('mixed_exc_list'); + end; + + procedure mixed_list_notexi is + begin + ut.expect(g_tests_results).to_match('^\s*Success when match exception even if other variable on list dont exists \[[,\.0-9]+ sec\]\s*$','m'); + ut.expect(g_tests_results).to_match('mixed_list_notexi\s*Invalid parameter value "utter_rubbish" for "--%throws" annotation. Parameter ignored.','m'); + end; + + procedure named_exc_pragma is + begin + ut.expect(g_tests_results).to_match('^\s*Success resolve and match named exception defined in pragma exception init \[[,\.0-9]+ sec\]\s*$','m'); + ut.expect(g_tests_results).not_to_match('named_exc_pragma'); + end; + + procedure named_exc_ora is + begin + ut.expect(g_tests_results).to_match('^\s*Success resolve and match oracle named exception \[[,\.0-9]+ sec\]\s*$','m'); + ut.expect(g_tests_results).not_to_match('named_exc_ora'); + end; + + procedure named_exc_ora_dup_ind is + begin + ut.expect(g_tests_results).to_match('^\s*Success resolve and match oracle named exception dup val index \[[,\.0-9]+ sec\]\s*$','m'); + ut.expect(g_tests_results).not_to_match('named_exc_ora_dup_ind'); + end; + + procedure nodata_exc_ora is + begin + ut.expect(g_tests_results).to_match('^\s*Success map no data 100 to -1403 \[[,\.0-9]+ sec\]\s*$','m'); + ut.expect(g_tests_results).not_to_match('nodata_exc_ora'); + end; + + procedure defined_varchar_exc is + begin + ut.expect(g_tests_results).to_match('^\s*Success for exception defined as varchar \[[,\.0-9]+ sec\]\s*$','m'); + ut.expect(g_tests_results).not_to_match('defined_varchar_exc'); + end; + + procedure non_existing_const is + begin + ut.expect(g_tests_results).to_match('^\s*Non existing constant exception \[[,\.0-9]+ sec\] \(FAILED - [0-9]+\)\s*$','m'); + ut.expect(g_tests_results).to_match('non_existing_const\s*ORA-20143: Test error\s*ORA-06512: at "UT3_TESTER.ANNOTATED_PACKAGE_WITH_THROWS"'); + end; + + procedure bad_exc_const is + begin + ut.expect(g_tests_results).to_match('^\s*Bad exception constant \[[,\.0-9]+ sec\] \(FAILED - [0-9]+\)\s*$','m'); + ut.expect(g_tests_results).to_match('bad_exc_const\s*ORA-20143: Test error\s*ORA-06512: at "UT3_TESTER.ANNOTATED_PACKAGE_WITH_THROWS"'); + end; + + procedure drop_test_package is + pragma autonomous_transaction; + begin + execute immediate 'drop package annotated_package_with_throws'; + execute immediate 'drop package exc_pkg'; + end; + +end; +/ diff --git a/test/core/annotations/test_annot_throws_exception.pks b/test/ut3_tester/core/annotations/test_annot_throws_exception.pks similarity index 90% rename from test/core/annotations/test_annot_throws_exception.pks rename to test/ut3_tester/core/annotations/test_annot_throws_exception.pks index 54e814b55..a9d20183d 100644 --- a/test/core/annotations/test_annot_throws_exception.pks +++ b/test/ut3_tester/core/annotations/test_annot_throws_exception.pks @@ -1,7 +1,7 @@ create or replace package test_annot_throws_exception is --%suite(annotations - throws) - --%suitepath(utplsql.core.annotations) + --%suitepath(utplsql.ut3_tester.core.annotations) --%beforeall procedure recollect_tests_results; @@ -26,7 +26,13 @@ is --%test(Ignores when only bad parameters are passed, the test does not raise a exception and it shows successful test) procedure bad_paramters_without_except; - + + --%test(Ignores annotation for positive exception number value) + procedure positive_exception_number; + + --%test(Ignores annotation for positive exception number variable) + procedure positive_exception_number_var; + --%test(Detects a valid exception number within many invalid ones) procedure one_valid_exception_number; diff --git a/test/ut3_tester/core/annotations/test_annotation_cache.pkb b/test/ut3_tester/core/annotations/test_annotation_cache.pkb new file mode 100644 index 000000000..eefaf8800 --- /dev/null +++ b/test/ut3_tester/core/annotations/test_annotation_cache.pkb @@ -0,0 +1,521 @@ +create or replace package body test_annotation_cache is + + procedure cache_populated_for_packages(a_packages ut_varchar2_rows) is + l_actual_cache_info sys_refcursor; + l_expected_cache_info sys_refcursor; + begin + open l_actual_cache_info for + select * + from ut3_develop.ut_annotation_cache_info + where object_owner = 'UT3_CACHE_TEST_OWNER'; + open l_expected_cache_info for + select 'UT3_CACHE_TEST_OWNER' as object_owner, upper( column_value ) as object_name + from table (a_packages) x; + ut.expect( l_actual_cache_info ).to_equal( l_expected_cache_info ).exclude( 'CACHE_ID,PARSE_TIME,OBJECT_TYPE' ).JOIN_BY('OBJECT_NAME'); + end; + + procedure cant_run_any_packages(a_user varchar2) is + l_actual clob; + l_current_time date := sysdate; + pragma autonomous_transaction; + begin + --Act + l_actual := annotation_cache_helper.run_tests_as( a_user ); + + --Assert - no suites are + ut.expect( l_actual ).to_be_like( '%0 tests, 0 failed%' ); + rollback; + end; + + procedure can_run_one_package(a_user varchar2) is + l_actual clob; + l_current_time date := sysdate; + pragma autonomous_transaction; + begin + --Act + l_actual := annotation_cache_helper.run_tests_as( a_user ); + + --Assert - only granted_test_suite is invoked + ut.expect( l_actual ).to_be_like( 'granted_test_suite%2 tests, 0 failed%' ); + rollback; + end; + + procedure can_run_new_package(a_user varchar2) is + l_actual clob; + l_current_time date := sysdate; + pragma autonomous_transaction; + begin + --Arrange + l_actual := annotation_cache_helper.run_tests_as( a_user ); + annotation_cache_helper.add_new_suite( ); + --Act + l_actual := annotation_cache_helper.run_tests_as( a_user ); + --Assert -Both granted_test_suite and new_suite are invoked + ut.expect( l_actual ).to_be_like( 'granted_test_suite%new_suite%4 tests, 0 failed%' ); + rollback; + end ; + + procedure cant_run_revoked_package(a_user varchar2) is + l_actual clob; + l_current_time date := sysdate; + pragma autonomous_transaction; + begin + --Arrange + l_actual := annotation_cache_helper.run_tests_as( a_user ); + annotation_cache_helper.add_new_suite( ); + annotation_cache_helper.revoke_granted_suite( ); + + --Act + l_actual := annotation_cache_helper.run_tests_as( a_user ); + --Assert -Only new_suite gets invoked + ut.expect( l_actual ).to_be_like( 'new_suite%2 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%' ); + ut.expect( l_actual ).not_to_be_like( '%granted_test_suite%' ); + rollback; + end; + + procedure cant_run_dropped_package(a_user varchar2) is + l_actual clob; + l_current_time date := sysdate; + pragma autonomous_transaction; + begin + --Arrange + l_actual := annotation_cache_helper.run_tests_as( a_user ); + annotation_cache_helper.add_new_suite( ); + l_actual := annotation_cache_helper.run_tests_as( a_user ); + annotation_cache_helper.revoke_granted_suite( ); + annotation_cache_helper.cleanup_new_suite( ); + + --Act + l_actual := annotation_cache_helper.run_tests_as( a_user ); + --Assert - no test suites are invoked + ut.expect( l_actual ).to_be_like( '%0 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%' ); + ut.expect( l_actual ).not_to_be_like( '%new_suite%' ); + ut.expect( l_actual ).not_to_be_like( '%granted_test_suite%' ); + rollback; + end; + + procedure can_run_all_packages(a_user varchar2) is + l_actual clob; + l_current_time date := sysdate; + pragma autonomous_transaction; + begin + --Act + l_actual := annotation_cache_helper.run_tests_as( a_user ); + + --Assert - only granted_test_suite is invoked + ut.expect( l_actual ).to_be_like( 'granted_test_suite%not_granted_test_suite%4 tests, 0 failed%' ); + rollback; + end; + + procedure can_run_all_new_packages(a_user varchar2) is + l_actual clob; + l_current_time date := sysdate; + pragma autonomous_transaction; + begin + --Arrange + l_actual := annotation_cache_helper.run_tests_as( a_user ); + annotation_cache_helper.add_new_suite( ); + --Act + l_actual := annotation_cache_helper.run_tests_as( a_user ); + + --Assert - only granted_test_suite is invoked + ut.expect( l_actual ).to_be_like( 'granted_test_suite%new_suite%not_granted_test_suite% tests, 0 failed%' ); + rollback; + end; + + procedure can_run_revoked_packages(a_user varchar2) is + l_actual clob; + l_current_time date := sysdate; + pragma autonomous_transaction; + begin + --Arrange + l_actual := annotation_cache_helper.run_tests_as( a_user ); + annotation_cache_helper.add_new_suite( ); + annotation_cache_helper.revoke_granted_suite( ); + --Act + l_actual := annotation_cache_helper.run_tests_as( a_user ); + + --Assert - only granted_test_suite is invoked + ut.expect( l_actual ).to_be_like( 'granted_test_suite%new_suite%not_granted_test_suite% tests, 0 failed%' ); + rollback; + end; + + procedure can_run_all_but_dropped(a_user varchar2) is + l_actual clob; + l_current_time date := sysdate; + pragma autonomous_transaction; + begin + --Arrange + l_actual := annotation_cache_helper.run_tests_as( a_user ); + annotation_cache_helper.add_new_suite( ); + l_actual := annotation_cache_helper.run_tests_as( a_user ); + annotation_cache_helper.revoke_granted_suite( ); + annotation_cache_helper.cleanup_new_suite( ); + + --Act + l_actual := annotation_cache_helper.run_tests_as( a_user ); + --Assert - no test suites are invoked + ut.expect( l_actual ).to_be_like( 'granted_test_suite%not_granted_test_suite%4 tests, 0 failed%' ); + ut.expect( l_actual ).not_to_be_like( '%new_suite%' ); + rollback; + end; + + + procedure user_can_run_one_package is + begin + can_run_one_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE' ) ); + end; + + procedure user_can_run_new_package is + begin + can_run_new_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure user_cant_run_revoked_package is + begin + cant_run_revoked_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure user_cant_run_dropped_package is + begin + cant_run_dropped_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure sel_cat_user_can_run_one is + begin + can_run_one_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE' ) ); + end; + + procedure sel_cat_user_can_run_new is + begin + can_run_new_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure sel_cat_user_cant_run_revoked is + begin + cant_run_revoked_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure sel_cat_user_cant_run_dropped is + begin + cant_run_dropped_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure sel_any_user_can_run_one is + begin + can_run_one_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE' ) ); + end; + + procedure sel_any_user_can_run_new is + begin + can_run_new_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure sel_any_user_cant_run_revoked is + begin + cant_run_revoked_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure sel_any_user_cant_run_dropped is + begin + cant_run_dropped_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure exe_any_user_can_run_all is + begin + can_run_all_packages( 'ut3_execute_any_proc_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure exe_any_user_can_run_new is + begin + can_run_all_new_packages( 'ut3_execute_any_proc_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure exe_any_user_can_run_revoked is + begin + can_run_revoked_packages('ut3_execute_any_proc_user'); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure exe_any_user_cant_run_dropped is + begin + can_run_all_but_dropped('ut3_execute_any_proc_user'); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure owner_user_can_run_all is + begin + can_run_all_packages( 'ut3_cache_test_owner' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + + procedure owner_user_can_run_new is + begin + can_run_all_new_packages( 'ut3_cache_test_owner' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure owner_user_cant_run_dropped is + begin + can_run_all_but_dropped('ut3_cache_test_owner'); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + + procedure t_user_can_run_one_package is + begin + can_run_one_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_user_can_run_new_package is + begin + can_run_new_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_user_cant_run_revoked_pkg is + begin + cant_run_revoked_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_user_cant_run_dropped_pkg is + begin + cant_run_dropped_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_sel_cat_user_can_run_one is + begin + can_run_one_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_sel_cat_user_can_run_new is + begin + can_run_new_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_sel_cat_user_cant_run_revokd is + begin + cant_run_revoked_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_sel_cat_user_cant_run_dropd is + begin + cant_run_dropped_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + + procedure t_sel_any_user_can_run_one is + begin + can_run_one_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_sel_any_user_can_run_new is + begin + can_run_new_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_sel_any_user_cant_run_revokd is + begin + cant_run_revoked_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_sel_any_user_cant_run_dropd is + begin + cant_run_dropped_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + + procedure t_exe_any_user_can_run_all is + begin + can_run_all_packages( 'ut3_execute_any_proc_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_exe_any_user_can_run_new is + begin + can_run_all_new_packages( 'ut3_execute_any_proc_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_exe_any_user_can_run_revokd is + begin + can_run_revoked_packages( 'ut3_execute_any_proc_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_exe_any_user_cant_run_dropd is + begin + can_run_all_but_dropped( 'ut3_execute_any_proc_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_owner_user_can_run_all is + begin + can_run_all_packages( 'ut3_cache_test_owner' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_owner_user_can_run_new is + begin + can_run_all_new_packages( 'ut3_cache_test_owner' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_owner_user_cant_run_dropd is + begin + can_run_all_but_dropped( 'ut3_cache_test_owner' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_ut_owner_cannot_run_tests is + begin + cant_run_any_packages( 'ut3_develop' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + + + procedure p_user_can_run_one_package is + begin + can_run_one_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE' ) ); + end; + + procedure p_user_can_run_new_package is + begin + can_run_new_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure p_user_cant_run_revoked_pack is + begin + cant_run_revoked_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure p_user_cant_run_dropped_pack is + begin + cant_run_dropped_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE' ) ); + end; + + + + procedure p_sel_cat_user_can_run_one is + begin + can_run_one_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE' ) ); + end; + + procedure p_sel_cat_user_can_run_new is + begin + can_run_new_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure p_sel_cat_user_cant_run_revokd is + begin + cant_run_revoked_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure p_sel_cat_user_cant_run_dropd is + begin + cant_run_dropped_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE' ) ); + end; + + procedure p_sel_any_user_can_run_one is + begin + can_run_one_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE' ) ); + end; + + procedure p_sel_any_user_can_run_new is + begin + can_run_new_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure p_sel_any_user_cant_run_revokd is + begin + cant_run_revoked_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure p_sel_any_user_cant_run_dropd is + begin + cant_run_dropped_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE' ) ); + end; + + procedure p_exe_any_user_can_run_all is + begin + can_run_all_packages( 'ut3_execute_any_proc_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure p_exe_any_user_can_run_new is + begin + can_run_all_new_packages( 'ut3_execute_any_proc_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure p_exe_any_user_can_run_revokd is + begin + can_run_revoked_packages( 'ut3_execute_any_proc_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure p_exe_any_user_cant_run_dropd is + begin + can_run_all_but_dropped( 'ut3_execute_any_proc_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure p_owner_user_can_run_all is + begin + can_run_all_packages( 'ut3_cache_test_owner' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure p_owner_user_can_run_new is + begin + can_run_all_new_packages( 'ut3_cache_test_owner' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure p_owner_user_cant_run_dropped is + begin + can_run_all_but_dropped( 'ut3_cache_test_owner' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + +end; +/ diff --git a/test/ut3_tester/core/annotations/test_annotation_cache.pks b/test/ut3_tester/core/annotations/test_annotation_cache.pks new file mode 100644 index 000000000..5a3fdd8ca --- /dev/null +++ b/test/ut3_tester/core/annotations/test_annotation_cache.pks @@ -0,0 +1,280 @@ +create or replace package test_annotation_cache is + + --%suite(annotation cache) + --%suitepath(utplsql.ut3_tester.core.annotations) + --%beforeall(annotation_cache_helper.create_run_function_for_users) + --%afterall(annotation_cache_helper.drop_run_function_for_users) + + --%context(With DDL trigger enabled) + + --%beforeall(annotation_cache_helper.enable_ddl_trigger) + --%beforeeach(annotation_cache_helper.setup_two_suites) + --%aftereach(annotation_cache_helper.cleanup_new_suite) + --%afterall(annotation_cache_helper.cleanup_two_suites) + + --%context(User without elevated privileges) + + --%test(Can only execute granted packages) + procedure t_user_can_run_one_package; + + --%test(Can see newly created packages as they are added) + procedure t_user_can_run_new_package; + + --%test(Cannot execute revoked packages) + procedure t_user_cant_run_revoked_pkg; + + --%test(Cannot execute dropped unit test packages) + procedure t_user_cant_run_dropped_pkg; + + --%endcontext + + --%context(User with select_catalog_role) + + --%test(Can only execute granted packages) + procedure t_sel_cat_user_can_run_one; + + --%test(Can see newly created packages as they are added) + procedure t_sel_cat_user_can_run_new; + + --%test(Cannot execute revoked packages) + procedure t_sel_cat_user_cant_run_revokd; + + --%test(Cannot execute dropped unit test packages) + procedure t_sel_cat_user_cant_run_dropd; + + --%endcontext + + --%context(User with select any table privilege) + + --%test(Can only execute granted packages) + procedure t_sel_any_user_can_run_one; + + --%test(Can see newly created packages as they are added) + procedure t_sel_any_user_can_run_new; + + --%test(Cannot execute revoked packages) + procedure t_sel_any_user_cant_run_revokd; + + --%test(Cannot execute dropped unit test packages) + procedure t_sel_any_user_cant_run_dropd; + + --%endcontext + + --%context(User with execute any procedure) + + --%test(Can execute and see all unit test packages) + procedure t_exe_any_user_can_run_all; + + --%test(Can see newly created packages as they are added) + procedure t_exe_any_user_can_run_new; + + --%test(Can execute revoked packages) + procedure t_exe_any_user_can_run_revokd; + + --%test(Cannot execute dropped unit test packages) + procedure t_exe_any_user_cant_run_dropd; + + --%endcontext + + --%context(User owning test packages) + + --%test(Can execute and see all unit test packages) + procedure t_owner_user_can_run_all; + + --%test(Can see newly created packages as they are added) + procedure t_owner_user_can_run_new; + + --%test(Cannot execute dropped unit test packages) + procedure t_owner_user_cant_run_dropd; + + --%endcontext + + --%context(utPLSQL framework owner) + + --%test(Cannot see any tests and doesn't impact annotation cache ) + procedure t_ut_owner_cannot_run_tests; + + --%endcontext + + --%endcontext + + --%context(With DDL trigger disabled) + + --%beforeall(annotation_cache_helper.disable_ddl_trigger) + --%beforeeach(annotation_cache_helper.setup_two_suites) + --%beforeeach(annotation_cache_helper.purge_annotation_cache) + --%aftereach(annotation_cache_helper.cleanup_new_suite) + --%afterall(annotation_cache_helper.enable_ddl_trigger) + --%afterall(annotation_cache_helper.cleanup_two_suites) + + --%context(User without elevated privileges) + + --%test(Can only execute granted packages) + procedure user_can_run_one_package; + + --%test(Can see newly created packages as they are added) + procedure user_can_run_new_package; + + --%test(Cannot execute revoked packages) + procedure user_cant_run_revoked_package; + + --%test(Cannot execute dropped unit test packages) + procedure user_cant_run_dropped_package; + + --%endcontext + + --%context(User with select_catalog_role) + + --%test(Can only execute granted packages) + procedure sel_cat_user_can_run_one; + + --%test(Can see newly created packages as they are added) + procedure sel_cat_user_can_run_new; + + --%test(Cannot execute revoked packages) + procedure sel_cat_user_cant_run_revoked; + + --%test(Cannot execute dropped unit test packages) + procedure sel_cat_user_cant_run_dropped; + + --%endcontext + + --%context(User with select any table privilege) + + --%test(Can only execute granted packages) + procedure sel_any_user_can_run_one; + + --%test(Can see newly created packages as they are added) + procedure sel_any_user_can_run_new; + + --%test(Cannot execute revoked packages) + procedure sel_any_user_cant_run_revoked; + + --%test(Cannot execute dropped unit test packages) + procedure sel_any_user_cant_run_dropped; + + --%endcontext + + --%context(User with execute any procedure) + + --%test(Can execute and see all unit test packages) + procedure exe_any_user_can_run_all; + + --%test(Can see newly created packages as they are added) + procedure exe_any_user_can_run_new; + + --%test(Can execute revoked packages) + procedure exe_any_user_can_run_revoked; + + --%test(Cannot execute dropped unit test packages) + procedure exe_any_user_cant_run_dropped; + + --%endcontext + + --%context(User owning test packages) + + --%test(Can execute and see all unit test packages) + procedure owner_user_can_run_all; + + --%test(Can see newly created packages as they are added) + procedure owner_user_can_run_new; + + --%test(Cannot execute dropped unit test packages) + procedure owner_user_cant_run_dropped; + + --%endcontext + + --%endcontext + + --%context(With DDL trigger enabled and cache purged) + + --%beforeall(annotation_cache_helper.enable_ddl_trigger) + + --%beforeeach(annotation_cache_helper.setup_two_suites) + --%beforeeach(annotation_cache_helper.purge_annotation_cache) + + --%aftereach(annotation_cache_helper.cleanup_new_suite) + --%aftereach(annotation_cache_helper.cleanup_two_suites) + + --%context(User without elevated privileges) + + --%test(Can only execute granted packages) + procedure p_user_can_run_one_package; + + --%test(Can see newly created packages as they are added) + procedure p_user_can_run_new_package; + + --%test(Cannot execute revoked packages) + procedure p_user_cant_run_revoked_pack; + + --%test(Cannot execute dropped unit test packages) + procedure p_user_cant_run_dropped_pack; + + --%endcontext + + --%context(User with select_catalog_role) + + --%test(Can only execute granted packages) + procedure p_sel_cat_user_can_run_one; + + --%test(Can see newly created packages as they are added) + procedure p_sel_cat_user_can_run_new; + + --%test(Cannot execute revoked packages) + procedure p_sel_cat_user_cant_run_revokd; + + --%test(Cannot execute dropped unit test packages) + procedure p_sel_cat_user_cant_run_dropd; + + --%endcontext + + --%context(User with select any table privilege) + + --%test(Can only execute granted packages) + procedure p_sel_any_user_can_run_one; + + --%test(Can see newly created packages as they are added) + procedure p_sel_any_user_can_run_new; + + --%test(Cannot execute revoked packages) + procedure p_sel_any_user_cant_run_revokd; + + --%test(Cannot execute dropped unit test packages) + procedure p_sel_any_user_cant_run_dropd; + + --%endcontext + + --%context(User with execute any procedure) + + --%test(Can execute and see all unit test packages) + procedure p_exe_any_user_can_run_all; + + --%test(Can see newly created packages as they are added) + procedure p_exe_any_user_can_run_new; + + --%test(Can execute revoked packages) + procedure p_exe_any_user_can_run_revokd; + + --%test(Cannot execute dropped unit test packages) + procedure p_exe_any_user_cant_run_dropd; + + --%endcontext + + --%context(User owning test packages) + + --%test(Can execute and see all unit test packages) + procedure p_owner_user_can_run_all; + + --%test(Can see newly created packages as they are added) + procedure p_owner_user_can_run_new; + + --%test(Cannot execute dropped unit test packages) + procedure p_owner_user_cant_run_dropped; + + --%endcontext + + + --%endcontext + +end; +/ diff --git a/test/ut3_tester/core/annotations/test_annotation_manager.pkb b/test/ut3_tester/core/annotations/test_annotation_manager.pkb new file mode 100644 index 000000000..8eb3c2f6d --- /dev/null +++ b/test/ut3_tester/core/annotations/test_annotation_manager.pkb @@ -0,0 +1,466 @@ +create or replace package body test_annotation_manager is + + procedure exec_autonomous(a_sql varchar2) is + pragma autonomous_transaction; + begin + execute immediate a_sql; + end; + + procedure create_dummy_package is + begin + exec_autonomous(q'[create or replace package dummy_package as + procedure some_dummy_procedure; + end;]'); + end; + + procedure drop_dummy_package is + begin + exec_autonomous(q'[drop package dummy_package]'); + exception + when others then + null; + end; + + procedure recompile_dummy_package is + begin + exec_autonomous(q'[alter package dummy_package compile]'); + end; + + procedure create_dummy_test_package is + begin + exec_autonomous(q'[ + /* + * Some multiline comments before package spec + create or replace package dummy_test_package dummy comment to prove that we pick the right piece of code + */ + -- create or replace package dummy_test_package dummy comment to prove that we pick the right piece of code + --Some single-line comment before package spec + create or replace package dummy_test_package as + --%suite(dummy_test_suite) + --%rollback(manual) + + --create or replace package dummy_test_package dummy comment to prove that we pick the right piece of code + + --%test(dummy_test) + --%beforetest(some_procedure) + procedure some_dummy_test_procedure; + end;]'); + exec_autonomous(q'[grant execute on dummy_test_package to public]'); + end; + + procedure modify_dummy_test_package is + begin + exec_autonomous(q'[create or replace package dummy_test_package as + --%suite(dummy_test_suite) + + --%test(dummy_test) + procedure some_dummy_test_procedure; + end;]'); + end; + + procedure drop_dummy_test_package is + begin + exec_autonomous(q'[drop package dummy_test_package]'); + exception + when others then + null; + end; + + procedure recompile_dummy_test_package is + begin + exec_autonomous(q'[alter package dummy_test_package compile]'); + end; + + procedure create_parse_proc_as_ut3_user is + begin + ut3_tester_helper.main_helper.create_parse_proc_as_ut3_user(); + end; + + procedure parse_dummy_test_as_ut3_user is + begin + ut3_tester_helper.main_helper.parse_dummy_test_as_ut3_user(); + end; + + procedure drop_parse_proc_as_ut3_user is + begin + ut3_tester_helper.main_helper.drop_parse_proc_as_ut3_user(); + exception + when others then + null; + end; + + procedure cleanup_annotation_cache is + begin + ut3_tester_helper.main_helper.cleanup_annotation_cache(); + end; + + procedure assert_dummy_package(a_start_date date) is + l_actual_cache_id integer; + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + select max(cache_id) + into l_actual_cache_id + from ut3_develop.ut_annotation_cache_info + where object_owner = sys_context('USERENV', 'CURRENT_USER') and object_type = 'PACKAGE' and object_name = 'DUMMY_PACKAGE' + and parse_time >= a_start_date; + ut.expect(l_actual_cache_id).to_be_not_null; + + open l_actual for + select annotation_position, annotation_name, annotation_text, subobject_name + from ut3_develop.ut_annotation_cache where cache_id = l_actual_cache_id + order by annotation_position; + + ut.expect(l_actual).to_be_empty(); + end; + + procedure assert_dummy_test_package(a_start_time timestamp) is + l_actual_cache_id integer; + l_data ut3_develop.ut_annotated_objects; + l_result sys_refcursor; + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + open l_expected for + select + ut3_develop.ut_annotated_object( + sys_context('USERENV', 'CURRENT_USER'), + 'DUMMY_TEST_PACKAGE', 'PACKAGE', a_start_time, + ut3_develop.ut_annotations( + ut3_develop.ut_annotation( 2, 'suite', 'dummy_test_suite', null ), + ut3_develop.ut_annotation( 3, 'rollback', 'manual', null ), + ut3_develop.ut_annotation( 7, 'test', 'dummy_test', 'some_dummy_test_procedure' ), + ut3_develop.ut_annotation( 8, 'beforetest', 'some_procedure', 'some_dummy_test_procedure' ) + ) + ) annotated_object + from dual; + + l_result := ut3_develop.ut_annotation_manager.get_annotated_objects(sys_context('USERENV', 'CURRENT_USER'), 'PACKAGE', a_start_time); + fetch l_result bulk collect into l_data; + open l_actual for select value(x) as annotated_object from table(l_data) x where object_name = 'DUMMY_TEST_PACKAGE'; + ut.expect(l_actual).to_equal(l_expected).exclude('ANNOTATED_OBJECT/PARSE_TIME').join_by('ANNOTATED_OBJECT/OBJECT_NAME'); + end; + + + procedure trg_skip_existing_package is + l_actual_cache_id integer; + begin + --Arrange + annotation_cache_helper.disable_ddl_trigger(); + create_dummy_test_package(); + --Act + annotation_cache_helper.enable_ddl_trigger(); + --Assert + select max(cache_id) + into l_actual_cache_id + from ut3_develop.ut_annotation_cache_info + where object_owner = sys_context('USERENV', 'CURRENT_USER') and object_type = 'PACKAGE' and object_name = 'DUMMY_TEST_PACKAGE'; + + ut.expect(l_actual_cache_id).to_be_null; + end; + + --%test(Adds existing package to cache when package recompiled) + procedure trg_add_existing_on_compile is + l_start_date date; + begin + --Arrange + annotation_cache_helper.disable_ddl_trigger(); + create_dummy_test_package(); + --Act + annotation_cache_helper.enable_ddl_trigger(); + l_start_date := sysdate; + recompile_dummy_test_package(); + --Assert + assert_dummy_test_package(l_start_date); + end; + + --%test(Adds existing package to cache when schema cache refreshed) + procedure trg_add_existing_on_refresh is + l_start_date date; + begin + --Arrange + annotation_cache_helper.disable_ddl_trigger(); + create_dummy_test_package(); + create_dummy_package(); + --Act + annotation_cache_helper.enable_ddl_trigger(); + l_start_date := sysdate; + ut3_develop.ut_annotation_manager.rebuild_annotation_cache(sys_context('USERENV', 'CURRENT_USER'),'PACKAGE'); + --Assert + assert_dummy_test_package(l_start_date); + assert_dummy_package(l_start_date); + end; + + procedure trg_not_add_new_package is + l_actual sys_refcursor; + begin + --Arrange + open l_actual for + select * + from ut3_develop.ut_annotation_cache_info + where object_owner = sys_context('USERENV', 'CURRENT_USER') and object_type = 'PACKAGE' and object_name = 'DUMMY_PACKAGE'; + + ut.expect(l_actual).to_be_empty(); + + --Act + create_dummy_package(); + --Assert + open l_actual for + select * + from ut3_develop.ut_annotation_cache_info + where object_owner = sys_context('USERENV', 'CURRENT_USER') and object_type = 'PACKAGE' and object_name = 'DUMMY_PACKAGE'; + + ut.expect(l_actual).to_be_empty(); + end; + + procedure trg_add_new_test_package is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_start_date date; + begin + --Arrange + l_start_date := sysdate; + --Act + create_dummy_test_package(); + --Assert + assert_dummy_test_package(l_start_date); + end; + + procedure trg_no_data_for_dropped_object is + l_actual sys_refcursor; + begin + drop_dummy_test_package(); + --Assert + open l_actual for + select * + from ut3_develop.ut_annotation_cache_info + where object_owner = sys_context('USERENV', 'CURRENT_USER') + and object_type = 'PACKAGE' and object_name = 'DUMMY_TEST_PACKAGE'; + + ut.expect(l_actual).to_be_empty(); + + end; + + procedure trg_populate_cache_after_purge is + l_start_date date; + begin + --Arrange + create_dummy_test_package(); + l_start_date := sysdate; + ut3_develop.ut_annotation_manager.purge_cache(sys_context('USERENV', 'CURRENT_USER'), 'PACKAGE'); + --Act & Assert + assert_dummy_test_package(l_start_date); + end; + + procedure add_annotated_package is + l_start_time timestamp := systimestamp; + begin + --Arrange + create_dummy_test_package(); + --Act & Assert + assert_dummy_test_package( l_start_time ); + end; + + procedure remove_annotated_package is + l_start_time timestamp := systimestamp; + begin + --Arrange + create_dummy_test_package(); + assert_dummy_test_package( l_start_time ); + + --Act + drop_dummy_test_package(); + + --Assert + ut.expect( + ut3_develop.ut_annotation_manager.get_annotated_objects( + sys_context( 'USERENV', 'CURRENT_USER' ), 'PACKAGE', l_start_time + ), + 'Annotations are empty after package was dropped' + ).to_be_empty(); + end; + + procedure add_not_annotated_package is + l_start_time timestamp := systimestamp; + begin + --Arrange + create_dummy_package(); + --Act & Assert + ut.expect( + ut3_develop.ut_annotation_manager.get_annotated_objects( + sys_context( 'USERENV', 'CURRENT_USER' ), 'PACKAGE', l_start_time + ), + 'Annotations are empty for not annotated package' + ).to_be_empty(); + end; + + procedure remove_not_annotated_package is + l_start_time timestamp := systimestamp; + begin + --Arrange + create_dummy_package(); + ut.expect( + ut3_develop.ut_annotation_manager.get_annotated_objects( + sys_context( 'USERENV', 'CURRENT_USER' ), 'PACKAGE', l_start_time + ), + 'Annotations are empty for non annotated package' + ).to_be_empty(); + + --Act + drop_dummy_package(); + + --Assert + ut.expect( + ut3_develop.ut_annotation_manager.get_annotated_objects( + sys_context( 'USERENV', 'CURRENT_USER' ), 'PACKAGE', l_start_time + ), + 'Annotations are empty after non annoteted package was dropped' + ).to_be_empty(); + end; + + procedure remove_annotations_from_pkg is + l_start_time timestamp := systimestamp; + begin + --Arrange + create_dummy_test_package(); + assert_dummy_test_package( l_start_time ); + + --Act + exec_autonomous(q'[create or replace package dummy_test_package as + procedure some_dummy_test_procedure; + end;]'); + + --Assert + ut.expect( + ut3_develop.ut_annotation_manager.get_annotated_objects( + sys_context( 'USERENV', 'CURRENT_USER' ), 'PACKAGE', l_start_time + ) + ).to_be_empty(); + end; + + procedure add_annotations_to_package is + l_start_time timestamp := systimestamp; + begin + --Arrange + exec_autonomous(q'[create or replace package dummy_test_package as + procedure some_dummy_test_procedure; + end;]'); + ut.expect( + ut3_develop.ut_annotation_manager.get_annotated_objects( + sys_context( 'USERENV', 'CURRENT_USER' ), 'PACKAGE', l_start_time + ) + ).to_be_empty(); + + --Act + create_dummy_test_package(); + + --Assert + assert_dummy_test_package( l_start_time ); + end; + + procedure update_modified_test_package is + l_actual_cache_id integer; + l_actual sys_refcursor; + l_expected sys_refcursor; + l_start_date date; + begin + --Arrange + ut3_develop.ut_annotation_manager.rebuild_annotation_cache(sys_context('USERENV', 'CURRENT_USER'),'PACKAGE'); + l_start_date := sysdate; + modify_dummy_test_package(); + --Act + ut3_develop.ut_annotation_manager.rebuild_annotation_cache(sys_context('USERENV', 'CURRENT_USER'),'PACKAGE'); + --Assert + select max(cache_id) + into l_actual_cache_id + from ut3_develop.ut_annotation_cache_info + where object_owner = sys_context('USERENV', 'CURRENT_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; + + open l_actual for + select annotation_position, annotation_name, annotation_text, subobject_name + from ut3_develop.ut_annotation_cache where cache_id = l_actual_cache_id + order by annotation_position; + + open l_expected for + select 2 as annotation_position, 'suite' as annotation_name, + 'dummy_test_suite' as annotation_text, to_char(null) as subobject_name + from dual union all + select 4, 'test' , 'dummy_test', 'some_dummy_test_procedure' as subobject_name + from dual; + + ut.expect(l_actual).to_equal(l_expected); + end; + + + procedure keep_dropped_data_in_cache is + l_cache_count integer; + l_start_date date; + begin + l_start_date := sysdate; + parse_dummy_test_as_ut3_user(); + drop_dummy_test_package(); + --Act + parse_dummy_test_as_ut3_user(); + --Assert + select count(1) + into l_cache_count + from ut3_develop.ut_annotation_cache_info + where object_owner = sys_context('USERENV', 'CURRENT_USER') + and object_type = 'PACKAGE' + and object_name = 'DUMMY_TEST_PACKAGE' + and parse_time > l_start_date; + ut.expect( l_cache_count ).to_equal(1); + end; + + procedure no_data_for_dropped_object is + l_result sys_refcursor; + l_data ut3_develop.ut_annotated_objects; + l_actual sys_refcursor; + l_start_time timestamp := systimestamp; + begin + --Arrange + drop_dummy_test_package(); + --Act + l_result := ut3_develop.ut_annotation_manager.get_annotated_objects( sys_context('USERENV', 'CURRENT_USER'),'PACKAGE', l_start_time ); + fetch l_result bulk collect into l_data; + open l_actual for select object_name from table(l_data) where object_name = 'DUMMY_TEST_PACKAGE'; + --Assert + ut.expect(l_actual).to_be_empty(); + end; + + procedure cleanup_dropped_data_in_cache is + l_cache_count integer; + begin + --Arrange + ut3_develop.ut_annotation_manager.rebuild_annotation_cache(sys_context('USERENV', 'CURRENT_USER'),'PACKAGE'); + drop_dummy_test_package(); + --Act + ut3_develop.ut_annotation_manager.rebuild_annotation_cache(sys_context('USERENV', 'CURRENT_USER'),'PACKAGE'); + --Assert + select count(1) + into l_cache_count + from ut3_develop.ut_annotation_cache_info + where object_owner = sys_context('USERENV', 'CURRENT_USER') + and object_type = 'PACKAGE' + and object_name = 'DUMMY_TEST_PACKAGE'; + + ut.expect(l_cache_count).to_equal(0); + + end; + + procedure populate_cache_after_purge is + l_start_date date; + begin + --Arrange + create_dummy_test_package(); + l_start_date := sysdate; + ut3_develop.ut_annotation_manager.purge_cache(sys_context('USERENV', 'CURRENT_USER'), 'PACKAGE'); + --Act & Assert + assert_dummy_test_package(l_start_date); + end; + +end test_annotation_manager; +/ diff --git a/test/ut3_tester/core/annotations/test_annotation_manager.pks b/test/ut3_tester/core/annotations/test_annotation_manager.pks new file mode 100644 index 000000000..7207917f3 --- /dev/null +++ b/test/ut3_tester/core/annotations/test_annotation_manager.pks @@ -0,0 +1,104 @@ +create or replace package test_annotation_manager is + + --%suite(ut_annotation_manager) + --%suitepath(utplsql.ut3_tester.core.annotations) + + --%afterall(drop_dummy_test_package) + + --%aftereach + procedure cleanup_annotation_cache; + + procedure create_dummy_package; + + procedure drop_dummy_package; + + procedure create_dummy_test_package; + + procedure create_parse_proc_as_ut3_user; + + procedure drop_parse_proc_as_ut3_user; + + procedure drop_dummy_test_package; + + --%context(With DDL trigger enabled) + + --%aftereach(drop_dummy_test_package,drop_dummy_package) + + --%test(Does not detect unit test packages created before enabling trigger) + procedure trg_skip_existing_package; + + --%test(Adds existing package to cache when package recompiled) + procedure trg_add_existing_on_compile; + + --%test(Adds existing package to cache when schema cache refreshed) + procedure trg_add_existing_on_refresh; + + --%test(Doesn't add package to annotation cache info when it is not unit test package) + procedure trg_not_add_new_package; + + --%test(Populates annotation cache when package created) + procedure trg_add_new_test_package; + + --%test(Removes annotations from cache when object was removed and user can't see whole schema) + --%beforetest(create_dummy_test_package) + procedure trg_no_data_for_dropped_object; + + --%test(Objects are populated on scan after cache was purged) + --%beforetest(annotation_cache_helper.disable_ddl_trigger) + --%aftertest(annotation_cache_helper.enable_ddl_trigger) + procedure trg_populate_cache_after_purge; + + --%endcontext + + --%context(Without DDL trigger) + + --%beforeall(annotation_cache_helper.disable_ddl_trigger) + + --%afterall(annotation_cache_helper.enable_ddl_trigger) + + --%beforeeach(create_dummy_package) + --%aftereach(drop_dummy_package) + + --%test(Returns annotations when annotated package was created) + --%aftertest(drop_dummy_test_package) + procedure add_annotated_package; + + --%test(Doesn't return annotations when annotated package was removed) + --%aftertest(drop_dummy_test_package) + procedure remove_annotated_package; + + --%test(Doesn't return annotations when package doesn't contain annotations) + procedure add_not_annotated_package; + + --%test(Doesn't return annotations when package without annotations was dropped) + procedure remove_not_annotated_package; + + --%test(Doesn't return annotations when annotations removed from package) + --%aftertest(drop_dummy_test_package) + procedure remove_annotations_from_pkg; + + --%test(Returns annotations when annotations were added to package) + --%aftertest(drop_dummy_test_package) + procedure add_annotations_to_package; + + --%test(Updates annotations in cache for modified test package) + procedure update_modified_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) + procedure no_data_for_dropped_object; + + --%test(Remove object from cache when object dropped and user can see whole schema) + procedure cleanup_dropped_data_in_cache; + + --%test(Objects are populated on scan after cache was purged) + procedure populate_cache_after_purge; + + --%endcontext + +end test_annotation_manager; +/ diff --git a/test/ut3_tester/core/annotations/test_annotation_parser.pkb b/test/ut3_tester/core/annotations/test_annotation_parser.pkb new file mode 100644 index 000000000..bc789c377 --- /dev/null +++ b/test/ut3_tester/core/annotations/test_annotation_parser.pkb @@ -0,0 +1,461 @@ +create or replace package body test_annotation_parser is + + procedure test_proc_comments is + l_source clob; + l_actual ut3_develop.ut_annotations; + l_expected ut3_develop.ut_annotations; + + begin + l_source := 'PACKAGE test_tt AS + -- %suite + -- %displayname(Name of suite) + -- %suitepath(all.globaltests) + + -- %ann1(Name of suite) + -- wrong line + -- %ann2(some_value) + procedure foo; + END;'; + + --Act + l_actual := ut3_develop.ut_annotation_parser.parse_object_annotations(l_source); + + --Assert + + l_expected := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2,'suite',null, null), + ut3_develop.ut_annotation(3,'displayname','Name of suite',null), + ut3_develop.ut_annotation(4,'suitepath','all.globaltests',null), + ut3_develop.ut_annotation(6,'ann1','Name of suite',null), + ut3_develop.ut_annotation(8,'ann2','some_value','foo') + ); + + ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); + end; + + procedure include_floating_annotations is + l_source clob; + l_actual ut3_develop.ut_annotations; + l_expected ut3_develop.ut_annotations; + begin + l_source := 'PACKAGE test_tt AS + -- %suite + -- %displayname(Name of suite) + -- %suitepath(all.globaltests) + + -- %ann1(Name of suite) + -- %ann2(all.globaltests) + + --%test + procedure foo; + + -- %ann3(Name of suite) + -- %ann4(all.globaltests) + + --%test + procedure bar; + END;'; + + --Act + l_actual := ut3_develop.ut_annotation_parser.parse_object_annotations(l_source); + + --Assert + l_expected := ut3_develop.ut_annotations( + ut3_develop.ut_annotation( 2, 'suite', null, null ), + ut3_develop.ut_annotation( 3, 'displayname', 'Name of suite', null ), + ut3_develop.ut_annotation( 4, 'suitepath', 'all.globaltests', null ), + ut3_develop.ut_annotation( 6, 'ann1', 'Name of suite', null ), + ut3_develop.ut_annotation( 7, 'ann2', 'all.globaltests', null ), + ut3_develop.ut_annotation( 9, 'test', null, 'foo'), + ut3_develop.ut_annotation( 12, 'ann3', 'Name of suite', null ), + ut3_develop.ut_annotation( 13, 'ann4', 'all.globaltests', null ), + ut3_develop.ut_annotation( 15, 'test', null, 'bar') + ); + + ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); + + end; + + procedure parse_complex_with_functions is + l_source clob; + l_actual ut3_develop.ut_annotations; + l_expected ut3_develop.ut_annotations; + + begin + l_source := 'PACKAGE test_tt AS + -- %suite + -- %displayname(Name of suite) + -- %suitepath(all.globaltests) + + --%test + procedure foo; + + + --%beforeeach + procedure foo2; + + --test comment + -- wrong comment + + + /* + describtion of the procedure + */ + --%beforeeach(key=testval) + PROCEDURE foo3(a_value number default null); + + --%all + function foo4(a_val number default null + , a_par varchar2 default := ''asdf''); + END;'; + + --Act + l_actual := ut3_develop.ut_annotation_parser.parse_object_annotations(l_source); + + --Assert + l_expected := ut3_develop.ut_annotations( + ut3_develop.ut_annotation( 2, 'suite', null, null ), + ut3_develop.ut_annotation( 3, 'displayname', 'Name of suite', null ), + ut3_develop.ut_annotation( 4, 'suitepath', 'all.globaltests', null ), + ut3_develop.ut_annotation( 6, 'test', null, 'foo' ), + ut3_develop.ut_annotation( 10, 'beforeeach', null,'foo2' ), + ut3_develop.ut_annotation( 20, 'beforeeach', 'key=testval','foo3' ), + ut3_develop.ut_annotation( 23, 'all', null,'foo4' ) + ); + + ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); + + end; + + procedure no_procedure_annotation is + l_source clob; + l_actual ut3_develop.ut_annotations; + l_expected ut3_develop.ut_annotations; + + begin + l_source := 'PACKAGE test_tt AS + -- %suite + -- %displayname(Name of suite) + -- %suitepath(all.globaltests) + + procedure foo; + END;'; + + --Act + l_actual := ut3_develop.ut_annotation_parser.parse_object_annotations(l_source); + + --Assert + l_expected := ut3_develop.ut_annotations( + ut3_develop.ut_annotation( 2, 'suite', null, null ), + ut3_develop.ut_annotation( 3, 'displayname', 'Name of suite', null ), + ut3_develop.ut_annotation( 4, 'suitepath', 'all.globaltests', null ) + ); + + ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); + + end; + + procedure parse_accessible_by is + l_source clob; + l_actual ut3_develop.ut_annotations; + l_expected ut3_develop.ut_annotations; + + begin + l_source := 'PACKAGE test_tt accessible by (foo) AS + -- %suite + -- %displayname(Name of suite) + -- %suitepath(all.globaltests) + + procedure foo; + END;'; + + --Act + l_actual := ut3_develop.ut_annotation_parser.parse_object_annotations(l_source); + + --Assert + l_expected := ut3_develop.ut_annotations( + ut3_develop.ut_annotation( 2, 'suite', null, null ), + ut3_develop.ut_annotation( 3, 'displayname', 'Name of suite', null ), + ut3_develop.ut_annotation( 4, 'suitepath', 'all.globaltests', null ) + ); + + ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); + + end; + + procedure complex_package_declaration is + l_source clob; + l_actual ut3_develop.ut_annotations; + l_expected ut3_develop.ut_annotations; + + begin + l_source := 'PACKAGE test_tt + ACCESSIBLE BY (calling_proc) + authid current_user + AS + -- %suite + -- %displayname(Name of suite) + -- %suitepath(all.globaltests) + + procedure foo; + END;'; + + --Act + l_actual := ut3_develop.ut_annotation_parser.parse_object_annotations(l_source); + + --Assert + l_expected := ut3_develop.ut_annotations( + ut3_develop.ut_annotation( 5, 'suite', null, null ), + ut3_develop.ut_annotation( 6, 'displayname', 'Name of suite', null ), + ut3_develop.ut_annotation( 7, 'suitepath', 'all.globaltests', null ) + ); + + ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); + + end; + + procedure complex_text is + l_source clob; + l_actual ut3_develop.ut_annotations; + l_expected ut3_develop.ut_annotations; + + begin + l_source := 'PACKAGE test_tt AS + -- %suite + --%displayname(name = Name of suite) + -- %suitepath(key=all.globaltests,key2=foo,"--%some text") + + procedure foo; + END;'; + + --Act + l_actual := ut3_develop.ut_annotation_parser.parse_object_annotations(l_source); + + --Assert + l_expected := ut3_develop.ut_annotations( + ut3_develop.ut_annotation( 2, 'suite', null, null ), + ut3_develop.ut_annotation( 3, 'displayname', 'name = Name of suite', null ), + ut3_develop.ut_annotation( 4, 'suitepath', 'key=all.globaltests,key2=foo,"--%some text"', null ) + ); + + ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); + + end; + + procedure ignore_annotations_in_comments is + l_source clob; + l_actual ut3_develop.ut_annotations; + l_expected ut3_develop.ut_annotations; + + begin + l_source := 'PACKAGE test_tt AS + /* + Some comment + -- inlined + -- %ignored + */ + -- %suite + --%displayname(Name of suite) + -- %suitepath(all.globaltests) + + procedure foo; + END;'; + + --Act + l_actual := ut3_develop.ut_annotation_parser.parse_object_annotations(l_source); + + --Assert + l_expected := ut3_develop.ut_annotations( + ut3_develop.ut_annotation( 7, 'suite', null, null ), + ut3_develop.ut_annotation( 8, 'displayname', 'Name of suite', null ), + ut3_develop.ut_annotation( 9, 'suitepath', 'all.globaltests', null ) + ); + + ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); + + end; + + procedure ignore_wrapped_package is + l_source dbms_preprocessor.source_lines_t; + l_actual ut3_develop.ut_annotations; + begin + --Arrange + l_source(1) := 'create or replace PACKAGE tst_wrapped_pck wrapped +a000000 +369 +abcd +abcd +abcd +abcd +abcd +abcd +abcd +abcd +abcd +abcd +abcd +abcd +abcd +abcd +abcd +9 +34 6d +bg9Jaf2KguofrwaqloE8yvbggKcwg5m49TOf9b9cFj7R9JaW8lYWWi70llr/K6V0iwlp5+eb +v58yvbLAXLi9gYHwoIvAgccti+Cmpg0DKLY= +-- %some_annotation_like_text +'; + --Act + l_actual := ut3_develop.ut_annotation_parser.parse_object_annotations(l_source,'PACKAGE'); + --Assert + ut.expect(anydata.convertCollection(l_actual)).to_be_empty(); + end; + + procedure brackets_in_desc is + + l_source clob; + l_actual ut3_develop.ut_annotations; + l_expected ut3_develop.ut_annotations; + begin + l_source := 'PACKAGE test_tt AS + -- %suite(Name of suite (including some brackets) and some more text) +END;'; + + --Act + l_actual := ut3_develop.ut_annotation_parser.parse_object_annotations(l_source); + + --Assert + l_expected := ut3_develop.ut_annotations( + ut3_develop.ut_annotation( 2, 'suite', 'Name of suite (including some brackets) and some more text', null ) + ); + + ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); + end; + + procedure test_space_before_annot_params is + l_source clob; + l_actual ut3_develop.ut_annotations; + l_expected ut3_develop.ut_annotations; + + begin + l_source := 'PACKAGE test_tt AS + /* + Some comment + -- inlined + */ + -- %suite + -- %suitepath (all.globaltests) + + procedure foo; +END;'; + + --Act + l_actual := ut3_develop.ut_annotation_parser.parse_object_annotations(l_source); + + --Assert + l_expected := ut3_develop.ut_annotations( + ut3_develop.ut_annotation( 6, 'suite', null, null ), + ut3_develop.ut_annotation( 7, 'suitepath', 'all.globaltests', null ) + ); + + ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); + end; + + procedure test_windows_newline + as + l_source clob; + l_actual ut3_develop.ut_annotations; + l_expected ut3_develop.ut_annotations; + begin + l_source := 'PACKAGE test_tt AS + -- %suite + -- %displayname(Name of suite)' || chr(13) || chr(10) + || ' -- %suitepath(all.globaltests) + END;'; + + --Act + l_actual := ut3_develop.ut_annotation_parser.parse_object_annotations(l_source); + + --Assert + l_expected := ut3_develop.ut_annotations( + ut3_develop.ut_annotation( 2, 'suite', null, null ), + ut3_develop.ut_annotation( 3, 'displayname', 'Name of suite', null ), + ut3_develop.ut_annotation( 4, 'suitepath', 'all.globaltests', null ) + ); + + ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); + end; + + procedure test_annot_very_long_name + as + l_source clob; + l_actual ut3_develop.ut_annotations; + l_expected ut3_develop.ut_annotations; + begin + l_source := 'PACKAGE very_long_procedure_name_valid_for_oracle_12_so_utPLSQL_should_allow_it_definitely_well_still_not_reached_128_but_wait_we_did_it AS + -- %suite + -- %displayname(Name of suite) + -- %suitepath(all.globaltests) + + --%test + procedure very_long_procedure_name_valid_for_oracle_12_so_utPLSQL_should_allow_it_definitely_well_still_not_reached_128_but_wait_we_dit_it; + END;'; + + --Act + l_actual := ut3_develop.ut_annotation_parser.parse_object_annotations(l_source); + + --Assert + l_expected := ut3_develop.ut_annotations( + ut3_develop.ut_annotation( 2, 'suite', null, null ), + ut3_develop.ut_annotation( 3, 'displayname', 'Name of suite', null ), + ut3_develop.ut_annotation( 4, 'suitepath', 'all.globaltests', null ), + ut3_develop.ut_annotation( 6, 'test', null, 'very_long_procedure_name_valid_for_oracle_12_so_utPLSQL_should_allow_it_definitely_well_still_not_reached_128_but_wait_we_dit_it' ) + ); + + ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); + end; + + procedure test_upper_annot is + l_source clob; + l_actual ut3_develop.ut_annotations; + l_expected ut3_develop.ut_annotations; + begin + l_source := 'PACKAGE test_tt AS + -- %SUITE + -- %DISPLAYNAME(Name of suite) + -- %SUITEPATH(all.globaltests) + + -- %ANN1(Name of suite) + -- %ANN2(all.globaltests) + + --%TEST + procedure foo; + + -- %ANN3(Name of suite) + -- %ANN4(all.globaltests) + + --%TEST + procedure bar; + END;'; + + --Act + l_actual := ut3_develop.ut_annotation_parser.parse_object_annotations(l_source); + + --Assert + l_expected := ut3_develop.ut_annotations( + ut3_develop.ut_annotation( 2, 'suite', null, null ), + ut3_develop.ut_annotation( 3, 'displayname', 'Name of suite', null ), + ut3_develop.ut_annotation( 4, 'suitepath', 'all.globaltests', null ), + ut3_develop.ut_annotation( 6, 'ann1', 'Name of suite', null ), + ut3_develop.ut_annotation( 7, 'ann2', 'all.globaltests', null ), + ut3_develop.ut_annotation( 9, 'test', null, 'foo'), + ut3_develop.ut_annotation( 12, 'ann3', 'Name of suite', null ), + ut3_develop.ut_annotation( 13, 'ann4', 'all.globaltests', null ), + ut3_develop.ut_annotation( 15, 'test', null, 'bar') + ); + + ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); + + end; + +end test_annotation_parser; +/ diff --git a/test/core/annotations/test_annotation_parser.pks b/test/ut3_tester/core/annotations/test_annotation_parser.pks similarity index 92% rename from test/core/annotations/test_annotation_parser.pks rename to test/ut3_tester/core/annotations/test_annotation_parser.pks index e606c438f..a4fe3ed70 100644 --- a/test/core/annotations/test_annotation_parser.pks +++ b/test/ut3_tester/core/annotations/test_annotation_parser.pks @@ -1,7 +1,7 @@ create or replace package test_annotation_parser is --%suite(ut_annotation_parser) - --%suitepath(utplsql.core.annotations) + --%suitepath(utplsql.ut3_tester.core.annotations) --%test(Treats procedure level annotations as package level, if mixed with comments) procedure test_proc_comments; @@ -35,5 +35,8 @@ create or replace package test_annotation_parser is -- %test(Parses annotations with very long object names) procedure test_annot_very_long_name; + -- %test(Parses upper case annotations) + procedure test_upper_annot; + end test_annotation_parser; / diff --git a/test/core/annotations/test_before_after_test_annotation.pkb b/test/ut3_tester/core/annotations/test_before_after_annotations.pkb similarity index 94% rename from test/core/annotations/test_before_after_test_annotation.pkb rename to test/ut3_tester/core/annotations/test_before_after_annotations.pkb index 06871a335..75bbadcc0 100644 --- a/test/core/annotations/test_before_after_test_annotation.pkb +++ b/test/ut3_tester/core/annotations/test_before_after_annotations.pkb @@ -28,7 +28,7 @@ create or replace package body test_before_after_annotations is l_dummy_utility_pkg_body varchar2(32737); l_test_package_spec varchar2(32737); l_test_package_body varchar2(32737); - l_test_results ut3.ut_varchar2_list; + l_test_results ut3_develop.ut_varchar2_list; begin l_dummy_utility_pkg_spec := q'[ @@ -200,12 +200,12 @@ create or replace package body test_before_after_annotations is execute immediate l_test_package_body; --Execute the tests and collect the results - select * bulk collect into l_test_results from table(ut3.ut.run(('dummy_before_after_test'))); + select * bulk collect into l_test_results from table(ut3_develop.ut.run(('ut3_tester.dummy_before_after_test'))); execute immediate 'drop package dummy_before_after_test'; execute immediate 'drop package shared_test_package'; - g_tests_results := ut3.ut_utils.table_to_clob(l_test_results); + g_tests_results := ut3_tester_helper.main_helper.table_to_clob(l_test_results); end; procedure beforetest_local_procedure is @@ -277,13 +277,12 @@ create or replace package body test_before_after_annotations is ut.expect(l_actual).to_be_empty; ut.expect(g_tests_results).to_match( - '^\s*Stops execution at first non-existing Beforetest procedure and marks test as errored \[[\.0-9]+ sec\] \(FAILED - 1\)\s*$' + '^\s*Stops execution at first non-existing Beforetest procedure and marks test as errored \[[,\.0-9]+ sec\] \(FAILED - 1\)\s*$' ,'m' ); ut.expect(g_tests_results).to_match( '1\) beforetest_missing_procedure\s+' || - 'Call params for beforetest are not valid: procedure does not exist ' || - 'UT3_TESTER.DUMMY_BEFORE_AFTER_TEST.NON_EXISTENT_PROCEDURE' + 'Call params for beforetest are not valid: procedure UT3_TESTER\.DUMMY_BEFORE_AFTER_TEST\.NON_EXISTENT_PROCEDURE does not exist\.' ,'m' ); end; @@ -297,7 +296,7 @@ create or replace package body test_before_after_annotations is ut.expect(l_actual).to_be_empty; ut.expect(g_tests_results).to_match( - '^\s*Stops execution at first non-existing Beforetest procedure and marks test as errored \[[\.0-9]+ sec\] \(FAILED - 1\)\s*$' + '^\s*Stops execution at first non-existing Beforetest procedure and marks test as errored \[[,\.0-9]+ sec\] \(FAILED - 1\)\s*$' ,'m' ); ut.expect(g_tests_results).to_match( diff --git a/test/core/annotations/test_before_after_test_annotation.pks b/test/ut3_tester/core/annotations/test_before_after_annotations.pks similarity index 96% rename from test/core/annotations/test_before_after_test_annotation.pks rename to test/ut3_tester/core/annotations/test_before_after_annotations.pks index a4ce52727..062efff48 100644 --- a/test/core/annotations/test_before_after_test_annotation.pks +++ b/test/ut3_tester/core/annotations/test_before_after_annotations.pks @@ -1,7 +1,7 @@ create or replace package test_before_after_annotations is --%suite(annotations - beforetest and aftertest) - --%suitepath(utplsql.core.annotations) + --%suitepath(utplsql.ut3_tester.core.annotations) subtype t_procedure_name is varchar2(250) not null; type t_procedures is table of t_procedure_name; diff --git a/test/ut3_tester/core/expectations/test_expectation_processor.pkb b/test/ut3_tester/core/expectations/test_expectation_processor.pkb new file mode 100644 index 000000000..63ce3c791 --- /dev/null +++ b/test/ut3_tester/core/expectations/test_expectation_processor.pkb @@ -0,0 +1,105 @@ +create or replace package body test_expectation_processor is + + gc_user constant varchar2(128) := sys_context('userenv','current_schema'); + + procedure who_called_expectation is + l_stack_trace varchar2(4000); + l_source_line varchar2(4000); + begin + l_stack_trace := q'[----- PL/SQL Call Stack ----- + object line object + handle number name +34f88e4420 124 package body SCH_TEST.UT_EXPECTATION_PROCESSOR +353dfeb2f8 26 SCH_TEST.UT_EXPECTATION_RESULT +cba2493ce0 112 SCH_TEST.UT_EXPECTATION +3539881cf0 21 SCH_TEST.UT_EXPECTATION_NUMBER +351a608008 7 package body ]'||gc_user||q'[.TEST_EXPECTATION_PROCESSOR +351a608018 12 package body ]'||gc_user||q'[.TEST_EXPECTATION_PROCESSOR +351a608018 24 package body ]'||gc_user||q'[.TEST_EXPECTATION_PROCESSOR +351a6862b8 6 anonymous block +351fe31010 1825 package body SYS.DBMS_SQL +20befbe4d8 129 SCH_TEST.UT_EXECUTABLE +20befbe4d8 65 SCH_TEST.UT_EXECUTABLE +34f8ab7cd8 80 SCH_TEST.UT_TEST +34f8ab98f0 48 SCH_TEST.UT_SUITE_ITEM +34f8ab9b10 74 SCH_TEST.UT_SUITE +34f8ab98f0 48 SCH_TEST.UT_SUITE_ITEM +cba24bfad0 75 SCH_TEST.UT_LOGICAL_SUITE +353dfecf30 59 SCH_TEST.UT_RUN +34f8ab98f0 48 SCH_TEST.UT_SUITE_ITEM +357f5421e8 77 package body SCH_TEST.UT_RUNNER +357f5421e8 111 package body SCH_TEST.UT_RUNNER +20be951ab0 292 package body SCH_TEST.UT +20be951ab0 320 package body SCH_TEST.UT +]'; + ut.expect( + ut3_develop.ut_expectation_processor.who_called_expectation(l_stack_trace) + ).to_equal('at "'||gc_user||'.TEST_EXPECTATION_PROCESSOR", line 7 l_source_line varchar2(4000); +at "'||gc_user||'.TEST_EXPECTATION_PROCESSOR", line 12 +at "'||gc_user||'.TEST_EXPECTATION_PROCESSOR", line 24'); + end; + + + procedure who_called_expectation_0x is + l_stack_trace varchar2(4000); + l_source_line varchar2(4000); + begin + l_stack_trace := q'[----- PL/SQL Call Stack ----- + object line object + handle number name +0x80e701d8 26 UT3_DEVELOP.UT_EXPECTATION_RESULT +0x85e10150 112 UT3_DEVELOP.UT_EXPECTATION +0x8b54bad8 21 UT3_DEVELOP.UT_EXPECTATION_NUMBER +0x85cfd238 20 package body UT3_DEVELOP.UT_EXAMPLETEST +0x85def380 6 anonymous block +0x85e93750 1825 package body SYS.DBMS_SQL +0x80f4f608 129 UT3_DEVELOP.UT_EXECUTABLE +0x80f4f608 65 UT3_DEVELOP.UT_EXECUTABLE +0x8a116010 76 UT3_DEVELOP.UT_TEST +0x8a3348a0 48 UT3_DEVELOP.UT_SUITE_ITEM +0x887e9948 67 UT3_DEVELOP.UT_LOGICAL_SUITE +0x8a26de20 59 UT3_DEVELOP.UT_RUN +0x8a3348a0 48 UT3_DEVELOP.UT_SUITE_ITEM +0x838d17c0 28 anonymous block +]'; + ut.expect( + ut3_develop.ut_expectation_processor.who_called_expectation(l_stack_trace) + ).to_be_like('at "UT3_DEVELOP.UT_EXAMPLETEST", line 20 %'); + end; + + procedure who_call_expectation_win_stack is + l_stack_trace varchar2(4000); + l_source_line varchar2(4000); + begin + l_stack_trace := q'[----- PL/SQL Call Stack ----- +object line object +handle number name +00007FF8547B7D30 124 package body SCH_TEST.UT_EXPECTATION_PROCESSOR +00007FF8547B7D30 26 SCH_TEST.UT_EXPECTATION_RESULT +00007FF8547B7D30 112 SCH_TEST.UT_EXPECTATION +00007FF8547B7D30 21 SCH_TEST.UT_EXPECTATION_NUMBER +00007FF8547B7D30 7 package body SCOTT.TEST_BETWNSTR.BASIC_USAGE +00007FF81FF207B0 345 type body SCOTT.TEST_BETWNSTR.BASIC_USAGE_TYP +00007FF8544B21B8 6 anonymous block +00007FF8267FBFC8 1721 package body SYS.DBMS_SQL.EXECUTE +00007FF852BCFC68 142 type body UT3_DEVELOP.UT_EXECUTABLE.DO_EXECUTE +00007FF852BCFC68 44 type body UT3_DEVELOP.UT_EXECUTABLE.DO_EXECUTE +00007FF8512F9A90 74 type body UT3_DEVELOP.UT_EXECUTABLE_TEST.DO_EXECUTE +00007FF8512F9A90 38 type body UT3_DEVELOP.UT_EXECUTABLE_TEST.DO_EXECUTE +00007FF8231A2088 79 type body UT3_DEVELOP.UT_TEST.DO_EXECUTE +00007FF81FF207B0 49 type body UT3_DEVELOP.UT_SUITE_ITEM.DO_EXECUTE +00007FF852C83270 66 type body UT3_DEVELOP.UT_SUITE.DO_EXECUTE +00007FF82165F3B0 67 type body UT3_DEVELOP.UT_RUN.DO_EXECUTE +00007FF81FF207B0 49 type body UT3_DEVELOP.UT_SUITE_ITEM.DO_EXECUTE +00007FF8266285C0 172 package body UT3_DEVELOP.UT_RUNNER.RUN +00007FF854710538 134 package body UT3_DEVELOP.UT.RUN_AUTONOMOUS +00007FF854710538 488 package body UT3_DEVELOP.UT.RUN +00007FF854710538 623 package body UT3_DEVELOP.UT.RUN +00007FF81CFFA388 1 anonymous block]'; + ut.expect( + ut3_develop.ut_expectation_processor.who_called_expectation(l_stack_trace) + ).to_be_like('at "SCOTT.TEST_BETWNSTR.BASIC_USAGE", line 7 %'); + end; + +end; +/ diff --git a/test/ut3_tester/core/expectations/test_expectation_processor.pks b/test/ut3_tester/core/expectations/test_expectation_processor.pks new file mode 100644 index 000000000..6087eb045 --- /dev/null +++ b/test/ut3_tester/core/expectations/test_expectation_processor.pks @@ -0,0 +1,23 @@ +create or replace package test_expectation_processor is + + --%suite(expectation_processor) + --%suitepath(utplsql.ut3_tester.core.expectations) + + --%beforeall(ut3_tester_helper.main_helper.set_ut_run_context) + --%afterall(ut3_tester_helper.main_helper.clear_ut_run_context) + + --%context(who_called_expectation_in_test) + + --%test(parses stack trace containing 0x and returns objects and line that called expectation) + procedure who_called_expectation_0x; + + --%test(parses stack trace and returns objects and line that called expectation) + procedure who_called_expectation; + + --%test(parses stack trace for Windows DB os - regression for #1000) + procedure who_call_expectation_win_stack; + + --%endcontext + +end; +/ diff --git a/test/ut3_tester/core/test_file_mapper.pkb b/test/ut3_tester/core/test_file_mapper.pkb new file mode 100644 index 000000000..fccc487bd --- /dev/null +++ b/test/ut3_tester/core/test_file_mapper.pkb @@ -0,0 +1,45 @@ +create or replace package body test_file_mapper is + + procedure default_mappings is + l_actual ut3_develop.ut_file_mappings; + l_expected ut3_develop.ut_file_mappings; + begin + --Arrange + l_expected := ut3_develop.ut_file_mappings( + ut3_develop.ut_file_mapping('C:\tests\helpers\core.pkb',sys_context('USERENV', 'CURRENT_USER'),'CORE','PACKAGE BODY'), + ut3_develop.ut_file_mapping('tests/helpers/test_file_mapper.pkb',sys_context('USERENV', 'CURRENT_USER'),'TEST_FILE_MAPPER','PACKAGE BODY') + ); + --Act + l_actual := ut3_develop.ut_file_mapper.build_file_mappings( + ut3_develop.ut_varchar2_list( + 'C:\tests\helpers\core.pkb', + 'tests/helpers/test_file_mapper.pkb' + ) + ); + --Assert + ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); + end; + + procedure specific_owner is + l_actual ut3_develop.ut_file_mappings; + l_expected ut3_develop.ut_file_mappings; + begin + --Arrange + l_expected := ut3_develop.ut_file_mappings( + ut3_develop.ut_file_mapping('C:\source\core\types\ut_file_mapping.tpb','UT3_DEVELOP','UT_FILE_MAPPING','TYPE BODY'), + ut3_develop.ut_file_mapping('source/core/ut_file_mapper.pkb','UT3_DEVELOP','UT_FILE_MAPPER','PACKAGE BODY') + ); + --Act + l_actual := ut3_develop.ut_file_mapper.build_file_mappings( + 'UT3_DEVELOP', + ut3_develop.ut_varchar2_list( + 'C:\source\core\types\ut_file_mapping.tpb', + 'source/core/ut_file_mapper.pkb' + ) + ); + --Assert + ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); + end; + +end; +/ diff --git a/test/core/test_file_mapper.pks b/test/ut3_tester/core/test_file_mapper.pks similarity index 88% rename from test/core/test_file_mapper.pks rename to test/ut3_tester/core/test_file_mapper.pks index f64343637..b2443766c 100644 --- a/test/core/test_file_mapper.pks +++ b/test/ut3_tester/core/test_file_mapper.pks @@ -1,7 +1,7 @@ create or replace package test_file_mapper is --%suite(file_mapper) - --%suitepath(utplsql.core) + --%suitepath(utplsql.ut3_tester.core) --%test(Maps file paths into database objects using default mappings) procedure default_mappings; diff --git a/test/ut3_tester/core/test_output_buffer.pkb b/test/ut3_tester/core/test_output_buffer.pkb new file mode 100644 index 000000000..317e7e3d5 --- /dev/null +++ b/test/ut3_tester/core/test_output_buffer.pkb @@ -0,0 +1,200 @@ +create or replace package body test_output_buffer is + + procedure test_receive is + l_actual_text clob; + l_actual_item_type varchar2(1000); + l_remaining integer; + l_expected_text clob; + l_expected_item_type varchar2(1000); + l_buffer ut3_develop.ut_output_buffer_base; + begin + --Arrange + l_buffer := ut3_develop.ut_output_clob_table_buffer(); + l_expected_text := to_clob(lpad('a text', 31000, ',a text')) + || chr(10) || to_clob(lpad('a text', 31000, ',a text')) + || chr(13) || to_clob(lpad('a text', 31000, ',a text')) + || chr(13) || chr(10) || to_clob(lpad('a text', 31000, ',a text')) || to_clob(lpad('a text', 31000, ',a text')); + l_expected_item_type := lpad('some item type',1000,'-'); + --Act + l_buffer.lock_buffer(); + l_buffer.send_clob(l_expected_text, l_expected_item_type); + l_buffer.close(); + + select text, item_type + into l_actual_text, l_actual_item_type + from table(l_buffer.get_lines(0.1,0.1)); + + --Assert + ut.expect(l_actual_text).to_equal(l_expected_text); + ut.expect(l_actual_item_type).to_equal(l_expected_item_type); + + select count(1) into l_remaining from table(ut3_tester_helper.run_helper.ut_output_buffer_tmp) + where output_id = l_buffer.output_id; + + ut.expect(l_remaining).to_equal(0); + end; + + procedure test_wait_for_producer is + l_buffer ut3_develop.ut_output_buffer_base; + begin + l_buffer := ut3_develop.ut_output_clob_table_buffer(); + ut.expect( l_buffer.get_lines_cursor(0.1) ).to_be_empty(); + end; + + procedure test_doesnt_send_on_null_text is + l_cur sys_refcursor; + l_result integer; + l_buffer ut3_develop.ut_output_buffer_base := ut3_develop.ut_output_table_buffer(); + begin + ut3_tester_helper.run_helper.delete_buffer(); + --Act + l_buffer.send_line(null); + + open l_cur for select * from table(ut3_tester_helper.run_helper.ut_output_buffer_tmp); + ut.expect(l_cur).to_be_empty; + end; + + + procedure test_doesnt_send_on_null_elem is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_buffer ut3_develop.ut_output_buffer_base := ut3_develop.ut_output_table_buffer(); + l_message_id varchar2(255); + l_text varchar2(4000); + begin + ut3_tester_helper.run_helper.delete_buffer(); + --Act + l_buffer.send_lines(ut3_develop.ut_varchar2_rows(null)); + l_buffer.send_lines(ut3_develop.ut_varchar2_rows('test')); + + open l_actual for + select text from table(ut3_tester_helper.run_helper.ut_output_buffer_tmp); + open l_expected for + select 'test' as text from dual; + + ut.expect(l_actual).to_equal(l_expected); + end; + + procedure test_send_line is + l_result varchar2(4000); + c_expected constant varchar2(4000) := lpad('a text',4000,',a text'); + l_buffer ut3_develop.ut_output_buffer_base := ut3_develop.ut_output_table_buffer(); + begin + l_buffer.send_line(c_expected); + + select text into l_result from table(ut3_tester_helper.run_helper.ut_output_buffer_tmp) where output_id = l_buffer.output_id; + + ut.expect(l_result).to_equal(c_expected); + end; + + procedure test_waiting_for_data is + l_result clob; + l_remaining integer; + l_expected clob; + l_buffer ut3_develop.ut_output_buffer_base := ut3_develop.ut_output_table_buffer(); + l_start timestamp; + l_duration interval day to second; + begin + --Arrange + l_expected := 'a text'; + l_buffer.lock_buffer(); + l_buffer.send_line(l_expected); + l_start := localtimestamp; + --Act + begin + select text into l_result from table(l_buffer.get_lines(0,0.3)); + ut.fail('Expected a timeout exception but nothing was raised'); + exception + when others then + l_duration := localtimestamp - l_start; + --Assert + --Fetches data from output + ut.expect(l_result).to_equal(l_expected); + --Throws a timeout exception + ut.expect(dbms_utility.format_error_stack()).to_match('ORA'||ut3_develop.ut_utils.gc_out_buffer_timeout); + --Waited for one second + ut.expect(l_duration).to_be_greater_or_equal(interval '0.3' second); + end; + + select count(1) into l_remaining from table(ut3_tester_helper.run_helper.ut_output_buffer_tmp) where output_id = l_buffer.output_id; + --Data got removed from output buffer + ut.expect(l_remaining).to_equal(0); + + end; + + procedure test_purge(a_buffer ut3_develop.ut_output_buffer_base ) is + l_stale_buffer ut3_develop.ut_output_buffer_base := a_buffer; + l_fresh_buffer ut3_develop.ut_output_buffer_base; + l_buffer ut3_develop.ut_output_buffer_base; + begin + --Arrange + l_stale_buffer.start_date := sysdate - 10; + --initialize with new start date + l_stale_buffer.init(); + l_stale_buffer.lock_buffer(); + l_stale_buffer.send_line('some text'); + l_stale_buffer.close(); + + l_fresh_buffer := ut3_develop.ut_output_table_buffer(); + l_fresh_buffer.lock_buffer(); + l_fresh_buffer.send_line('some text'); + l_fresh_buffer.close(); + + --Act - purge is performed on new buffer create + l_buffer := ut3_develop.ut_output_table_buffer(); + + --Assert + -- Data in "fresh" buffer remains + ut.expect( l_fresh_buffer.get_lines_cursor(0,0), l_fresh_buffer.self_type ).to_have_count(1); + -- Data in "stale" buffer is purged and so the call to get_lines_cursor throws ORA-20218 + ut.expect( l_stale_buffer.get_lines_cursor(0,0), l_stale_buffer.self_type ).to_be_empty(); + end; + + procedure test_purge_text_buffer is + begin + test_purge(ut3_develop.ut_output_table_buffer()); + end; + + procedure test_purge_clob_buffer is + begin + test_purge(ut3_develop.ut_output_clob_table_buffer()); + end; + + procedure text_buffer_send_multibyte is + l_input varchar2(32767); + l_max_len integer := ut3_develop.ut_utils.gc_max_storage_varchar2_len; + l_buffer ut3_develop.ut_output_buffer_base := ut3_develop.ut_output_table_buffer(); + l_text varchar2(4000); + begin + --Arrange + ut3_tester_helper.run_helper.delete_buffer(); + l_input := rpad( '❤', l_max_len, 'a' ); + ut.expect( lengthb( l_input ) ).to_be_greater_than(l_max_len); + + --Act + l_buffer.send_line(l_input); + --Assert + select text into l_text from table(ut3_tester_helper.run_helper.ut_output_buffer_tmp); + ut.expect(lengthb(l_text)).to_be_less_or_equal(l_max_len); + end; + + procedure text_buffer_send_clob_multib is + l_input clob; + l_max_len integer := ut3_develop.ut_utils.gc_max_storage_varchar2_len; + l_buffer ut3_develop.ut_output_buffer_base := ut3_develop.ut_output_table_buffer(); + l_text varchar2(4000); + begin + --Arrange + ut3_tester_helper.run_helper.delete_buffer(); + l_input := rpad( '❤', l_max_len, 'a' ); + ut.expect( ut3_develop.ut_utils.lengthb_clob( l_input ) ).to_be_greater_than(l_max_len); + + --Act + l_buffer.send_clob(l_input); + --Assert + select text into l_text from table(ut3_tester_helper.run_helper.ut_output_buffer_tmp); + ut.expect(lengthb(l_text)).to_be_less_or_equal(l_max_len); + end; + + end test_output_buffer; +/ diff --git a/test/ut3_tester/core/test_output_buffer.pks b/test/ut3_tester/core/test_output_buffer.pks new file mode 100644 index 000000000..5b6cd678b --- /dev/null +++ b/test/ut3_tester/core/test_output_buffer.pks @@ -0,0 +1,57 @@ +create or replace package test_output_buffer is + + --%suite(output_buffer) + --%suitepath(utplsql.ut3_tester.core) + + + --%context(Read and write within the same session) + + + --%endcontext + + --%context(Buffer is read in a different session than buffer write) + + --reader will wait for a_initial_timeout seconds for the writer process to start and then it will finish with error + + --reader will wait forever (beyond a_initial_timeout) if the writer process is started and end of data row was not received from the buffer + + --reader stops after reading the end of data signal from the buffer + + --reader stops when writer process ends and all data was read from the buffer + + + --%endcontext + + --%test(Receives a line from buffer table and deletes) + procedure test_receive; + + --%test(Waits specified time for producer to lock the buffer ) + --%throws(-20218) + procedure test_wait_for_producer; + + --%test(Does not send line if null text given) + procedure test_doesnt_send_on_null_text; + + --%test(Does not send line if null text given for multiline case) + procedure test_doesnt_send_on_null_elem; + + --%test(Sends a line into buffer table) + procedure test_send_line; + + --%test(Waits For The Data To Appear For Specified Time) + procedure test_waiting_for_data; + + --%test(Purges text buffer data older than one day and leaves the rest) + procedure test_purge_text_buffer; + + --%test(Purges clob buffer data older than one day and leaves the rest) + procedure test_purge_clob_buffer; + + --%test(Successfully sends multibyte long line into text buffer) + procedure text_buffer_send_multibyte; + + --%test(Successfully sends multibyte long clob line into text buffer) + procedure text_buffer_send_clob_multib; + +end test_output_buffer; +/ diff --git a/test/ut3_tester/core/test_suite_builder.pkb b/test/ut3_tester/core/test_suite_builder.pkb new file mode 100644 index 000000000..570d86a0d --- /dev/null +++ b/test/ut3_tester/core/test_suite_builder.pkb @@ -0,0 +1,1925 @@ +create or replace package body test_suite_builder is + + function invoke_builder_for_annotations( + a_annotations ut3_develop.ut_annotations, + a_package_name varchar2 := 'TEST_SUITE_BUILDER_PACKAGE' + ) return clob is + l_suites ut3_develop.ut_suite_items; + l_suite ut3_develop.ut_logical_suite; + l_cursor sys_refcursor; + l_type_cursor sys_refcursor; + l_ctx dbms_xmlgen.ctxhandle; + l_xml xmltype; + begin + open l_cursor for select value(x) from table( + ut3_develop.ut_annotated_objects( + ut3_develop.ut_annotated_object('UT3_TESTER', a_package_name, 'PACKAGE', systimestamp, a_annotations) + ) ) x; + + l_suites := ut3_develop.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_develop.ut_logical_suite); + + open l_type_cursor for select l_suite as "UT_LOGICAL_SUITE" from dual; + l_ctx := dbms_xmlgen.newcontext(l_type_cursor); + dbms_xmlgen.setNullHandling(l_ctx, dbms_xmlgen.empty_tag); + l_xml := dbms_xmlgen.getxmltype(l_ctx); + + select deletexml( + l_xml, + '//RESULTS_COUNT|//START_TIME|//END_TIME|//RESULT|//ASSOCIATED_EVENT_NAME' || + '|//TRANSACTION_INVALIDATORS|//ERROR_BACKTRACE|//ERROR_STACK|//SERVEROUTPUT' + ) + into l_xml + from dual; + + return l_xml.getClobVal(); + end; + + procedure no_suite_description is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite',null, null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_match( + 'UT3_TESTERsome_packagesome_package()?\s*some_package' + ); + end; + + procedure suite_description_from_suite is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Some description', null), + ut3_develop.ut_annotation(2, 'suite','Another description', null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%some_packageSome description%' + ); + end; + + procedure suitepath_from_non_empty_path is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite',null, null), + ut3_develop.ut_annotation(2, 'suitepath','org.utplsql.some', null), + ut3_develop.ut_annotation(3, 'suitepath','dummy.utplsql.some', null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%org.utplsql.some%' + ); + end; + + procedure suite_descr_from_displayname is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Some description', null), + ut3_develop.ut_annotation(2, 'suite','Another description', null), + ut3_develop.ut_annotation(3, 'displayname','New description', null), + ut3_develop.ut_annotation(4, 'displayname','Newest description', null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%some_packageNew description%' + ); + end; + + procedure rollback_type_valid is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite',null, null), + ut3_develop.ut_annotation(2, 'rollback','manual', null), + ut3_develop.ut_annotation(3, 'rollback','bad', null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%'||ut3_develop.ut_utils.gc_rollback_manual||'%' + ); + end; + + procedure rollback_type_duplicated is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite',null, null), + ut3_develop.ut_annotation(2, 'rollback','manual', null), + ut3_develop.ut_annotation(3, 'rollback','bad', null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%"--%rollback"%%UT3_TESTER.SOME_PACKAGE%3%%' + ); + end; + + procedure suite_annot_duplicated is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','Cool', null), + ut3_develop.ut_annotation(8, 'suite','bad', null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%Cool%%"--%suite"%UT3_TESTER.SOME_PACKAGE%line 8%%' + ); + end; + + procedure test_annotation is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','Cool', null), + ut3_develop.ut_annotation(8, 'test','Some test', 'test_procedure') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%' || + '%test_procedureSome testsome_package.test_procedure' || + '%%' + ); + end; + + procedure test_annot_duplicated is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','Cool', null), + ut3_develop.ut_annotation(8, 'test','Some test', 'test_procedure'), + ut3_develop.ut_annotation(9, 'test','Dup', 'test_procedure') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%Cool%%"--%test"%UT3_TESTER.SOME_PACKAGE.TEST_PROCEDURE%line 9%%' + ); + end; + + procedure beforeall_annot_duplicated is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','Cool', null), + ut3_develop.ut_annotation(8, 'beforeall', null, 'test_procedure'), + ut3_develop.ut_annotation(9, 'beforeall', null, 'test_procedure') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%Cool%%"--%beforeall"%UT3_TESTER.SOME_PACKAGE.TEST_PROCEDURE%line 9%%' + ); + end; + + procedure beforeeach_annot_duplicated is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','Cool', null), + ut3_develop.ut_annotation(8, 'beforeeach', null, 'test_procedure'), + ut3_develop.ut_annotation(9, 'beforeeach', null, 'test_procedure') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%Cool%%"--%beforeeach"%UT3_TESTER.SOME_PACKAGE.TEST_PROCEDURE%line 9%%' + ); + end; + + procedure afterall_annot_duplicated is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','Cool', null), + ut3_develop.ut_annotation(8, 'afterall', null, 'test_procedure'), + ut3_develop.ut_annotation(9, 'afterall', null, 'test_procedure') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%Cool%%"--%afterall"%UT3_TESTER.SOME_PACKAGE.TEST_PROCEDURE%line 9%%' + ); + end; + + procedure aftereach_annot_duplicated is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','Cool', null), + ut3_develop.ut_annotation(8, 'aftereach', null, 'test_procedure'), + ut3_develop.ut_annotation(9, 'aftereach', null, 'test_procedure') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%Cool%%"--%aftereach"%UT3_TESTER.SOME_PACKAGE.TEST_PROCEDURE%line 9%%' + ); + end; + + procedure suitepath_annot_duplicated is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','Cool', null), + ut3_develop.ut_annotation(3, 'suitepath','dummy.utplsql.some', null), + ut3_develop.ut_annotation(4, 'suitepath','org.utplsql.some', null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%"--%suitepath"%line 4%%' + ); + end; + + procedure displayname_annot_duplicated is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','Cool', null), + ut3_develop.ut_annotation(4, 'displayname','New description', null), + ut3_develop.ut_annotation(5, 'displayname','Newest description', null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%"--%displayname"%line 5%%' + ); + end; + + procedure suitepath_annot_empty is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(3, 'suitepath',null, null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%"--%suitepath" annotation requires a non-empty parameter value.%%' + ); + end; + + procedure suitepath_annot_invalid_path is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(2, 'suitepath','path with spaces', null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%Invalid path value in annotation "--%suitepath(path with spaces)"%%' + ); + end; + + procedure displayname_annot_empty is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(3, 'displayname',null, null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%"--%displayname" annotation requires a non-empty parameter value.%%' + ); + end; + + procedure rollback_type_empty is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(3, 'rollback',null, null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%"--%rollback" annotation requires one of values as parameter:%%' + ); + end; + + procedure rollback_type_invalid is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(2, 'rollback','bad', null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%"--%rollback" annotation requires one of values as parameter: "auto" or "manual". Annotation ignored.%%' + ); + end; + + procedure multiple_before_after is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(2, 'beforeall',null, 'first_before_all'), + ut3_develop.ut_annotation(3, 'beforeall',null, 'another_before_all'), + ut3_develop.ut_annotation(4, 'beforeeach',null, 'first_before_each'), + ut3_develop.ut_annotation(5, 'beforeeach',null, 'another_before_each'), + ut3_develop.ut_annotation(6, 'aftereach',null, 'first_after_each'), + ut3_develop.ut_annotation(7, 'aftereach',null, 'another_after_each'), + ut3_develop.ut_annotation(8, 'afterall',null, 'first_after_all'), + ut3_develop.ut_annotation(9, 'afterall',null, 'another_after_all'), + ut3_develop.ut_annotation(14, 'test','A test', 'some_test'), + ut3_develop.ut_annotation(15, 'beforetest','before_test_proc', 'some_test'), + ut3_develop.ut_annotation(16, 'beforetest','before_test_proc2', 'some_test'), + ut3_develop.ut_annotation(18, 'aftertest','after_test_proc', 'some_test'), + ut3_develop.ut_annotation(20, 'aftertest','after_test_proc2', 'some_test') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%some_package%some_test' || + '%' || + '%some_packagefirst_before_each' || + '%some_packageanother_before_each' || + '%' || + '%' || + '%some_packagebefore_test_proc' || + '%some_packagebefore_test_proc2' || + '%' || + '%' || + '%some_packageafter_test_proc' || + '%some_packageafter_test_proc2' || + '%' || + '%' || + '%some_packagefirst_after_each' || + '%some_packageanother_after_each' || + '%' || + '%' || + '%' || + '%some_packagefirst_before_all' || + '%some_packageanother_before_all' || + '%' || + '%' || + '%some_packagefirst_after_all' || + '%some_packageanother_after_all' || + '%%' + ); + end; + + procedure multiple_standalone_bef_aft is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(2, 'beforeall', 'some_package.first_before_all',null), + ut3_develop.ut_annotation(3, 'beforeall', 'different_package.another_before_all',null), + ut3_develop.ut_annotation(4, 'beforeeach', 'first_before_each',null), + ut3_develop.ut_annotation(5, 'beforeeach', 'different_owner.different_package.another_before_each',null), + ut3_develop.ut_annotation(6, 'aftereach', 'first_after_each',null), + ut3_develop.ut_annotation(7, 'aftereach', 'another_after_each,different_owner.different_package.one_more_after_each',null), + ut3_develop.ut_annotation(8, 'afterall', 'first_after_all',null), + ut3_develop.ut_annotation(9, 'afterall', 'another_after_all',null), + ut3_develop.ut_annotation(14, 'test','A test', 'some_test'), + ut3_develop.ut_annotation(15, 'beforetest','before_test_proc', 'some_test'), + ut3_develop.ut_annotation(16, 'beforetest','before_test_proc2', 'some_test'), + ut3_develop.ut_annotation(18, 'aftertest','after_test_proc', 'some_test'), + ut3_develop.ut_annotation(20, 'aftertest','after_test_proc2', 'some_test') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%some_package%some_test' || + '%' || + '%some_packagefirst_before_each' || + '%different_ownerdifferent_packageanother_before_each' || + '%' || + '%' || + '%some_packagebefore_test_proc' || + '%some_packagebefore_test_proc2' || + '%' || + '%' || + '%some_packageafter_test_proc' || + '%some_packageafter_test_proc2' || + '%' || + '%' || + '%some_packagefirst_after_each' || + '%some_packageanother_after_each' || + '%different_ownerdifferent_packageone_more_after_each' || + '%' || + '%' || + '%' || + '%some_packagefirst_before_all' || + '%different_packageanother_before_all' || + '%' || + '%' || + '%some_packagefirst_after_all' || + '%some_packageanother_after_all' || + '%%' + ); + end; + + procedure before_after_on_single_proc is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(2, 'beforeall',null, 'do_stuff'), + ut3_develop.ut_annotation(3, 'beforeeach',null, 'do_stuff'), + ut3_develop.ut_annotation(4, 'aftereach',null, 'do_stuff'), + ut3_develop.ut_annotation(5, 'afterall',null, 'do_stuff'), + ut3_develop.ut_annotation(6, 'test','A test', 'some_test') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%some_package%some_test' || + '%' || + '%some_packagedo_stuff' || + '%' || + '%' || + '%some_packagedo_stuff' || + '%' || + '%' || + '%' || + '%some_packagedo_stuff' || + '%' || + '%' || + '%some_packagedo_stuff' || + '%%' + ); + end; + + procedure multiple_mixed_bef_aft is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(2, 'beforeall', null,'first_before_all'), + ut3_develop.ut_annotation(3, 'beforeall', 'different_package.another_before_all',null), + ut3_develop.ut_annotation(4, 'beforeeach', 'first_before_each',null), + ut3_develop.ut_annotation(5, 'beforeeach', 'different_owner.different_package.another_before_each',null), + ut3_develop.ut_annotation(6, 'aftereach', null, 'first_after_each'), + ut3_develop.ut_annotation(7, 'aftereach', 'another_after_each,different_owner.different_package.one_more_after_each',null), + ut3_develop.ut_annotation(8, 'afterall', 'first_after_all',null), + ut3_develop.ut_annotation(9, 'afterall', 'another_after_all',null), + ut3_develop.ut_annotation(14, 'test','A test', 'some_test'), + ut3_develop.ut_annotation(15, 'beforetest','before_test_proc', 'some_test'), + ut3_develop.ut_annotation(16, 'beforetest','before_test_proc2', 'some_test'), + ut3_develop.ut_annotation(18, 'aftertest','after_test_proc', 'some_test'), + ut3_develop.ut_annotation(20, 'aftertest','after_test_proc2', 'some_test'), + ut3_develop.ut_annotation(21, 'beforeall', null,'last_before_all'), + ut3_develop.ut_annotation(22, 'aftereach', null, 'last_after_each'), + ut3_develop.ut_annotation(23, 'afterall', null, 'last_after_all') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%some_package%some_test' || + '%' || + '%some_packagefirst_before_each' || + '%different_ownerdifferent_packageanother_before_each' || + '%' || + '%' || + '%some_packagebefore_test_proc' || + '%some_packagebefore_test_proc2' || + '%' || + '%' || + '%some_packageafter_test_proc' || + '%some_packageafter_test_proc2' || + '%' || + '%' || + '%some_packagefirst_after_each' || + '%some_packageanother_after_each' || + '%different_ownerdifferent_packageone_more_after_each' || + '%some_packagelast_after_each' || + '%' || + '%' || + '%' || + '%some_packagefirst_before_all' || + '%different_packageanother_before_all' || + '%some_packagelast_before_all' || + '%' || + '%' || + '%some_packagefirst_after_all' || + '%some_packageanother_after_all' || + '%some_packagelast_after_all' || + '%%' + ); + end; + + + procedure before_after_mixed_with_test is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(2, 'beforeall',null, 'do_stuff'), + ut3_develop.ut_annotation(3, 'beforeeach',null, 'do_stuff'), + ut3_develop.ut_annotation(4, 'aftereach',null, 'do_stuff'), + ut3_develop.ut_annotation(5, 'afterall',null, 'do_stuff'), + ut3_develop.ut_annotation(6, 'test','A test', 'do_stuff') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_match('(.*)()(.*)(Annotation "--%beforeall")(.*)(line 2)(.*)()(.*)', 'n'); + ut.expect(l_actual).to_match('(.*)()(.*)(Annotation "--%beforeeach")(.*)(line 3)(.*)()(.*)', 'n'); + ut.expect(l_actual).to_match('(.*)()(.*)(Annotation "--%aftereach")(.*)(line 4)(.*)()(.*)', 'n'); + ut.expect(l_actual).to_match('(.*)()(.*)(Annotation "--%afterall" cannot be used with "--%test". Annotation ignored.)' + ||'(.*)(at package "UT3_TESTER.SOME_PACKAGE.DO_STUFF", line 5)(.*)()(.*)', 'n'); + ut.expect(l_actual).not_to_be_like('%%'); + ut.expect(l_actual).not_to_be_like('%%'); + ut.expect(l_actual).not_to_be_like('%%'); + ut.expect(l_actual).not_to_be_like('%%'); + end; + + procedure suite_from_context is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(2, 'beforeall',null, 'suite_level_beforeall'), + ut3_develop.ut_annotation(3, 'test','In suite', 'suite_level_test'), + ut3_develop.ut_annotation(4, 'context','A context', null), + ut3_develop.ut_annotation(5, 'name','a_context', null), + ut3_develop.ut_annotation(6, 'beforeall',null, 'context_setup'), + ut3_develop.ut_annotation(7, 'test', 'In context', 'test_in_a_context'), + ut3_develop.ut_annotation(8, 'endcontext',null, null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + ''|| + '' || + '%' || + '%' || + '' || + '%suite_level_testIn suitesome_package.suite_level_test' || + '%' || + '' || + '%a_contextA contextsome_package.a_context' || + '%' || + '' || + '%test_in_a_contextIn contextsome_package.a_context.test_in_a_context' || + '%' || + '' || + '' || + '%some_packagecontext_setup' || + '%' || + '' || + '' || + '' || + '' || + '%some_packagesuite_level_beforeall' || + '%' || + '' || + ''|| + '' + ); + end; + + procedure nested_contexts is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation( 1, 'suite','Cool', null), + ut3_develop.ut_annotation( 2, 'beforeall',null, 'suite_level_beforeall'), + ut3_develop.ut_annotation( 3, 'test','In suite', 'suite_level_test'), + ut3_develop.ut_annotation( 4, 'context','A context', null), + ut3_develop.ut_annotation( 5, 'name','a_context', null), + ut3_develop.ut_annotation( 6, 'beforeall',null, 'context_setup'), + ut3_develop.ut_annotation( 7, 'test', 'First test in context', 'first_test_in_a_context'), + ut3_develop.ut_annotation( 8, 'context','A nested context', null), + ut3_develop.ut_annotation( 9, 'name','a_nested_context', null), + ut3_develop.ut_annotation(10, 'beforeall',null, 'nested_context_setup'), + ut3_develop.ut_annotation(11, 'test', 'Test in nested context', 'test_in_nested_context'), + ut3_develop.ut_annotation(12, 'endcontext',null, null), + ut3_develop.ut_annotation(13, 'context',null, null), + ut3_develop.ut_annotation(14, 'name','nested_context_2', null), + ut3_develop.ut_annotation(15, 'test', 'Test in nested context', 'test_in_nested_context_2'), + ut3_develop.ut_annotation(16, 'context','a_nested_context_3', null), + ut3_develop.ut_annotation(17, 'test', 'Test in nested context', 'test_in_nested_context_3'), + ut3_develop.ut_annotation(18, 'endcontext',null, null), + ut3_develop.ut_annotation(19, 'endcontext',null, null), + ut3_develop.ut_annotation(20, 'test', 'Second test in context', 'second_test_in_a_context'), + ut3_develop.ut_annotation(21, 'endcontext',null, null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + ''|| + '' || + '%' || + '%' || + '' || + '%suite_level_testIn suitesome_package.suite_level_test' || + '%' || + '' || + '%a_contextA contextsome_package.a_context' || + '%' || + '' || + '%first_test_in_a_contextFirst test in contextsome_package.a_context.first_test_in_a_context' || + '%' || + '' || + '%a_nested_contextA nested contextsome_package.a_context.a_nested_context' || + '%' || + '' || + '%test_in_nested_contextTest in nested contextsome_package.a_context.a_nested_context.test_in_nested_context' || + '%' || + '' || + '' || + '%some_packagenested_context_setup' || + '%' || + '%' || + '' || + '%nested_context_2nested_context_2some_package.a_context.nested_context_2' || + '%' || + '' || + '%test_in_nested_context_2Test in nested contextsome_package.a_context.nested_context_2.test_in_nested_context_2' || + '%' || + '' || + '%nested_context_#1a_nested_context_3some_package.a_context.nested_context_2.nested_context_#1' || + '%' || + '' || + '%test_in_nested_context_3Test in nested contextsome_package.a_context.nested_context_2.nested_context_#1.test_in_nested_context_3' || + '%' || + '' || + '' || + '%' || + '' || + '' || + '%' || + '' || + '%second_test_in_a_contextSecond test in contextsome_package.a_context.second_test_in_a_context' || + '%' || + '' || + '' || + '%some_packagecontext_setup' || + '%' || + '' || + '' || + '' || + '' || + '%some_packagesuite_level_beforeall' || + '%' || + '' || + ''|| + '' + ); + end; + + procedure nested_contexts_2 is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation( 1, 'suite','Cool', null), + ut3_develop.ut_annotation( 2, 'suitepath','path', null), + ut3_develop.ut_annotation( 3, 'context','Level 1', null), + ut3_develop.ut_annotation( 4, 'name','context_1', null), + ut3_develop.ut_annotation( 5, 'context','Level 1.1', null), + ut3_develop.ut_annotation( 6, 'name','context_1_1', null), + ut3_develop.ut_annotation( 7, 'test', 'Test 1.1.1', 'test_1_1_1'), + ut3_develop.ut_annotation( 8, 'test', 'Test 1.1.2', 'test_1_1_2'), + ut3_develop.ut_annotation( 9, 'endcontext', null, null), + ut3_develop.ut_annotation(10, 'endcontext', null, null), + ut3_develop.ut_annotation(11, 'context','Level 2', null), + ut3_develop.ut_annotation(12, 'name','context_2', null), + ut3_develop.ut_annotation(13, 'test', 'Test 2.1', 'test_2_1'), + ut3_develop.ut_annotation(14, 'endcontext',null, null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + ''|| + '' || + '%%' || + '' || + '%context_1Level 1path.some_package.context_1' || + '%' || + '' || + '%context_1_1Level 1.1path.some_package.context_1.context_1_1' || + '%' || + '' || + '%test_1_1_1Test 1.1.1path.some_package.context_1.context_1_1.test_1_1_1' || + '%' || + '' || + '%test_1_1_2Test 1.1.2path.some_package.context_1.context_1_1.test_1_1_2' || + '%' || + '' || + '%' || + '%' || + '' || + '%' || + '%' || + '%'|| + '' + ); + -- Test both contexts separately due to ordering + ut.expect(l_actual).to_be_like( + ''|| + '' || + '%%' || + '' || + '%context_2Level 2path.some_package.context_2' || + '%' || + '' || + '%test_2_1Test 2.1path.some_package.context_2.test_2_1' || + '%' || + '%' || + '%' || + '%' || + '%'|| + '' + ); + end; + + + procedure before_after_in_context is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite', 'Cool', null), + ut3_develop.ut_annotation(2, 'test', 'In suite', 'suite_level_test'), + ut3_develop.ut_annotation(3, 'context', 'A context', null), + ut3_develop.ut_annotation(4, 'beforeall', 'context_beforeall', null), + ut3_develop.ut_annotation(5, 'beforeeach', null, 'context_beforeeach'), + ut3_develop.ut_annotation(6, 'test', 'In context', 'test_in_a_context'), + ut3_develop.ut_annotation(7, 'aftereach', 'context_aftereach' ,null), + ut3_develop.ut_annotation(8, 'afterall', null, 'context_afterall'), + ut3_develop.ut_annotation(9, 'endcontext', null, null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + ''|| + '' || + '%' || + '%' || + '%suite_level_test' || + '%%suite_level_test%' || + '%' || + '%' || + '%nested_context_#1A contextsome_package.nested_context_#1' || + '%' || + '%' || + '%test_in_a_context' || + '%%context_beforeeach%' || + '%%test_in_a_context%' || + '%%context_aftereach%' || + '%' || + '%' || + '%%context_beforeall%' || + '%%context_afterall%' || + '%' || + '%' || + '%'|| + '' + ); + ut.expect(l_actual).not_to_be_like('%%%%%%'); + ut.expect(l_actual).not_to_be_like('%%%%%%'); + ut.expect(l_actual).not_to_be_like('%%%%%%'); + ut.expect(l_actual).not_to_be_like('%%%%%%'); + end; + + procedure before_after_out_of_context is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(2, 'beforeall',null, 'suite_level_beforeall'), + ut3_develop.ut_annotation(3, 'beforeeach',null, 'suite_level_beforeeach'), + ut3_develop.ut_annotation(4, 'test','In suite', 'suite_level_test'), + ut3_develop.ut_annotation(5, 'context',null, null), + ut3_develop.ut_annotation(6, 'test', 'In context', 'test_in_a_context'), + ut3_develop.ut_annotation(7, 'endcontext',null, null), + ut3_develop.ut_annotation(8, 'aftereach',null, 'suite_level_aftereach'), + ut3_develop.ut_annotation(9, 'afterall',null, 'suite_level_afterall') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + ''|| + '' || + '%' || + '%' || + '%suite_level_test' || + '%%suite_level_beforeeach%' || + '%%suite_level_test%' || + '%%suite_level_aftereach%' || + '%' || + '%' || + '%nested_context_#1nested_context_#1some_package.nested_context_#1' || + '%' || + '%' || + '%test_in_a_context' || + '%%suite_level_beforeeach%' || + '%%test_in_a_context%' || + '%%suite_level_aftereach%' || + '%' || + '%' || + '%' || + '%' || + '%%suite_level_beforeall%' || + '%%suite_level_afterall%' || + '%'|| + '' + ); + ut.expect(l_actual).not_to_be_like('%%%%%%'); + ut.expect(l_actual).not_to_be_like('%%%%%%'); + end; + + procedure context_without_endcontext is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(2, 'beforeall',null, 'suite_level_beforeall'), + ut3_develop.ut_annotation(3, 'test','In suite', 'suite_level_test'), + ut3_develop.ut_annotation(4, 'context','Some context', null), + ut3_develop.ut_annotation(5, 'name','a_context', null), + ut3_develop.ut_annotation(6, 'beforeall',null, 'context_setup'), + ut3_develop.ut_annotation(7, 'test', 'In context', 'test_in_a_context') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%Missing "--\%endcontext" annotation for a "--\%context" annotation. The end of package is considered end of context.%at package "UT3_TESTER.SOME_PACKAGE", line 4%' + ,'\' + ); + ut.expect(l_actual).to_be_like( + ''|| + '' || + '%' || + '%' || + '%suite_level_testIn suitesome_package.suite_level_test' || + '%' || + '%' || + '%a_contextSome contextsome_package.a_context' || + '%' || + '' || + '%test_in_a_contextIn contextsome_package.a_context.test_in_a_context' || + '%' || + '' || + '' || + '%some_packagecontext_setup' || + '%' || + '%' || + '' || + '' || + '%some_packagesuite_level_beforeall' || + '%' || + '' || + ''|| + '' + ); + end; + + procedure endcontext_without_context is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(2, 'beforeall',null, 'suite_level_beforeall'), + ut3_develop.ut_annotation(3, 'test','In suite', 'suite_level_test'), + ut3_develop.ut_annotation(4, 'context','A context', null), + ut3_develop.ut_annotation(5, 'name','a_context', null), + ut3_develop.ut_annotation(6, 'beforeall',null, 'context_setup'), + ut3_develop.ut_annotation(7, 'test', 'In context', 'test_in_a_context'), + ut3_develop.ut_annotation(8, 'endcontext',null, null), + ut3_develop.ut_annotation(9, 'endcontext',null, null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%Extra "--\%endcontext" annotation found. Cannot find corresponding "--\%context". Annotation ignored.%at package "UT3_TESTER.SOME_PACKAGE", line 9%' + ,'\' + ); + ut.expect(l_actual).to_be_like( + ''|| + '' || + '%' || + '' || + '%suite_level_testIn suitesome_package.suite_level_test' || + '%' || + '' || + '%a_contextA contextsome_package.a_context' || + '%' || + '' || + '%test_in_a_contextIn contextsome_package.a_context.test_in_a_context' || + '%' || + '' || + '' || + '%some_packagecontext_setup' || + '%' || + '' || + '' || + '' || + '' || + '%some_packagesuite_level_beforeall' || + '%' || + '' || + ''|| + '' + ); + end; + + procedure duplicate_context_name is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(2, 'beforeall',null, 'suite_level_beforeall'), + ut3_develop.ut_annotation(3, 'test','In suite', 'suite_level_test'), + ut3_develop.ut_annotation(4, 'context','A context', null), + ut3_develop.ut_annotation(5, 'name','a_context', null), + ut3_develop.ut_annotation(6, 'beforeall',null, 'context_setup'), + ut3_develop.ut_annotation(7, 'test', 'In context', 'test_in_a_context'), + ut3_develop.ut_annotation(8, 'endcontext',null, null), + ut3_develop.ut_annotation(9, 'context','A context', null), + ut3_develop.ut_annotation(10, 'name','a_context', null), + ut3_develop.ut_annotation(11, 'beforeall',null, 'setup_in_duplicated_context'), + ut3_develop.ut_annotation(12, 'test', 'In duplicated context', 'test_in_duplicated_context'), + ut3_develop.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 "a_context" already used in this scope. Name must be unique. Using fallback name nested_context_#2.%%' + ,'\' + ); + ut.expect(l_actual).to_be_like( + ''|| + '' || + '%' || + '' || + '%suite_level_testIn suitesome_package.suite_level_test' || + '%' || + '' || + '%a_contextA contextsome_package.a_context' || + '%' || + '' || + '%test_in_a_contextIn contextsome_package.a_context.test_in_a_context' || + '%' || + '' || + '' || + '%some_packagecontext_setup' || + '%' || + '' || + '' || + '' || + '%nested_context_#2A contextsome_package.nested_context_#2' || + '%' || + '' || + '%test_in_duplicated_contextIn duplicated contextsome_package.nested_context_#2.test_in_duplicated_context' || + '%' || + '' || + '' || + '%some_packagesetup_in_duplicated_context' || + '%' || + '' || + '' || + '' || + '' || + '%some_packagesuite_level_beforeall' || + '%' || + '' || + ''|| + '' + ); + end; + + procedure hard_stop_in_ctx_name is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + l_bad_name varchar2(100); + begin + --Arrange + l_bad_name := 'ctx_with_dot.in_it'; + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(4, 'context',null, null), + ut3_develop.ut_annotation(5, 'name',l_bad_name, null), + ut3_develop.ut_annotation(7, 'test', 'In context', 'test_in_a_context'), + ut3_develop.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( + '%Invalid value "'||l_bad_name||'" for context name. Context name ignored and fallback to auto-name "nested_context_#1"%' + ); + ut.expect(l_actual).to_be_like( + ''|| + '' || + '%' || + '' || + '%nested_context_#1nested_context_#1some_package.nested_context_#1' || + '%' || + '' || + '%test_in_a_contextIn contextsome_package.nested_context_#1.test_in_a_context' || + '%' || + '%' || + '%' || + '%' || + ''|| + '' + ); + end; + + procedure name_with_spaces_invalid is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + l_bad_name varchar2(100); + begin + --Arrange + l_bad_name := 'context name with spaces'; + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(4, 'context',null, null), + ut3_develop.ut_annotation(5, 'name',l_bad_name, null), + ut3_develop.ut_annotation(7, 'test', 'In context', 'test_in_a_context'), + ut3_develop.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( + '%Invalid value "'||l_bad_name||'" for context name. Context name ignored and fallback to auto-name "nested_context_#1"%' + ); + ut.expect(l_actual).to_be_like( + ''|| + '' || + '%' || + '' || + '%nested_context_#1nested_context_#1some_package.nested_context_#1' || + '%' || + '' || + '%test_in_a_contextIn contextsome_package.nested_context_#1.test_in_a_context' || + '%' || + '%' || + '%' || + '%' || + ''|| + '' + ); + end; + + procedure duplicate_name_annotation is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(4, 'context','A context', null), + ut3_develop.ut_annotation(5, 'name','a_context_name', null), + ut3_develop.ut_annotation(6, 'name','a_newer_context_name', null), + ut3_develop.ut_annotation(7, 'test', 'In context', 'test_in_a_context'), + ut3_develop.ut_annotation(8, 'endcontext',null, null), + ut3_develop.ut_annotation(12, 'test', 'In suite', 'suite_level_test') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%Duplicate annotation "--%name". Annotation ignored.%%' + ,'\' + ); + ut.expect(l_actual).to_be_like( + ''|| + '' || + '%' || + '' || + '%a_context_nameA contextsome_package.a_context_name' || + '%' || + '' || + '%test_in_a_contextIn contextsome_package.a_context_name.test_in_a_context' || + '%' || + '' || + '' || + '' || + '' || + '' || + '%suite_level_testIn suitesome_package.suite_level_test' || + '%' || + '' || + '' || + '' || + ''|| + '' + ); + end; + + procedure name_outside_of_context is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(3, 'name','a_context_name', null), + ut3_develop.ut_annotation(4, 'context','A context', null), + ut3_develop.ut_annotation(7, 'test', 'In context', 'test_in_a_context'), + ut3_develop.ut_annotation(8, 'endcontext',null, null), + ut3_develop.ut_annotation(12, 'test', 'In suite', 'suite_level_test') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%' + ,'\' + ); + ut.expect(l_actual).to_be_like( + ''|| + '' || + '%' || + '' || + '%nested_context_#1A contextsome_package.nested_context_#1' || + '%' || + '' || + '%test_in_a_contextIn contextsome_package.nested_context_#1.test_in_a_context' || + '%' || + '' || + '' || + '' || + '' || + '' || + '%suite_level_testIn suitesome_package.suite_level_test' || + '%' || + '' || + '' || + '' || + ''|| + '' + ); + end; + + procedure name_empty_value is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(4, 'context','A context', null), + ut3_develop.ut_annotation(5, 'name',null, null), + ut3_develop.ut_annotation(7, 'test', 'In context', 'test_in_a_context'), + ut3_develop.ut_annotation(8, 'endcontext',null, null), + ut3_develop.ut_annotation(12, 'test', 'In suite', 'suite_level_test') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%' + ,'\' + ); + ut.expect(l_actual).to_be_like( + ''|| + '' || + '%' || + '' || + '%nested_context_#1A contextsome_package.nested_context_#1' || + '%' || + '' || + '%test_in_a_contextIn contextsome_package.nested_context_#1.test_in_a_context' || + '%' || + '' || + '' || + '' || + '' || + '' || + '%suite_level_testIn suitesome_package.suite_level_test' || + '%' || + '' || + '' || + '' || + ''|| + '' + ); + end; + + procedure multiple_contexts is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(4, 'context','A context', null), + ut3_develop.ut_annotation(6, 'test', 'In context1', 'test_in_a_context1'), + ut3_develop.ut_annotation(7, 'endcontext',null, null), + ut3_develop.ut_annotation(8, 'context','A context', null), + ut3_develop.ut_annotation(10, 'test', 'In context2', 'test_in_a_context2'), + ut3_develop.ut_annotation(11, 'endcontext',null, null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%' + ,'\' + ); + ut.expect(l_actual).to_be_like( + ''|| + '' || + '%' || + '' || + '%nested_context_#1A contextsome_package.nested_context_#1' || + '%' || + '' || + '%test_in_a_context1In context1some_package.nested_context_#1.test_in_a_context1' || + '%' || + '' || + '' || + '' || + '' || + '' || + '%nested_context_#2A contextsome_package.nested_context_#2' || + '%' || + '' || + '%test_in_a_context2In context2some_package.nested_context_#2.test_in_a_context2' || + '%' || + '' || + '' || + '' || + '' || + '' || + '' || + '' || + ''|| + '' + ); + end; + + procedure throws_value_empty is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(3, 'test','A test with empty throws annotation', 'A_TEST_PROCEDURE'), + ut3_develop.ut_annotation(3, 'throws',null, 'A_TEST_PROCEDURE') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%"--%throws" annotation requires a parameter. Annotation ignored.%%' + ); + end; + + + procedure before_aftertest_multi is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(14, 'test','A test', 'some_test'), + ut3_develop.ut_annotation(15, 'beforetest','before_test_proc', 'some_test'), + ut3_develop.ut_annotation(16, 'beforetest','before_test_proc2', 'some_test'), + ut3_develop.ut_annotation(18, 'aftertest','after_test_proc', 'some_test'), + ut3_develop.ut_annotation(20, 'aftertest','after_test_proc2', 'some_test') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%some_package%some_test' || + '%' || + '%some_packagebefore_test_proc' || + '%some_packagebefore_test_proc2' || + '%' || + '%' || + '%some_packageafter_test_proc' || + '%some_packageafter_test_proc2' || + '%' || + '%%' + ); + end; + + procedure before_aftertest_twice is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(14, 'test','A test', 'some_test'), + ut3_develop.ut_annotation(15, 'beforetest','before_test_proc, before_test_proc2', 'some_test'), + ut3_develop.ut_annotation(16, 'beforetest','before_test_proc3', 'some_test'), + ut3_develop.ut_annotation(18, 'aftertest','after_test_proc,after_test_proc2', 'some_test'), + ut3_develop.ut_annotation(20, 'aftertest','after_test_proc3', 'some_test') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%some_package%some_test' || + '%' || + '%some_packagebefore_test_proc' || + '%some_packagebefore_test_proc2' || + '%some_packagebefore_test_proc3' || + '%' || + '%' || + '%some_packageafter_test_proc' || + '%some_packageafter_test_proc2' || + '%some_packageafter_test_proc3' || + '%' || + '%%' + ); + end; + + procedure before_aftertest_pkg_proc is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(14, 'test','A test', 'some_test'), + ut3_develop.ut_annotation(15, 'beforetest','external_package.before_test_proc', 'some_test'), + ut3_develop.ut_annotation(18, 'aftertest','external_package.after_test_proc', 'some_test') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%some_package%some_test' || + '%' || + '%external_packagebefore_test_proc' || + '%' || + '%' || + '%external_packageafter_test_proc' || + '%' || + '%%' + ); + end; + + procedure before_aftertest_mixed_syntax is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(14, 'test','A test', 'some_test'), + ut3_develop.ut_annotation(15, 'beforetest','external_package.before_test_proc, before_test_proc2', 'some_test'), + ut3_develop.ut_annotation(18, 'aftertest','external_package.after_test_proc, after_test_proc2', 'some_test') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%some_package%some_test' || + '%' || + '%external_packagebefore_test_proc' || + '%some_packagebefore_test_proc2' || + '%' || + '%' || + '%external_packageafter_test_proc' || + '%some_packageafter_test_proc2' || + '%' || + '%%' + ); + end; + + procedure test_annotation_ordering is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(4, 'test','B test', 'b_test'), + ut3_develop.ut_annotation(10, 'test','Z test', 'z_test'), + ut3_develop.ut_annotation(14, 'test','A test', 'a_test') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%some_package%b_test' || + '%%'|| + '%%some_package%z_test' || + '%%'|| + '%%some_package%a_test' || + '%%' + ); + end; + + procedure test_bad_procedure_annotation is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(2, 'bad_procedure_annotation',null, 'some_procedure'), + ut3_develop.ut_annotation(6, 'test','A test', 'do_stuff') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_match('(.*)(Unsupported annotation "--%bad_procedure_annotation"\. Annotation ignored\.)(.*)( line 2)(.*)', 'n'); + end; + + procedure test_bad_package_annotation is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(1, 'suite','Cool', null), + ut3_develop.ut_annotation(17, 'bad_package_annotation',null, null), + ut3_develop.ut_annotation(24, 'test','A test', 'do_stuff') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_match('(.*)(Unsupported annotation "--%bad_package_annotation"\. Annotation ignored\.)(.*)( line 17)(.*)', 'n'); + end; + + procedure test_tag_annotation is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','testsuite', null), + ut3_develop.ut_annotation(8, 'test','Some test', 'test_procedure'), + ut3_develop.ut_annotation(9, 'tags','testtag', 'test_procedure') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%' || + '%test_procedureSome testsome_package.test_procedure' || + '%testtag%'|| + '%%' + ); + + end; + + procedure suite_tag_annotation is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','testsuite', null), + ut3_develop.ut_annotation(3, 'tags','suitetag', null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%' || + '%some_packagetestsuitesome_package' || + '%suitetag%'|| + '%%' + ); + + end; + + procedure test_tags_annotation is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','testsuite', null), + ut3_develop.ut_annotation(8, 'test','Some test', 'test_procedure'), + ut3_develop.ut_annotation(9, 'tags','testtag,testtag2,testtag3', 'test_procedure') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%' || + '%test_procedureSome testsome_package.test_procedure' || + '%testtagtesttag2testtag3%'|| + '%%' + ); + + end; + + procedure suite_tags_annotation is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','testsuite', null), + ut3_develop.ut_annotation(3, 'tags','suitetag,suitetag1,suitetag2', null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%' || + '%some_packagetestsuitesome_package' || + '%suitetagsuitetag1suitetag2%'|| + '%%' + ); + + end; + + procedure test_2line_tags_annotation is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','testsuite', null), + ut3_develop.ut_annotation(8, 'test','Some test', 'test_procedure'), + ut3_develop.ut_annotation(9, 'tags','testtag', 'test_procedure'), + ut3_develop.ut_annotation(10, 'tags','testtag2', 'test_procedure') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%' || + '%test_procedureSome testsome_package.test_procedure' || + '%testtagtesttag2%'|| + '%%' + ); + + end; + + procedure suite_2line_tags_annotation is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','testsuite', null), + ut3_develop.ut_annotation(3, 'tags','suitetag', null), + ut3_develop.ut_annotation(4, 'tags','suitetag1', null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%' || + '%some_packagetestsuitesome_package' || + '%suitetagsuitetag1%'|| + '%%' + ); + + end; + + procedure test_empty_tag is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','testsuite', null), + ut3_develop.ut_annotation(8, 'test','Some test', 'test_procedure'), + ut3_develop.ut_annotation(9, 'tags',null, 'test_procedure') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%%"--%tags" annotation requires a tag value populated. Annotation ignored.%%'|| + '%%' + ); + + end; + + procedure suite_empty_tag is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','testsuite', null), + ut3_develop.ut_annotation(3, 'tags',null, null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%"--%tags" annotation requires a tag value populated. Annotation ignored.%%'|| + '%%' + ); + + end; + + procedure test_duplicate_tag is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','testsuite', null), + ut3_develop.ut_annotation(8, 'test','Some test', 'test_procedure'), + ut3_develop.ut_annotation(9, 'tags','testtag,testtag1,testtag', 'test_procedure'), + ut3_develop.ut_annotation(10, 'tags',' testtag,testtag1,testtag2', 'test_procedure') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%' || + '%test_procedureSome testsome_package.test_procedure' || + '%testtagtesttag1testtag2%'|| + '%%' + ); + + end; + + procedure suite_duplicate_tag is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','testsuite', null), + ut3_develop.ut_annotation(3, 'tags','suitetag,suitetag1,suitetag', null), + ut3_develop.ut_annotation(4, 'tags',' suitetag1,suitetag2', null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%' || + '%some_packagetestsuitesome_package' || + '%suitetagsuitetag1suitetag2%'|| + '%%' + ); + + end; + + procedure test_empty_tag_between is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','testsuite', null), + ut3_develop.ut_annotation(8, 'test','Some test', 'test_procedure'), + ut3_develop.ut_annotation(9, 'tags','testtag,, ,testtag1', 'test_procedure') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%' || + '%test_procedureSome testsome_package.test_procedure' || + '%testtagtesttag1%'|| + '%%' + ); + + end; + + procedure suite_empty_tag_between is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','testsuite', null), + ut3_develop.ut_annotation(3, 'tags','suitetag,, ,suitetag1', null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%' || + '%some_packagetestsuitesome_package' || + '%suitetagsuitetag1%'|| + '%%' + ); + + end; + + procedure test_special_char_tag is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','testsuite', null), + ut3_develop.ut_annotation(8, 'test','Some test', 'test_procedure'), + ut3_develop.ut_annotation(9, 'tags','#?$%^&*!|\/@][', 'test_procedure') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%' || + '%test_procedureSome testsome_package.test_procedure' || + '%#?$%^&*!|\/@][%'|| + '%%' + ); + + end; + + procedure suite_special_char_tag is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','testsuite', null), + ut3_develop.ut_annotation(3, 'tags','#?$%^&*!|\/@][', null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%' || + '%some_packagetestsuitesome_package' || + '%#?$%^&*!|\/@][%'|| + '%%' + ); + + end; + + procedure test_spaces_in_tag is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','testsuite', null), + ut3_develop.ut_annotation(3, 'tags',' good_tag , bad tag , good-tag ', null), + ut3_develop.ut_annotation(8, 'test','Some test', 'test_procedure'), + ut3_develop.ut_annotation(9, 'tags',' good_tag , bad tag , good-tag ', 'test_procedure') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%good_taggood-tag%'|| + 'good_taggood-tag%' + ); + ut.expect(l_actual).to_be_like( + '%Invalid value "bad tag" for "--%tags" annotation.'|| + ' See documentation for details on valid tag values. Annotation value ignored.' || + '%at package "UT3_TESTER.SOME_PACKAGE", line 3%' + ); + ut.expect(l_actual).to_be_like( + '%Invalid value "bad tag" for "--%tags" annotation.'|| + ' See documentation for details on valid tag values. Annotation value ignored.' || + '%at package "UT3_TESTER.SOME_PACKAGE.TEST_PROCEDURE", line 9%' + ); + end; + + procedure test_minus_in_tag is + l_actual clob; + l_annotations ut3_develop.ut_annotations; + begin + --Arrange + l_annotations := ut3_develop.ut_annotations( + ut3_develop.ut_annotation(2, 'suite','testsuite', null), + ut3_develop.ut_annotation(3, 'tags',' good_tag , -invalid_tag , good-tag ', null), + ut3_develop.ut_annotation(8, 'test','Some test', 'test_procedure'), + ut3_develop.ut_annotation(9, 'tags',' good_tag , -invalid_tag , good-tag ', 'test_procedure') + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%good_taggood-tag%'|| + 'good_taggood-tag%' + ); + ut.expect(l_actual).to_be_like( + '%Invalid value "-invalid_tag" for "--%tags" annotation.'|| + ' See documentation for details on valid tag values. Annotation value ignored.' || + '%at package "UT3_TESTER.SOME_PACKAGE", line 3%' + ); + ut.expect(l_actual).to_be_like( + '%Invalid value "-invalid_tag" for "--%tags" annotation.'|| + ' See documentation for details on valid tag values. Annotation value ignored.' || + '%at package "UT3_TESTER.SOME_PACKAGE.TEST_PROCEDURE", line 9%' + ); + end; + +end test_suite_builder; +/ diff --git a/test/ut3_tester/core/test_suite_builder.pks b/test/ut3_tester/core/test_suite_builder.pks new file mode 100644 index 000000000..4cbfcad74 --- /dev/null +++ b/test/ut3_tester/core/test_suite_builder.pks @@ -0,0 +1,245 @@ +create or replace package test_suite_builder is + --%suite(suite_builder) + --%suitepath(utplsql.ut3_tester.core) + + --%context(--%suite annotation) + --%name(suite) + + --%test(Sets suite name from package name and leaves description empty) + procedure no_suite_description; + + --%test(Sets suite description using first --%suite annotation) + procedure suite_description_from_suite; + + --%test(Gives warning if more than one --%suite annotation used) + procedure suite_annot_duplicated; + + --%endcontext + + --%context(--%displayname annotation) + + --%test(Overrides suite description using first --%displayname annotation) + procedure suite_descr_from_displayname; + + --%test(Gives warning if more than one --%displayname annotation used) + procedure displayname_annot_duplicated; + + --%test(Gives warning if --%displayname annotation has no value) + procedure displayname_annot_empty; + + --%endcontext + + --%context(--%test annotation) + + --%test(Creates a test item for procedure annotated with --%test annotation) + procedure test_annotation; + + --%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 annotation) + + --%test(Sets suite path using first --%suitepath annotation) + procedure suitepath_from_non_empty_path; + + --%test(Gives warning if more than one --%suitepath annotation used) + procedure suitepath_annot_duplicated; + + --%test(Gives warning if --%suitepath annotation has no value) + procedure suitepath_annot_empty; + + --%test(Gives warning if --%suitepath annotation has invalid value) + procedure suitepath_annot_invalid_path; + + --%endcontext + + --%context--%rollback annotation) + + --%test(Sets rollback type using first --%rollback annotation) + procedure rollback_type_valid; + + --%test(Gives warning if more than one --%rollback annotation used) + procedure rollback_type_duplicated; + + --%test(Gives warning if --%rollback annotation has no value) + procedure rollback_type_empty; + + --%test(Gives warning if --%rollback annotation has invalid value) + procedure rollback_type_invalid; + + --%endcontext + + --%context(--%before/after all/each annotations) + + --%test(Supports multiple before/after all/each procedure level definitions) + procedure multiple_before_after; + + --%test(Supports multiple before/after all/each standalone level definitions) + procedure multiple_standalone_bef_aft; + + --%test(Supports mixing before/after all/each annotations on single procedure) + procedure before_after_on_single_proc; + + --%test(Supports mixed before/after all/each as standalone and procedure level definitions) + procedure multiple_mixed_bef_aft; + + --%test(Gives warning if more than one --%beforeall annotation used on procedure) + procedure beforeall_annot_duplicated; + + --%test(Gives warning if more than one --%beforeeach annotation used on procedure) + procedure beforeeach_annot_duplicated; + + --%test(Gives warning if more than one --%afterall annotation used on procedure) + procedure afterall_annot_duplicated; + + --%test(Gives warning if more than one --%aftereach annotation used on procedure) + procedure aftereach_annot_duplicated; + + --%test(Gives warning on before/after all/each annotations mixed with test) + procedure before_after_mixed_with_test; + + --%endcontext + + --%context(--%context annotation) + --%name(context) + + --%test(Creates nested suite for content between context/endcontext annotations) + procedure suite_from_context; + + --%test(Creates nested contexts inside a context) + procedure nested_contexts; + + --%test(Creates multiple nested contexts inside a context) + procedure nested_contexts_2; + + --%test(Associates before/after all/each to tests in context only) + procedure before_after_in_context; + + --%test(Propagates beforeeach/aftereach to context) + procedure before_after_out_of_context; + + --%test(Gives warning when endcontext is missing) + procedure context_without_endcontext; + + --%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 falls back to default context name) + procedure duplicate_context_name; + + --%endcontext + + --%context(--%name annotation) + + --%test(Falls back to default context name and gives warning when context name contains "." character) + procedure hard_stop_in_ctx_name; + + --%test(Falls back to default context name and gives warning when name contains spaces) + procedure name_with_spaces_invalid; + + --%test(Raises warning when more than one name annotation used ) + procedure duplicate_name_annotation; + + --%test(Is ignored when used outside of context - no warning given) + procedure name_outside_of_context; + + --%test(Is ignored when name value is empty) + procedure name_empty_value; + + --%test(Is applied to corresponding context when multiple contexts used) + procedure multiple_contexts; + + --%endcontext + + --%context(--%throws annotation) + + --%test(Gives warning if --%throws annotation has no value) + procedure throws_value_empty; + + --%endcontext + + --%context(--%beforetest/aftertest annotation) + + --%test(Supports multiple occurrences of beforetest/aftertest for a test) + procedure before_aftertest_multi; + + --%test(Supports same procedure defined twice) + procedure before_aftertest_twice; + + --%test(Supports beforetest from external package) + procedure before_aftertest_pkg_proc; + + --%test(Supports mix of procedure and package.procedure) + procedure before_aftertest_mixed_syntax; + + --%endcontext + + --%context(--%bad_annotation) + + --%test(Gives warning when unknown procedure level annotation passed) + procedure test_bad_procedure_annotation; + + --%test(Gives warning when unknown package level annotation passed) + procedure test_bad_package_annotation; + + --%endcontext + + --%context(--%tag_annotation) + + --%test(Build suite test with tag) + procedure test_tag_annotation; + + --%test(Build suite with tag) + procedure suite_tag_annotation; + + --%test(Build suite test with three tags) + procedure test_tags_annotation; + + --%test(Build suite with three tags) + procedure suite_tags_annotation; + + --%test(Build suite test with two line tag annotation) + procedure test_2line_tags_annotation; + + --%test(Build suite with two line tag annotation) + procedure suite_2line_tags_annotation; + + --%test(Build suite test with empty line tag annotation) + procedure test_empty_tag; + + --%test(Build suite with empty line tag annotation) + procedure suite_empty_tag; + + --%test(Build suite test with duplicate tag annotation) + procedure test_duplicate_tag; + + --%test(Build suite with duplicate tag annotation) + procedure suite_duplicate_tag; + + --%test(Build suite test with empty between tag annotation) + procedure test_empty_tag_between; + + --%test(Build suite with empty between tag annotation) + procedure suite_empty_tag_between; + + --%test(Build suite test with special char tag annotation) + procedure test_special_char_tag; + + --%test(Build suite with special char tag annotation) + procedure suite_special_char_tag; + + --%test(Raise warning and ignore tag with spaces in tag name) + procedure test_spaces_in_tag; + + --%test(Raise warning and ignore tag starting ith '-') + procedure test_minus_in_tag; + + --%endcontext + +end test_suite_builder; +/ diff --git a/test/ut3_tester/core/test_suite_manager.pkb b/test/ut3_tester/core/test_suite_manager.pkb new file mode 100644 index 000000000..c818ad212 --- /dev/null +++ b/test/ut3_tester/core/test_suite_manager.pkb @@ -0,0 +1,2238 @@ +create or replace package body test_suite_manager is + + ex_obj_doesnt_exist exception; + pragma exception_init(ex_obj_doesnt_exist, -04043); + + procedure create_dummy_long_test_package is + begin + ut3_tester_helper.run_helper.create_dummy_long_test_package(); + end; + + procedure drop_dummy_long_test_package is + begin + ut3_tester_helper.run_helper.drop_dummy_long_test_package(); + end; + + procedure compile_dummy_packages is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package test_package_1 is + + --%suite + --%displayname(test_package_1) + --%suitepath(tests) + --%rollback(manual) + + gv_glob_val number; + + --%beforeeach + procedure global_setup; + + --%aftereach + procedure global_teardown; + + --%test + --%displayname(Test1 from test package 1) + procedure test1; + + --%test(Test2 from test package 1) + --%beforetest(test2_setup) + --%aftertest(test2_teardown) + procedure test2; + + procedure test2_setup; + + procedure test2_teardown; + +end test_package_1;]'; + + execute immediate q'[create or replace package body test_package_1 is + gv_var_1 number; + gv_var_1_temp number; + + procedure global_setup is + begin + gv_var_1 := 1; + gv_glob_val := 1; + end; + + procedure global_teardown is + begin + gv_var_1 := 0; + gv_glob_val := 0; + end; + + procedure test1 is + begin + ut.expect(gv_var_1, 'Some expectation').to_equal(1); + end; + + procedure test2 is + begin + ut.expect(gv_var_1, 'Some expectation').to_equal(2); + end; + + procedure test2_setup is + begin + gv_var_1_temp := gv_var_1; + gv_var_1 := 2; + end; + + procedure test2_teardown is + begin + gv_var_1 := gv_var_1_temp; + gv_var_1_temp := null; + end; + +end test_package_1;]'; + + execute immediate q'[create or replace package test_package_2 is + --%suite + --%suitepath(tests.test_package_1) + + gv_glob_val varchar2(1); + + --%beforeeach + procedure global_setup; + + --%aftereach + procedure global_teardown; + + --%test + procedure test1; + + --%test + --%beforetest(test2_setup) + --%aftertest(test2_teardown) + procedure test2; + + procedure test2_setup; + + procedure test2_teardown; + + --%beforeall + procedure context_setup; + + --%test(Test in a context) + procedure context_test; + + --%afterall + procedure context_teardown; + +end test_package_2;]'; + + execute immediate q'[create or replace package body test_package_2 is + gv_var_1 varchar2(1); + gv_var_1_temp varchar2(1); + + procedure global_setup is + begin + gv_var_1 := 'a'; + gv_glob_val := 'z'; + end; + + procedure global_teardown is + begin + gv_var_1 := 'n'; + gv_glob_val := 'n'; + end; + + procedure test1 is + begin + ut.expect(gv_var_1).to_equal('a'); + end; + + procedure test2 is + begin + ut.expect(gv_var_1).to_equal('b'); + end; + + procedure test2_setup is + begin + gv_var_1_temp := gv_var_1; + gv_var_1 := 'b'; + end; + + procedure test2_teardown is + begin + gv_var_1 := gv_var_1_temp; + gv_var_1_temp := null; + end; + + procedure context_setup is + begin + gv_var_1_temp := gv_var_1 || 'a'; + end; + + procedure context_test is + begin + ut.expect(gv_var_1_temp, 'Some expectation').to_equal('na'); + end; + + procedure context_teardown is + begin + gv_var_1_temp := null; + end; + +end test_package_2;]'; + + execute immediate q'[create or replace package test_package_3 is + --%suite + --%suitepath(tests2) + --%rollback(auto) + + gv_glob_val number; + + --%beforeeach + procedure global_setup; + + --%aftereach + procedure global_teardown; + + --%test + --%rollback(auto) + procedure test1; + + --%test + --%beforetest(test2_setup) + --%aftertest(test2_teardown) + procedure test2; + + procedure test2_setup; + + procedure test2_teardown; + + --%test + --%disabled + procedure disabled_test; + +end test_package_3;]'; + + execute immediate q'[create or replace package body test_package_3 is + gv_var_1 number; + gv_var_1_temp number; + + procedure global_setup is + begin + gv_var_1 := 1; + gv_glob_val := 1; + end; + + procedure global_teardown is + begin + gv_var_1 := 0; + gv_glob_val := 0; + end; + + procedure test1 is + begin + ut.expect(gv_var_1).to_equal(1); + end; + + procedure test2 is + begin + ut.expect(gv_var_1).to_equal(2); + end; + + procedure test2_setup is + begin + gv_var_1_temp := gv_var_1; + gv_var_1 := 2; + end; + + procedure test2_teardown is + begin + gv_var_1 := gv_var_1_temp; + gv_var_1_temp := null; + end; + + procedure disabled_test is + begin + null; + end; + +end test_package_3;]'; + + execute immediate q'[create or replace package test_package_with_ctx is + + --%suite(test_package_with_ctx) + + gv_glob_val number; + + --%context(Some context description) + --%name(some_context) + + --%test + --%displayname(Test1 from test package 1) + procedure test1; + + --%endcontext + +end test_package_with_ctx;]'; + + execute immediate q'[create or replace package body test_package_with_ctx is + + procedure test1 is + begin + null; + end; + +end test_package_with_ctx;]'; + + execute immediate q'[create or replace package test1_frontwildcard is + + --%suite + --%displayname(test1_frontwildcard) + --%suitepath(front_wildcard) + --%rollback(manual) + + --%test + --%displayname(Test1 from test test1_frontwildcard) + procedure first_test; + + --%test + --%displayname(Test2 from test test1_frontwildcard) + procedure second_test; + +end test1_frontwildcard;]'; + + execute immediate q'[create or replace package body test1_frontwildcard is + + procedure first_test is + begin + ut.expect(1).to_equal(1); + end; + + procedure second_test is + begin + ut.expect(1).to_equal(2); + end; + +end test1_frontwildcard;]'; + + execute immediate q'[create or replace package test2_frontwildcard is + + --%suite + --%displayname(test2_frontwildcard) + --%suitepath(front_wildcard) + --%rollback(manual) + + --%test + --%displayname(Test1 from test package test2_frontwildcard) + procedure first_test; + +end test2_frontwildcard;]'; + + execute immediate q'[create or replace package body test2_frontwildcard is + + procedure first_test is + begin + ut.expect(1).to_equal(1); + end; + +end test2_frontwildcard;]'; + + execute immediate q'[create or replace package middle_test1_wildcard is + + --%suite + --%displayname(middle_test1_wildcard) + --%suitepath(wild_middle_card) + --%rollback(manual) + + --%test + --%displayname(Test1 from test middle_test1_wildcard) + procedure middle_first_test; + + --%test + --%displayname(Test2 from test middle_test1_wildcard) + procedure middle_second_test; + +end middle_test1_wildcard;]'; + + execute immediate q'[create or replace package body middle_test1_wildcard is + + procedure middle_first_test is + begin + ut.expect(1).to_equal(1); + end; + + procedure middle_second_test is + begin + ut.expect(1).to_equal(2); + end; + +end middle_test1_wildcard;]'; + + execute immediate q'[create or replace package middle_test2_wildcard is + + --%suite + --%displayname(middle_test2_wildcard) + --%suitepath(wild_middle_card) + --%rollback(manual) + + --%test + --%displayname(Test1 from test package middle_test2_wildcard) + procedure middle_first_test; + +end middle_test2_wildcard;]'; + + execute immediate q'[create or replace package body middle_test2_wildcard is + + procedure middle_first_test is + begin + ut.expect(1).to_equal(1); + end; + +end middle_test2_wildcard;]'; + + execute immediate q'[create or replace package test1_multi_wildcard is + + --%suite + --%displayname(test1_multi_wildcard) + --%suitepath(wildcard_multi_asterisks) + --%rollback(manual) + + --%test + --%displayname(Test1 from test test1_multi_wildcard) + procedure first_multi_test1; + + --%test + --%displayname(Test2 from test test1_multi_wildcard) + procedure second_multi_test2; + +end test1_multi_wildcard;]'; + + execute immediate q'[create or replace package body test1_multi_wildcard is + + procedure first_multi_test1 is + begin + ut.expect(1).to_equal(1); + end; + + procedure second_multi_test2 is + begin + ut.expect(1).to_equal(2); + end; + +end test1_multi_wildcard;]'; + + execute immediate q'[create or replace package test2_multi_wildcard is + + --%suite + --%displayname(test2_multi_wildcard) + --%suitepath(wildcard_multi_asterisks) + --%rollback(manual) + + --%test + --%displayname(Test1 from test package test2_multi_wildcard) + procedure first_multi_test1; + +end test2_multi_wildcard;]'; + + execute immediate q'[create or replace package body test2_multi_wildcard is + + procedure first_multi_test1 is + begin + ut.expect(1).to_equal(1); + end; + +end test2_multi_wildcard;]'; + + end; + + procedure drop_dummy_packages is + pragma autonomous_transaction; + begin + execute immediate 'drop package test_package_1'; + execute immediate 'drop package test_package_2'; + execute immediate 'drop package test_package_3'; + execute immediate 'drop package test_package_with_ctx'; + execute immediate 'drop package test1_frontwildcard'; + execute immediate 'drop package test2_frontwildcard'; + execute immediate 'drop package middle_test1_wildcard'; + execute immediate 'drop package middle_test2_wildcard'; + execute immediate 'drop package test1_multi_wildcard'; + execute immediate 'drop package test2_multi_wildcard'; + end; + + procedure test_schema_run is + c_path constant varchar2(100) := sys_context('USERENV', 'CURRENT_USER'); + l_objects_to_run ut3_develop.ut_suite_items := ut3_develop.ut_suite_items(); + l_all_objects_to_run ut3_develop.ut_suite_items; + + l_test0_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test2_suite ut3_develop.ut_logical_suite; + begin + --Act + l_all_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + for i in 1..l_all_objects_to_run.count loop + if l_all_objects_to_run(i).name in ('tests', 'tests2') then + l_objects_to_run.extend; + l_objects_to_run(l_objects_to_run.last) := l_all_objects_to_run(i); + end if; + end loop; + + --Assert + ut.expect(l_objects_to_run.count).to_equal(2); + + for i in 1 .. 2 loop + l_test0_suite := treat(l_objects_to_run(i) as ut3_develop.ut_logical_suite); + ut.expect(l_test0_suite.name in ('tests', 'tests2')).to_be_true; + + l_test1_suite := treat(l_test0_suite.items(1) as ut3_develop.ut_logical_suite); + + case l_test0_suite.name + when 'tests' then + 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_develop.ut_utils.gc_rollback_manual); + l_test2_suite := treat(l_test1_suite.items(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test2_suite.name).to_equal('test_package_2'); + ut.expect(l_test2_suite.items.count).to_equal(3); + ut.expect(l_test2_suite.rollback_type).to_equal(ut3_develop.ut_utils.gc_rollback_manual); + when 'tests2' then + ut.expect(l_test1_suite.name).to_equal('test_package_3'); + ut.expect(l_test1_suite.items.count).to_equal(3); + end case; + + end loop; + + end; + + procedure test_top2_by_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||'.test_package_2'; + l_objects_to_run ut3_develop.ut_suite_items; + + l_test0_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test2_suite ut3_develop.ut_logical_suite; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test0_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test0_suite.name).to_equal('tests'); + ut.expect(l_test0_suite.items.count).to_equal(1); + l_test1_suite := treat(l_test0_suite.items(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test1_suite.name).to_equal('test_package_1'); + ut.expect(l_test1_suite.items.count).to_equal(1); + ut.expect(l_test1_suite.rollback_type).to_equal(ut3_develop.ut_utils.gc_rollback_manual); + l_test2_suite := treat(l_test1_suite.items(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test2_suite.name).to_equal('test_package_2'); + ut.expect(l_test2_suite.rollback_type).to_equal(ut3_develop.ut_utils.gc_rollback_manual); + ut.expect(l_test2_suite.items.count).to_equal(3); + end; + + procedure test_top2_bt_name_cur_user is + c_path varchar2(100) := 'test_package_2'; + l_objects_to_run ut3_develop.ut_suite_items; + + l_test0_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test2_suite ut3_develop.ut_logical_suite; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test0_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test0_suite.name).to_equal('tests'); + ut.expect(l_test0_suite.items.count).to_equal(1); + l_test1_suite := treat(l_test0_suite.items(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test1_suite.name).to_equal('test_package_1'); + ut.expect(l_test1_suite.items.count).to_equal(1); + ut.expect(l_test1_suite.rollback_type).to_equal(ut3_develop.ut_utils.gc_rollback_manual); + l_test2_suite := treat(l_test1_suite.items(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test2_suite.name).to_equal('test_package_2'); + ut.expect(l_test2_suite.rollback_type).to_equal(ut3_develop.ut_utils.gc_rollback_manual); + ut.expect(l_test2_suite.items.count).to_equal(3); + end; + + procedure test_by_path_to_subsuite is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||':tests.test_package_1.test_package_2'; + l_objects_to_run ut3_develop.ut_suite_items; + + l_test0_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test2_suite ut3_develop.ut_logical_suite; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test0_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test0_suite.name).to_equal('tests'); + ut.expect(l_test0_suite.items.count).to_equal(1); + l_test1_suite := treat(l_test0_suite.items(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test1_suite.name).to_equal('test_package_1'); + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test2_suite := treat(l_test1_suite.items(1) as ut3_develop.ut_logical_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_by_path_to_subsuite_cu is + c_path varchar2(100) := ':tests.test_package_1.test_package_2'; + l_objects_to_run ut3_develop.ut_suite_items; + + l_test0_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test2_suite ut3_develop.ut_logical_suite; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test0_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test0_suite.name).to_equal('tests'); + ut.expect(l_test0_suite.items.count).to_equal(1); + l_test1_suite := treat(l_test0_suite.items(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test1_suite.name).to_equal('test_package_1'); + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test2_suite := treat(l_test1_suite.items(1) as ut3_develop.ut_logical_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_subsute_proc_by_path is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||':tests.test_package_1.test_package_2.test2'; + l_objects_to_run ut3_develop.ut_suite_items; + + l_test0_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test2_suite ut3_develop.ut_logical_suite; + l_test_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test0_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test0_suite.name).to_equal('tests'); + ut.expect(l_test0_suite.items.count).to_equal(1); + l_test1_suite := treat(l_test0_suite.items(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test1_suite.name).to_equal('test_package_1'); + ut.expect(l_test1_suite.rollback_type).to_equal(ut3_develop.ut_utils.gc_rollback_manual); + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test2_suite := treat(l_test1_suite.items(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test2_suite.name).to_equal('test_package_2'); + ut.expect(l_test2_suite.rollback_type).to_equal(ut3_develop.ut_utils.gc_rollback_manual); + ut.expect(l_test2_suite.items.count).to_equal(1); + + l_test_proc := treat(l_test2_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test_proc.name).to_equal('test2'); + ut.expect(l_test_proc.rollback_type).to_equal(ut3_develop.ut_utils.gc_rollback_manual); + ut.expect(l_test_proc.before_test_list.count).to_be_greater_than(0); + ut.expect(l_test_proc.after_test_list.count).to_be_greater_than(0); + + end; + + procedure test_subsute_proc_by_path_cu is + c_path varchar2(100) := ':tests.test_package_1.test_package_2.test2'; + l_objects_to_run ut3_develop.ut_suite_items; + + l_test0_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test2_suite ut3_develop.ut_logical_suite; + l_test_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test0_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test0_suite.name).to_equal('tests'); + ut.expect(l_test0_suite.items.count).to_equal(1); + l_test1_suite := treat(l_test0_suite.items(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test1_suite.name).to_equal('test_package_1'); + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test2_suite := treat(l_test1_suite.items(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test2_suite.name).to_equal('test_package_2'); + ut.expect(l_test2_suite.items.count).to_equal(1); + + l_test_proc := treat(l_test2_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test_proc.name).to_equal('test2'); + ut.expect(l_test_proc.before_test_list.count).to_be_greater_than(0); + ut.expect(l_test_proc.after_test_list.count).to_be_greater_than(0); + end; + + procedure test_top_pack_by_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||'.test_package_1'; + l_objects_to_run ut3_develop.ut_suite_items; + + l_test0_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_suite; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test0_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test0_suite.name).to_equal('tests'); + ut.expect(l_test0_suite.items.count).to_equal(1); + l_test1_suite := treat(l_test0_suite.items(1) as ut3_develop.ut_suite); + + ut.expect(l_test1_suite.name).to_equal('test_package_1'); + 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'); + ut.expect(treat(l_test1_suite.items(1) as ut3_develop.ut_test).before_test_list.count).to_equal(0); + ut.expect(treat(l_test1_suite.items(1) as ut3_develop.ut_test).after_test_list.count).to_equal(0); + ut.expect(treat(l_test1_suite.items(1) as ut3_develop.ut_test).before_each_list.count).to_be_greater_than(0); + ut.expect(treat(l_test1_suite.items(1) as ut3_develop.ut_test).disabled_flag).to_equal(0); + + ut.expect(l_test1_suite.items(2).name).to_equal('test2'); + ut.expect(l_test1_suite.items(2).description).to_equal('Test2 from test package 1'); + ut.expect(treat(l_test1_suite.items(2) as ut3_develop.ut_test).before_test_list.count).to_be_greater_than(0); + ut.expect(treat(l_test1_suite.items(2) as ut3_develop.ut_test).after_test_list.count).to_be_greater_than(0); + ut.expect(treat(l_test1_suite.items(2) as ut3_develop.ut_test).before_each_list.count).to_be_greater_than(0); + ut.expect(treat(l_test1_suite.items(2) as ut3_develop.ut_test).disabled_flag).to_equal(0); + + end; + + procedure test_top_pack_by_name_cu is + c_path varchar2(100) := 'test_package_1'; + l_objects_to_run ut3_develop.ut_suite_items; + + l_test0_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_suite; + l_test2_suite ut3_develop.ut_suite; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test0_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test0_suite.name).to_equal('tests'); + ut.expect(l_test0_suite.items.count).to_equal(1); + l_test1_suite := treat(l_test0_suite.items(1) as ut3_develop.ut_suite); + + ut.expect(l_test1_suite.name).to_equal('test_package_1'); + 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'); + ut.expect(treat(l_test1_suite.items(1) as ut3_develop.ut_test).before_test_list.count).to_equal(0); + ut.expect(treat(l_test1_suite.items(1) as ut3_develop.ut_test).after_test_list.count).to_equal(0); + ut.expect(treat(l_test1_suite.items(1) as ut3_develop.ut_test).before_each_list.count).to_be_greater_than(0); + ut.expect(treat(l_test1_suite.items(1) as ut3_develop.ut_test).disabled_flag).to_equal(0); + + ut.expect(l_test1_suite.items(2).name).to_equal('test2'); + ut.expect(l_test1_suite.items(2).description).to_equal('Test2 from test package 1'); + ut.expect(treat(l_test1_suite.items(2) as ut3_develop.ut_test).before_test_list.count).to_be_greater_than(0); + ut.expect(treat(l_test1_suite.items(2) as ut3_develop.ut_test).after_test_list.count).to_be_greater_than(0); + ut.expect(treat(l_test1_suite.items(2) as ut3_develop.ut_test).before_each_list.count).to_be_greater_than(0); + ut.expect(treat(l_test1_suite.items(2) as ut3_develop.ut_test).disabled_flag).to_equal(0); + + end; + + procedure test_top_pack_by_path is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||':tests'; + l_objects_to_run ut3_develop.ut_suite_items; + + l_test0_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test2_suite ut3_develop.ut_logical_suite; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test0_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test0_suite.name).to_equal('tests'); + ut.expect(l_test0_suite.items.count).to_equal(1); + l_test1_suite := treat(l_test0_suite.items(1) as ut3_develop.ut_logical_suite); + + 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(1) as ut3_develop.ut_logical_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_cu is + c_path varchar2(100) := ':tests'; + l_objects_to_run ut3_develop.ut_suite_items; + + l_test0_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test2_suite ut3_develop.ut_logical_suite; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test0_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test0_suite.name).to_equal('tests'); + ut.expect(l_test0_suite.items.count).to_equal(1); + l_test1_suite := treat(l_test0_suite.items(1) as ut3_develop.ut_logical_suite); + + 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(1) as ut3_develop.ut_logical_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_pck_proc_by_path is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||':tests.test_package_1.test2'; + l_objects_to_run ut3_develop.ut_suite_items; + + l_test0_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test2_suite ut3_develop.ut_logical_suite; + l_test_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test0_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test0_suite.name).to_equal('tests'); + ut.expect(l_test0_suite.items.count).to_equal(1); + l_test1_suite := treat(l_test0_suite.items(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test1_suite.name).to_equal('test_package_1'); + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + + ut.expect(l_test_proc.name).to_equal('test2'); + ut.expect(l_test_proc.description).to_equal('Test2 from test package 1'); + ut.expect(l_test_proc.before_test_list.count).to_be_greater_than(0); + ut.expect(l_test_proc.after_test_list.count).to_be_greater_than(0); + end; + + procedure test_top_pck_proc_by_path_cu is + c_path varchar2(100) := ':tests.test_package_1.test2'; + l_objects_to_run ut3_develop.ut_suite_items; + + l_test0_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test2_suite ut3_develop.ut_logical_suite; + l_test_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test0_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test0_suite.name).to_equal('tests'); + ut.expect(l_test0_suite.items.count).to_equal(1); + l_test1_suite := treat(l_test0_suite.items(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test1_suite.name).to_equal('test_package_1'); + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + + ut.expect(l_test_proc.name).to_equal('test2'); + ut.expect(l_test_proc.description).to_equal('Test2 from test package 1'); + ut.expect(l_test_proc.before_test_list.count).to_be_greater_than(0); + ut.expect(l_test_proc.after_test_list.count).to_be_greater_than(0); + end; + + procedure test_top_pkc_proc_by_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||'.test_package_1.test2'; + l_objects_to_run ut3_develop.ut_suite_items; + + l_test0_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test0_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test0_suite.name).to_equal('tests'); + ut.expect(l_test0_suite.items.count).to_equal(1); + l_test1_suite := treat(l_test0_suite.items(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test1_suite.name).to_equal('test_package_1'); + ut.expect(l_test1_suite.items.count).to_equal(1); + + l_test_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test_proc.name).to_equal('test2'); + ut.expect(l_test_proc.before_test_list.count).to_be_greater_than(0); + ut.expect(l_test_proc.after_test_list.count).to_be_greater_than(0); + end; + + procedure test_top_pkc_proc_by_name_cu is + c_path varchar2(100) := 'test_package_1.test2'; + l_objects_to_run ut3_develop.ut_suite_items; + + l_test0_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test0_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test0_suite.name).to_equal('tests'); + ut.expect(l_test0_suite.items.count).to_equal(1); + l_test1_suite := treat(l_test0_suite.items(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test1_suite.name).to_equal('test_package_1'); + ut.expect(l_test1_suite.items.count).to_equal(1); + + l_test_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test_proc.name).to_equal('test2'); + ut.expect(l_test_proc.before_test_list.count).to_be_greater_than(0); + ut.expect(l_test_proc.after_test_list.count).to_be_greater_than(0); + end; + + procedure test_top_pkc_nosub_by_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||'.test_package_3'; + l_objects_to_run ut3_develop.ut_suite_items; + + l_test0_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1 ut3_develop.ut_test; + l_test3 ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test0_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test0_suite.name).to_equal('tests2'); + ut.expect(l_test0_suite.items.count).to_equal(1); + l_test1_suite := treat(l_test0_suite.items(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test1_suite.name).to_equal('test_package_3'); + ut.expect(l_test1_suite.items.count).to_equal(3); + + l_test1 := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1.name).to_equal('test1'); + ut.expect(l_test1.DISABLED_FLAG).to_equal(0); + + l_test3 := treat(l_test1_suite.items(3) as ut3_develop.ut_test); + ut.expect(l_test3.name).to_equal('disabled_test'); + ut.expect(l_test3.DISABLED_FLAG).to_equal(1); + end; + + procedure test_top_pkc_nosub_by_name_cu is + c_path varchar2(100) := 'test_package_3'; + l_objects_to_run ut3_develop.ut_suite_items; + + l_test0_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1 ut3_develop.ut_test; + l_test3 ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test0_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test0_suite.name).to_equal('tests2'); + ut.expect(l_test0_suite.items.count).to_equal(1); + l_test1_suite := treat(l_test0_suite.items(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test1_suite.name).to_equal('test_package_3'); + ut.expect(l_test1_suite.items.count).to_equal(3); + + l_test1 := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1.name).to_equal('test1'); + ut.expect(l_test1.DISABLED_FLAG).to_equal(0); + + l_test3 := treat(l_test1_suite.items(3) as ut3_develop.ut_test); + ut.expect(l_test3.name).to_equal('disabled_test'); + ut.expect(l_test3.DISABLED_FLAG).to_equal(1); + end; + + procedure test_top_subpck_by_path is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||':tests2.test_package_3'; + l_objects_to_run ut3_develop.ut_suite_items; + + l_test0_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1 ut3_develop.ut_test; + l_test3 ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test0_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test0_suite.name).to_equal('tests2'); + ut.expect(l_test0_suite.items.count).to_equal(1); + l_test1_suite := treat(l_test0_suite.items(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test1_suite.name).to_equal('test_package_3'); + ut.expect(l_test1_suite.items.count).to_equal(3); + + l_test1 := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1.name).to_equal('test1'); + ut.expect(l_test1.DISABLED_FLAG).to_equal(0); + + l_test3 := treat(l_test1_suite.items(3) as ut3_develop.ut_test); + ut.expect(l_test3.name).to_equal('disabled_test'); + ut.expect(l_test3.DISABLED_FLAG).to_equal(1); + end; + + procedure test_top_subpck_by_path_cu is + c_path varchar2(100) := ':tests2.test_package_3'; + l_objects_to_run ut3_develop.ut_suite_items; + + l_test0_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1 ut3_develop.ut_test; + l_test3 ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test0_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test0_suite.name).to_equal('tests2'); + ut.expect(l_test0_suite.items.count).to_equal(1); + l_test1_suite := treat(l_test0_suite.items(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test1_suite.name).to_equal('test_package_3'); + ut.expect(l_test1_suite.items.count).to_equal(3); + + l_test1 := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1.name).to_equal('test1'); + ut.expect(l_test1.DISABLED_FLAG).to_equal(0); + + l_test3 := treat(l_test1_suite.items(3) as ut3_develop.ut_test); + ut.expect(l_test3.name).to_equal('disabled_test'); + ut.expect(l_test3.DISABLED_FLAG).to_equal(1); + end; + + procedure test_search_invalid_pck is + l_objects_to_run ut3_develop.ut_suite_items; + begin + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list('failing_invalid_spec')); + + ut3_develop.ut.expect(l_objects_to_run.count).to_be_greater_than(0); + ut3_develop.ut.expect(l_objects_to_run(l_objects_to_run.first).object_name).to_equal('failing_invalid_spec'); + end; + + procedure compile_invalid_package is + ex_compilation_error exception; + pragma exception_init(ex_compilation_error,-24344); + pragma autonomous_transaction; + begin + begin + execute immediate q'[create or replace package failing_invalid_spec as + --%suite + gv_glob_val non_existing_table.id%type := 0; + + --%beforeall + procedure before_all; + --%test + procedure test1; + --%test + procedure test2; +end;]'; + exception when ex_compilation_error then null; + end; + begin + execute immediate q'[create or replace package body failing_invalid_spec as + procedure before_all is begin gv_glob_val := 1; end; + procedure test1 is begin ut.expect(1).to_equal(1); end; + procedure test2 is begin ut.expect(1).to_equal(1); end; +end;]'; + exception when ex_compilation_error then null; + end; + end; + procedure drop_invalid_package is + pragma autonomous_transaction; + begin + execute immediate 'drop package failing_invalid_spec'; + end; + + procedure test_search_nonexisting_pck is + l_objects_to_run ut3_develop.ut_suite_items; + begin + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list('ut3_develop.failing_non_existing')); + ut.fail('Non existing package did not raise exception'); + exception + when others then + ut.expect(sqlerrm).to_be_like('%failing_non_existing%'); + end; + + procedure test_search_nonex_pck_wild is + l_objects_to_run ut3_develop.ut_suite_items; + begin + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list('ut3_develop.failing_non_*')); + ut.fail('Non existing package did not raise exception'); + exception + when others then + ut.expect(sqlerrm).to_be_like('%failing_non_*%'); + end; + + procedure test_search_nonex_prc_wild is + l_objects_to_run ut3_develop.ut_suite_items; + begin + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list('ut3_tester.test_package_1.nonexist*')); + ut.fail('Non existing package did not raise exception'); + exception + when others then + ut.expect(sqlerrm).to_be_like('%nonexist*%'); + end; + + procedure test_search_nonex_path_wild is + l_objects_to_run ut3_develop.ut_suite_items; + begin + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list('ut3_develop:failing_non_*')); + ut.fail('Non existing path did not raise exception'); + exception + when others then + ut.expect(sqlerrm).to_be_like('%:failing_non_*%'); + end; + + procedure test_search_nonexist_sch_pck is + l_objects_to_run ut3_develop.ut_suite_items; + begin + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list('failing_non_existing')); + 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%'); + end; + + procedure test_desc_with_comma is + l_objects_to_run ut3_develop.ut_suite_items; + l_suite ut3_develop.ut_suite; + l_test ut3_develop.ut_test; + begin + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list('tst_package_to_be_dropped')); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + + l_suite := treat(l_objects_to_run(1) as ut3_develop.ut_suite); + + ut.expect(l_suite.name).to_equal('tst_package_to_be_dropped'); + ut.expect(l_suite.description).to_equal('A suite description, though with comma, is assigned by suite_manager'); + ut.expect(l_suite.items.count).to_equal(2); + + l_test := treat(l_suite.items(1) as ut3_develop.ut_test); + + 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_develop.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 + pragma autonomous_transaction; + begin + execute immediate 'create or replace package tst_package_to_be_dropped as + --%suite(A suite description, though with comma, is assigned by suite_manager) + + --%test(A test description, though with comma, is assigned by suite_manager) + procedure test1; + + --%test + --%displayname(A test description, though with comma, is assigned by suite_manager) + procedure test2; +end;'; + + execute immediate '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;'; + end; + procedure clean_desc_with_comma is + pragma autonomous_transaction; + begin + begin + execute immediate 'drop package tst_package_to_be_dropped'; + exception + when ex_obj_doesnt_exist then + null; + end; + end; + + procedure test_inv_cache_on_drop is + l_test_report ut3_develop.ut_varchar2_list; + begin + + select * bulk collect into l_test_report from table(ut3_develop.ut.run(sys_context('USERENV', 'CURRENT_USER')||'.tst_package_to_be_dropped')); + + -- drop package + clean_inv_cache_on_drop; + + begin + select * bulk collect into l_test_report from table(ut3_develop.ut.run(sys_context('USERENV', 'CURRENT_USER') || '.tst_package_to_be_dropped')); + ut.fail('Cache not invalidated on package drop'); + exception + when others then + ut.expect(sqlerrm).to_be_like('%tst_package_to_be_dropped%does not exist%'); + end; + + end; + procedure setup_inv_cache_on_drop is + pragma autonomous_transaction; + begin + execute immediate 'create or replace package tst_package_to_be_dropped as + --%suite + + --%test + procedure test1; +end;'; + + execute immediate '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;'; + end; + + procedure clean_inv_cache_on_drop is + pragma autonomous_transaction; + begin + execute immediate 'drop package tst_package_to_be_dropped'; + exception + when ex_obj_doesnt_exist then + null; + end; + + procedure test_inv_pck_bodies is + l_test_report ut3_develop.ut_varchar2_list; + begin + + select * bulk collect into l_test_report from table(ut3_develop.ut.run(sys_context('USERENV', 'CURRENT_USER')||'.test_dependencies')); + + ut.expect(l_test_report(l_test_report.count-1)).to_be_like('1 test_, 0 failed, 0 errored, 0 disabled, 0 warning(s)'); + --execute immediate 'select * from table(ut3_develop.ut.run(''UT3_DEVELOP.test_dependencies'', ut3_develop.utplsql_test_reporter()))' into l_result; + +-- ut.expect(l_result).to_equal(ut3_develop.ut_utils.gc_success); + end; + procedure setup_inv_pck_bodies is + pragma autonomous_transaction; + begin + execute immediate 'create table test_dependency_table (id integer)'; + execute immediate 'create or replace package test_dependencies as + -- %suite + + -- %test + procedure dependant; +end;'; + execute immediate 'create or replace package body test_dependencies as + gc_dependant_variable test_dependency_table.id%type; + procedure dependant is begin null; end; +end;'; + + execute immediate 'alter table test_dependency_table modify id number'; + + end; + procedure clean_inv_pck_bodies is + pragma autonomous_transaction; + begin + execute immediate 'drop table test_dependency_table'; + execute immediate 'drop package test_dependencies'; + end; + + procedure test_pck_with_dollar is + l_objects_to_run ut3_develop.ut_suite_items; + l_suite ut3_develop.ut_suite; + begin + --act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list('tst_package_with$dollar')); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + + l_suite := treat(l_objects_to_run(1) as ut3_develop.ut_suite); + ut.expect(l_suite.name).to_equal('tst_package_with$dollar'); + end; + procedure setup_pck_with_dollar is + pragma autonomous_transaction; + begin + execute immediate 'create or replace package tst_package_with$dollar as + --%suite + + --%test + procedure test1; +end;'; + + execute immediate 'create or replace package body tst_package_with$dollar as + procedure test1 is begin ut.expect(1).to_equal(1); end; + procedure test2 is begin ut.expect(1).to_equal(1); end; +end;'; + end; + procedure clean_pck_with_dollar is + pragma autonomous_transaction; + begin + execute immediate 'drop package tst_package_with$dollar'; + end; + + + procedure test_pck_with_hash is + l_objects_to_run ut3_develop.ut_suite_items; + l_suite ut3_develop.ut_suite; + begin + --act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list('tst_package_with#hash')); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + + l_suite := treat(l_objects_to_run(1) as ut3_develop.ut_suite); + ut.expect(l_suite.name).to_equal('tst_package_with#hash'); + end; + procedure setup_pck_with_hash is + pragma autonomous_transaction; + begin + execute immediate 'create or replace package tst_package_with#hash as + --%suite + + --%test + procedure test1; +end;'; + + execute immediate 'create or replace package body tst_package_with#hash as + procedure test1 is begin ut.expect(1).to_equal(1); end; + procedure test2 is begin ut.expect(1).to_equal(1); end; +end;'; + end; + procedure clean_pck_with_hash is + pragma autonomous_transaction; + begin + execute immediate 'drop package tst_package_with#hash'; + end; + + + procedure test_test_with_dollar is + l_objects_to_run ut3_develop.ut_suite_items; + l_suite ut3_develop.ut_suite; + l_test ut3_develop.ut_test; + begin + --act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list('tst_package_with_dollar_test.test$1')); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + + l_suite := treat(l_objects_to_run(1) as ut3_develop.ut_suite); + + ut.expect(l_suite.name).to_equal('tst_package_with_dollar_test'); + ut.expect(l_suite.items.count).to_equal(1); + + l_test := treat(l_suite.items(1) as ut3_develop.ut_test); + + ut.expect(l_test.name).to_equal('test$1'); + + end; + procedure setup_test_with_dollar is + pragma autonomous_transaction; + begin + execute immediate 'create or replace package tst_package_with_dollar_test as + --%suite + + --%test + procedure test$1; +end;'; + + execute immediate 'create or replace package body tst_package_with_dollar_test as + procedure test$1 is begin ut.expect(1).to_equal(1); end; +end;'; + end; + procedure clean_test_with_dollar is + pragma autonomous_transaction; + begin + execute immediate 'drop package tst_package_with_dollar_test'; + end; + + procedure test_test_with_hash is + l_objects_to_run ut3_develop.ut_suite_items; + l_suite ut3_develop.ut_suite; + l_test ut3_develop.ut_test; + begin + --act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list('tst_package_with_hash_test.test#1')); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + + l_suite := treat(l_objects_to_run(1) as ut3_develop.ut_suite); + + ut.expect(l_suite.name).to_equal('tst_package_with_hash_test'); + ut.expect(l_suite.items.count).to_equal(1); + + l_test := treat(l_suite.items(1) as ut3_develop.ut_test); + + ut.expect(l_test.name).to_equal('test#1'); + + end; + procedure setup_test_with_hash is + pragma autonomous_transaction; + begin + execute immediate 'create or replace package tst_package_with_hash_test as + --%suite + + --%test + procedure test#1; +end;'; + + execute immediate 'create or replace package body tst_package_with_hash_test as + procedure test#1 is begin ut.expect(1).to_equal(1); end; +end;'; + end; + procedure clean_test_with_hash is + pragma autonomous_transaction; + begin + execute immediate 'drop package tst_package_with_hash_test'; + end; + + procedure test_empty_suite_path is + l_objects_to_run ut3_develop.ut_suite_items; + l_suite ut3_develop.ut_suite; + begin + + --act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.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 ut3_develop.ut_suite); + + ut.expect(l_suite.name).to_equal('tst_empty_suite_path'); + end; + + procedure setup_empty_suite_path is + pragma autonomous_transaction; + begin + execute immediate 'create or replace package tst_empty_suite_path as + --%suite + --%suitepath + + --%test + procedure test1; +end;'; + execute immediate 'create or replace package body tst_empty_suite_path as + procedure test1 is begin ut.expect(1).to_equal(1); end; +end;'; + end; + + procedure clean_empty_suite_path is + pragma autonomous_transaction; + begin + execute immediate 'drop package tst_empty_suite_path'; + end; + + procedure test_pck_with_same_path is + l_objects_to_run ut3_develop.ut_suite_items; + l_suite1 ut3_develop.ut_logical_suite; + l_suite2 ut3_develop.ut_logical_suite; + l_suite3 ut3_develop.ut_suite; + begin + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(':test1.test2$.test_package_same_1')); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + + l_suite1 := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_suite1.name).to_equal('test1'); + ut.expect(l_suite1.items.count).to_equal(1); + + l_suite2 := treat(l_suite1.items(1) as ut3_develop.ut_logical_suite); + ut.expect(l_suite2.name).to_equal('test2$'); + ut.expect(l_suite2.items.count).to_equal(1); + + l_suite3 := treat(l_suite2.items(1) as ut3_develop.ut_suite); + ut.expect(l_suite3.name).to_equal('test_package_same_1'); + end; + + procedure setup_pck_with_same_path is + pragma autonomous_transaction; + begin + execute immediate 'create or replace package test_package_same_1 as + --%suite + --%suitepath(test1.test2$) + + --%test + procedure test1; +end;'; + execute immediate 'create or replace package body test_package_same_1 as + procedure test1 is begin null; end; +end;'; + execute immediate 'create or replace package test_package_same_1_a as + --%suite + --%suitepath(test1.test2$) + + --%test + procedure test1; +end;'; + execute immediate 'create or replace package body test_package_same_1_a as + procedure test1 is begin null; end; +end;'; + end; + + procedure clean_pck_with_same_path is + pragma autonomous_transaction; + begin + execute immediate 'drop package test_package_same_1'; + execute immediate 'drop package test_package_same_1_a'; + end; + + procedure setup_disabled_pck is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package test_disabled_floating as + --%suite + + --%test + procedure test1; + + --%disabled + + --%test + procedure test2; + +end;]'; + end; + + procedure clean_disabled_pck is + pragma autonomous_transaction; + begin + execute immediate 'drop package test_disabled_floating'; + end; + + procedure disable_suite_floating_annot is + l_objects_to_run ut3_develop.ut_suite_items; + l_suite ut3_develop.ut_suite; + begin + --Arrange + setup_disabled_pck; + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list('test_disabled_floating')); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_suite := treat(l_objects_to_run(1) as ut3_develop.ut_suite); + ut.expect(l_suite.name).to_equal('test_disabled_floating'); + ut.expect(l_suite.get_disabled_flag()).to_be_true(); + + clean_disabled_pck; + end; + + procedure pck_proc_in_ctx_by_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||'.test_package_with_ctx.test1'; + l_objects_to_run ut3_develop.ut_suite_items; + + l_test_suite ut3_develop.ut_logical_suite; + l_ctx_suite ut3_develop.ut_logical_suite; + l_test_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('test_package_with_ctx'); + ut.expect(l_test_suite.items.count).to_equal(1); + + l_ctx_suite := treat(l_test_suite.items(1) as ut3_develop.ut_logical_suite); + ut.expect(l_ctx_suite.name).to_equal('some_context'); + ut.expect(l_ctx_suite.description).to_equal('Some context description'); + ut.expect(l_ctx_suite.items.count).to_equal(1); + + l_test_proc := treat(l_ctx_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test_proc.name).to_equal('test1'); + end; + + procedure pck_proc_in_ctx_by_path is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||':test_package_with_ctx.some_context.test1'; + l_objects_to_run ut3_develop.ut_suite_items; + + l_test_suite ut3_develop.ut_logical_suite; + l_ctx_suite ut3_develop.ut_logical_suite; + l_test_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('test_package_with_ctx'); + ut.expect(l_test_suite.items.count).to_equal(1); + + l_ctx_suite := treat(l_test_suite.items(1) as ut3_develop.ut_logical_suite); + ut.expect(l_ctx_suite.name).to_equal('some_context'); + ut.expect(l_ctx_suite.description).to_equal('Some context description'); + ut.expect(l_ctx_suite.items.count).to_equal(1); + + l_test_proc := treat(l_ctx_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test_proc.name).to_equal('test1'); + end; + + procedure test_get_schema_ut_packages is + l_expected ut3_develop.ut_object_names; + l_actual ut3_develop.ut_object_names; + begin + l_expected := ut3_develop.ut_object_names( + ut3_develop.ut_object_name('UT3_DEVELOP','SOME_TEST_PACKAGE') + ); + l_actual := ut3_tester_helper.run_helper.get_schema_ut_packages('UT3_DEVELOP'); + + ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); + end; + + procedure create_ut3_suite is + begin + ut3_tester_helper.run_helper.create_ut3_suite(); + end; + + procedure drop_ut3_suite is + pragma autonomous_transaction; + begin + ut3_tester_helper.run_helper.drop_ut3_suite(); + end; + + procedure add_new_long_test_package is + l_actual ut3_develop.ut_object_names; + l_expected_message varchar2(500); + begin + l_expected_message := q'[ORA-20217: 'Suitepath exceeds 1000 CHAR on: UT3_DEVELOP.DUMMY_LONG_TEST_PACKAGE,UT3_DEVELOP.DUMMY_LONG_TEST_PACKAGE1'%]'; + l_actual := ut3_tester_helper.run_helper.get_schema_ut_packages('UT3_DEVELOP'); + ut.fail('Expected exception for suitpaths over 1k for two packages'); + exception + when others then + ut.expect(dbms_utility.format_error_stack()).to_be_like(l_expected_message); + ut.expect(SQLCODE).to_equal(ut3_develop.ut_utils.gc_value_too_large); + end; + + procedure setup_remove_annot_test is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package test_removing_annotation as + --%suite + + --%test + procedure test1; + + --%test + procedure test2; + +end;]'; + end; + + procedure remove_annot_from_test is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package test_removing_annotation as + + procedure test1; + + procedure test2; + +end;]'; + end; + + procedure rem_one_annot_test is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package test_removing_annotation as + --%suite + + procedure test1; + + --%test + procedure test2; + +end;]'; + execute immediate q'[create or replace package body test_removing_annotation as + + procedure test1 is + begin + ut.expect(1).to_equal(1); + end; + + procedure test2 is + begin + ut.expect(1).to_equal(1); + end; + +end;]'; + end; + + procedure clean_remove_annot_test is + pragma autonomous_transaction; + begin + execute immediate 'drop package test_removing_annotation'; + end; + + procedure test_rem_cache_on_create is + l_test_report ut3_develop.ut_varchar2_list; + begin + + select * bulk collect into l_test_report from table(ut3_develop.ut.run(sys_context('USERENV', 'CURRENT_USER')||'.test_removing_annotation')); + + -- drop all tests + remove_annot_from_test; + + begin + select * bulk collect into l_test_report from table(ut3_develop.ut.run(sys_context('USERENV', 'CURRENT_USER') || '.test_removing_annotation')); + exception + when others then + ut.expect(sqlerrm).to_be_like('%ORA-20204: Suite package ut3_tester.test_removing_annotation does not exist%'); + end; + + end; + + procedure test_rem_cache_on_crt_anno is + l_test_report ut3_develop.ut_varchar2_list; + l_results clob; + begin + + select * bulk collect into l_test_report from table(ut3_develop.ut.run(sys_context('USERENV', 'CURRENT_USER')||'.test_removing_annotation')); + + -- drop single test + rem_one_annot_test; + ut3_develop.ut.run(sys_context('USERENV', 'CURRENT_USER')|| '.test_removing_annotation',a_reporter => ut3_develop.ut_documentation_reporter() ); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%1 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%' ); + + end; + + procedure test_wild_card_obj_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||'.test_package_*'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test2_suite ut3_develop.ut_logical_suite; + l_ctx_suite ut3_develop.ut_logical_suite; + l_test_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(3); + + + for i in 1 .. 3 loop + l_test_suite := treat(l_objects_to_run(i) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name in ('test_package_with_ctx','tests', 'tests2')).to_be_true; + + case l_test_suite.name + when 'test_package_with_ctx' then + ut.expect(l_test_suite.items.count).to_equal(1); + l_ctx_suite:= treat(l_test_suite.items(1) as ut3_develop.ut_logical_suite); + ut.expect(l_ctx_suite.name).to_equal('some_context'); + ut.expect(l_ctx_suite.description).to_equal('Some context description'); + ut.expect(l_ctx_suite.items.count).to_equal(1); + l_test_proc := treat(l_ctx_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test_proc.name).to_equal('test1'); + when 'tests' then + l_test1_suite := treat(l_test_suite.items(1) as ut3_develop.ut_logical_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.rollback_type).to_equal(ut3_develop.ut_utils.gc_rollback_manual); + l_test2_suite := treat(l_test1_suite.items(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test2_suite.name).to_equal('test_package_2'); + ut.expect(l_test2_suite.items.count).to_equal(3); + ut.expect(l_test2_suite.rollback_type).to_equal(ut3_develop.ut_utils.gc_rollback_manual); + when 'tests2' then + l_test1_suite := treat(l_test_suite.items(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test1_suite.name).to_equal('test_package_3'); + ut.expect(l_test1_suite.items.count).to_equal(3); + end case; + + end loop; + + end; + + procedure test_wild_card_prc_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||'.test_package_1.test*'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('tests'); + + l_test1_suite := treat(l_test_suite.items(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test1_suite.name).to_equal('test_package_1'); + ut.expect(l_test1_suite.items.count).to_equal(2); + + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('test1'); + + l_test2_proc := treat(l_test1_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test2_proc.name).to_equal('test2'); + end; + + procedure test_wild_card_path_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||':tests*'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test2_suite ut3_develop.ut_logical_suite; + l_ctx_suite ut3_develop.ut_logical_suite; + l_test_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(2); + + + for i in 1 .. 2 loop + l_test_suite := treat(l_objects_to_run(i) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name in ('tests', 'tests2')).to_be_true; + + case l_test_suite.name + when 'tests' then + l_test1_suite := treat(l_test_suite.items(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test1_suite.name).to_equal('test_package_1'); + ut.expect(l_test1_suite.items.count).to_equal(3); + + for i in 1 ..3 loop + case l_test1_suite.items(i).self_type + when 'UT_SUITE' then + l_test2_suite := treat(l_test1_suite.items(i) as ut3_develop.ut_logical_suite); + ut.expect(l_test2_suite.name).to_equal('test_package_2'); + ut.expect(l_test2_suite.items.count).to_equal(3); + + l_test_proc := treat(l_test2_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test_proc.name in ('test1', 'test2','context_test')).to_be_true; + + l_test_proc := treat(l_test2_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test_proc.name in ('test1', 'test2','context_test')).to_be_true; + + l_test_proc := treat(l_test2_suite.items(3) as ut3_develop.ut_test); + ut.expect(l_test_proc.name in ('test1', 'test2','context_test')).to_be_true; + + when 'UT_TEST' then + l_test_proc := treat(l_test1_suite.items(i) as ut3_develop.ut_test); + ut.expect(l_test_proc.name in ('test1', 'test2')).to_be_true; + end case; + end loop; + when 'tests2' then + ut.expect(l_test_suite.items.count).to_equal(1); + l_test1_suite := treat(l_test_suite.items(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test1_suite.name).to_equal('test_package_3'); + ut.expect(l_test1_suite.items.count).to_equal(3); + for i in 1 .. 3 loop + l_test_proc := treat(l_test1_suite.items(i) as ut3_develop.ut_test); + ut.expect(l_test_proc.name in ('test1', 'test2','disabled_test')).to_be_true; + end loop; + end case; + + end loop; + + end; + + procedure test_wild_card_front_obj_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||'.*_frontwildcard'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('front_wildcard'); + ut.expect(l_test_suite.items.count).to_equal(2); + + for i in 1 .. 2 loop + l_test1_suite := treat(l_test_suite.items(i) as ut3_develop.ut_logical_suite); + case l_test1_suite.name + when 'test1_frontwildcard' then + ut.expect(l_test1_suite.items.count).to_equal(2); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_test'); + l_test2_proc := treat(l_test1_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test2_proc.name).to_equal('second_test'); + when 'test2_frontwildcard' then + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_test'); + end case; + + end loop; + end; + + procedure test_wild_card_front_prc_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||'.test1_frontwildcard.*_test'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('front_wildcard'); + + l_test1_suite := treat(l_test_suite.items(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test1_suite.name).to_equal('test1_frontwildcard'); + ut.expect(l_test1_suite.items.count).to_equal(2); + + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_test'); + + l_test2_proc := treat(l_test1_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test2_proc.name).to_equal('second_test'); + end; + + procedure test_wild_card_front_path_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||':*_wildcard'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('front_wildcard'); + ut.expect(l_test_suite.items.count).to_equal(2); + + for i in 1 .. 2 loop + l_test1_suite := treat(l_test_suite.items(i) as ut3_develop.ut_logical_suite); + case l_test1_suite.name + when 'test1_frontwildcard' then + ut.expect(l_test1_suite.items.count).to_equal(2); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_test'); + l_test2_proc := treat(l_test1_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test2_proc.name).to_equal('second_test'); + when 'test2_frontwildcard' then + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_test'); + end case; + + end loop; + end; + + procedure test_wild_card_mid_obj_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||'.middle_*_wildcard'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('wild_middle_card'); + ut.expect(l_test_suite.items.count).to_equal(2); + + for i in 1 .. 2 loop + l_test1_suite := treat(l_test_suite.items(i) as ut3_develop.ut_logical_suite); + case l_test1_suite.name + when 'middle_test1_wildcard' then + ut.expect(l_test1_suite.items.count).to_equal(2); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('middle_first_test'); + l_test2_proc := treat(l_test1_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test2_proc.name).to_equal('middle_second_test'); + when 'middle_test2_wildcard' then + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('middle_first_test'); + end case; + + end loop; + end; + + procedure test_wild_card_mid_prc_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||'.middle_test1_wildcard.middle_*_test'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('wild_middle_card'); + + l_test1_suite := treat(l_test_suite.items(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test1_suite.name).to_equal('middle_test1_wildcard'); + ut.expect(l_test1_suite.items.count).to_equal(2); + + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('middle_first_test'); + + l_test2_proc := treat(l_test1_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test2_proc.name).to_equal('middle_second_test'); + end; + + procedure test_wild_card_mid_path_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||':wild_*card'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('wild_middle_card'); + ut.expect(l_test_suite.items.count).to_equal(2); + + for i in 1 .. 2 loop + l_test1_suite := treat(l_test_suite.items(i) as ut3_develop.ut_logical_suite); + case l_test1_suite.name + when 'middle_test1_wildcard' then + ut.expect(l_test1_suite.items.count).to_equal(2); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('middle_first_test'); + l_test2_proc := treat(l_test1_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test2_proc.name).to_equal('middle_second_test'); + when 'middle_test2_wildcard' then + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('middle_first_test'); + end case; + + end loop; + end; + + procedure test_wild_card_mul_obj_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||'.*_multi_*card'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('wildcard_multi_asterisks'); + ut.expect(l_test_suite.items.count).to_equal(2); + + for i in 1 .. 2 loop + l_test1_suite := treat(l_test_suite.items(i) as ut3_develop.ut_logical_suite); + case l_test1_suite.name + when 'test1_multi_wildcard' then + ut.expect(l_test1_suite.items.count).to_equal(2); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_multi_test1'); + l_test2_proc := treat(l_test1_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test2_proc.name).to_equal('second_multi_test2'); + when 'test2_multi_wildcard' then + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_multi_test1'); + end case; + + end loop; + end; + + procedure test_wild_card_mul_prc_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||'.test1_multi_wildcard.*_multi_*'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('wildcard_multi_asterisks'); + + l_test1_suite := treat(l_test_suite.items(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test1_suite.name).to_equal('test1_multi_wildcard'); + ut.expect(l_test1_suite.items.count).to_equal(2); + + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_multi_test1'); + + l_test2_proc := treat(l_test1_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test2_proc.name).to_equal('second_multi_test2'); + end; + + procedure test_wild_card_mul_path_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||':wild*_multi_*risks'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('wildcard_multi_asterisks'); + ut.expect(l_test_suite.items.count).to_equal(2); + + for i in 1 .. 2 loop + l_test1_suite := treat(l_test_suite.items(i) as ut3_develop.ut_logical_suite); + case l_test1_suite.name + when 'test1_multi_wildcard' then + ut.expect(l_test1_suite.items.count).to_equal(2); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_multi_test1'); + l_test2_proc := treat(l_test1_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test2_proc.name).to_equal('second_multi_test2'); + when 'test2_multi_wildcard' then + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_multi_test1'); + end case; + + end loop; + end; + + procedure tst_wild_card_mul_lv_path_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||':wild*_multi_*risks.*_multi_wildcard.*_multi_test1'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('wildcard_multi_asterisks'); + ut.expect(l_test_suite.items.count).to_equal(2); + + for i in 1 .. 2 loop + l_test1_suite := treat(l_test_suite.items(i) as ut3_develop.ut_logical_suite); + case l_test1_suite.name + when 'test1_multi_wildcard' then + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_multi_test1'); + when 'test2_multi_wildcard' then + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_multi_test1'); + end case; + + end loop; + end; + + --%test(Path validation does not fail on Estonian NLS_SORT - fix #1252) + procedure path_validate_nls_sort is + l_schema_names ut3_develop.ut_varchar2_rows; + begin + --Arrange + execute immediate q'[alter session set nls_sort='estonian']'; + --Act + l_schema_names := ut3_develop.ut_suite_manager.get_schema_names(ut3_develop.ut_varchar2_list('ut3')); + --Asseert + ut.expect(sqlcode).to_equal(0); + end; + + + procedure reset_nls_sort is + begin + execute immediate q'[alter session set nls_sort='binary']'; + end; +end test_suite_manager; +/ diff --git a/test/core/test_suite_manager.pks b/test/ut3_tester/core/test_suite_manager.pks similarity index 60% rename from test/core/test_suite_manager.pks rename to test/ut3_tester/core/test_suite_manager.pks index 45466b9d2..ac7818f4f 100644 --- a/test/core/test_suite_manager.pks +++ b/test/ut3_tester/core/test_suite_manager.pks @@ -1,7 +1,8 @@ create or replace package test_suite_manager is --%suite(suite_manager) - --%suitepath(utplsql.core) + --%suitepath(utplsql.ut3_tester.core) + --%beforeall procedure compile_dummy_packages; @@ -74,8 +75,17 @@ create or replace package test_suite_manager is --%test(Prepare runner for nonexisting package with schema) procedure test_search_nonexisting_pck; - - --%test(Prepare runner for nonexisting package without schema) + + --%test(Prepare runner for nonexisting package using wildcard filter) + procedure test_search_nonex_pck_wild; + + --%test(Prepare runner for nonexisting procedure using wildcard filter) + procedure test_search_nonex_prc_wild; + + --%test(Prepare runner for nonexisting path using wildcard filter) + procedure test_search_nonex_path_wild; + + --%test(Prepare runner for nonexisting package without schema) procedure test_search_nonexist_sch_pck; --%test(Test description with comma) @@ -151,5 +161,91 @@ create or replace package test_suite_manager is --%test(Prepare runner for a package procedure inside context by path) procedure pck_proc_in_ctx_by_path; + --%context(get_schema_ut_packages) + + --%test(returns list of all unit test packages in given schema) + --%beforetest(create_ut3_suite) + --%aftertest(drop_ut3_suite) + procedure test_get_schema_ut_packages; + procedure create_ut3_suite; + procedure drop_ut3_suite; + + --%endcontext + + --%test(Adds suitepath to cache over 1k characters long) + --%beforetest(create_dummy_long_test_package) + --%aftertest(drop_dummy_long_test_package) + procedure add_new_long_test_package; + procedure create_dummy_long_test_package; + procedure drop_dummy_long_test_package; + + + procedure setup_remove_annot_test; + procedure clean_remove_annot_test; + + --%test(Remove cache on package create or replace when all annotations removed) + --%beforetest(setup_remove_annot_test) + --%aftertest(clean_remove_annot_test) + procedure test_rem_cache_on_create; + + + --%test(Remove cache on package create or replace when single annotation removed) + --%beforetest(setup_remove_annot_test) + --%aftertest(clean_remove_annot_test) + procedure test_rem_cache_on_crt_anno; + + --%context(wildcard_filters) + + --%test(Execute test_packages using a object_name with wildcard at the end ) + procedure test_wild_card_obj_name; + + --%test(Execute test_packages using a procedure name with wildcard at the end) + procedure test_wild_card_prc_name; + + --%test(Execute test_packages using a path name with wildcard at the end) + procedure test_wild_card_path_name; + + --%test(Execute test_packages using a object_name with wildcard in the front) + procedure test_wild_card_front_obj_name; + + --%test(Execute test_packages using a procedure name with wildcard in the front) + procedure test_wild_card_front_prc_name; + + -- %test(Execute test_packages using a path name with wildcard in the front) + procedure test_wild_card_front_path_name; + + --%test(Execute test_packages using a object_name with wildcard in the middle) + procedure test_wild_card_mid_obj_name; + + --%test(Execute test_packages using a procedure name with wildcard in the middle) + procedure test_wild_card_mid_prc_name; + + -- %test(Execute test_packages using a path name with wildcard in the middle) + procedure test_wild_card_mid_path_name; + + --%test(Execute test_packages using a object_name with multiple wildcards) + procedure test_wild_card_mul_obj_name; + + --%test(Execute test_packages using a procedure name with multiple wildcards) + procedure test_wild_card_mul_prc_name; + + -- %test(Execute test_packages using a path name with multiple wildcards) + procedure test_wild_card_mul_path_name; + + -- %test(Execute test_packages using a path name with multiple wildcards on different level) + procedure tst_wild_card_mul_lv_path_name; + + --%endcontext + + --%context(paths validation) + + --%test(Path validation does not fail on Estonian NLS_SORT - fix #1252) + --%aftertest(reset_nls_sort) + procedure path_validate_nls_sort; + + procedure reset_nls_sort; + + --%endcontext + end test_suite_manager; / diff --git a/test/ut3_tester/core/test_ut_executable.pkb b/test/ut3_tester/core/test_ut_executable.pkb new file mode 100644 index 000000000..e27a2e432 --- /dev/null +++ b/test/ut3_tester/core/test_ut_executable.pkb @@ -0,0 +1,78 @@ +create or replace package body test_ut_executable is + + g_dbms_output_text varchar2(30) := 'Some output from procedure'; + + procedure exec_schema_package_proc is + l_executable ut3_develop.ut_executable; + l_test ut3_develop.ut_test; + l_result boolean; + begin + --Arrange + l_test := ut3_develop.ut_test(a_object_name => 'test_ut_executable',a_name => 'test_ut_executable', a_line_no=> 1); + l_executable := ut3_develop.ut_executable_test( null, 'test_ut_executable', 'passing_proc', ut3_develop.ut_utils.gc_test_execute ); + --Act + l_result := l_executable.do_execute(l_test); + --Assert + ut.expect(l_result).to_be_true; + ut.expect(l_executable.serveroutput).to_be_null; + ut.expect(l_executable.get_error_stack_trace()).to_be_null; + end; + + procedure exec_package_proc_output is + l_executable ut3_develop.ut_executable; + l_test ut3_develop.ut_test; + l_result boolean; + begin + --Arrange + l_test := ut3_develop.ut_test(a_object_owner => 'ut3_tester', a_object_name => 'test_ut_executable',a_name => 'test_ut_executable', a_line_no=> 1); + l_executable := ut3_develop.ut_executable_test( a_owner => 'ut3_tester', a_package => 'test_ut_executable', + a_procedure_name => 'output_proc', a_executable_type => ut3_develop.ut_utils.gc_test_execute ); + --Act + l_result := l_executable.do_execute(l_test); + --Assert + ut.expect(l_result).to_be_true; + ut.expect(l_executable.serveroutput).to_equal(to_clob(g_dbms_output_text||chr(10))); + ut.expect(l_executable.get_error_stack_trace()).to_be_null; + end; + + procedure exec_failing_proc is + l_executable ut3_develop.ut_executable; + l_test ut3_develop.ut_test; + l_result boolean; + begin + --Arrange + l_test := ut3_develop.ut_test(a_object_owner => 'ut3_tester', a_object_name => 'test_ut_executable',a_name => 'test_ut_executable', a_line_no=> 1); + l_executable := ut3_develop.ut_executable_test( 'ut3_tester', 'test_ut_executable', 'throwing_proc', ut3_develop.ut_utils.gc_test_execute ); + --Act + l_result := l_executable.do_execute(l_test); + --Assert + ut.expect(l_result).to_be_false; + ut.expect(l_executable.serveroutput).to_be_null; + ut.expect(l_executable.get_error_stack_trace()).to_be_like('ORA-06501: PL/SQL: program error%'); + end; + + procedure form_name is + begin + ut.expect(ut3_develop.ut_executable_test( user, ' package ', 'proc', null ).form_name()).to_equal(user||'.package.proc'); + ut.expect(ut3_develop.ut_executable_test( null, 'package', ' proc ', null ).form_name()).to_equal('package.proc'); + ut.expect(ut3_develop.ut_executable_test( null, 'proc', null, null ).form_name()).to_equal('proc'); + ut.expect(ut3_develop.ut_executable_test( ' '||user||' ', 'proc', null, null ).form_name()).to_equal(user||'.proc'); + end; + + procedure passing_proc is + begin + null; + end; + + procedure output_proc is + begin + dbms_output.put_line('Some output from procedure'); + end; + + procedure throwing_proc is + begin + raise program_error; + end; + +end; +/ diff --git a/test/core/test_ut_executable.pks b/test/ut3_tester/core/test_ut_executable.pks similarity index 94% rename from test/core/test_ut_executable.pks rename to test/ut3_tester/core/test_ut_executable.pks index 4c11e5142..882f0f209 100644 --- a/test/core/test_ut_executable.pks +++ b/test/ut3_tester/core/test_ut_executable.pks @@ -1,7 +1,7 @@ create or replace package test_ut_executable is --%suite(ut_executable) - --%suitepath(utplsql.core) + --%suitepath(utplsql.ut3_tester.core) --%context(do_execute) diff --git a/test/ut3_tester/core/test_ut_suite.pkb b/test/ut3_tester/core/test_ut_suite.pkb new file mode 100644 index 000000000..7cb9121f6 --- /dev/null +++ b/test/ut3_tester/core/test_ut_suite.pkb @@ -0,0 +1,164 @@ +create or replace package body test_ut_suite is + + procedure cleanup_package_state is + begin + ut3_tester_helper.ut_example_tests.g_number := null; + end; + + procedure create_trans_control is + begin + ut3_tester_helper.run_helper.create_trans_control; + end; + + procedure drop_trans_control is + begin + ut3_tester_helper.run_helper.drop_trans_control; + end; + + procedure disabled_suite is + l_suite ut3_develop.ut_suite; + begin + --Arrange + l_suite := ut3_develop.ut_suite(a_object_owner => 'ut3_tester_helper', a_object_name => 'UT_EXAMPLE_TESTS', a_line_no=> 1); + l_suite.path := 'ut3_tester_helper.ut_example_tests'; + l_suite.disabled_flag := ut3_develop.ut_utils.boolean_to_int(true); + l_suite.before_all_list := ut3_develop.ut_executables(ut3_develop.ut_executable('ut3_tester_helper', 'UT_EXAMPLE_TESTS', 'set_g_number_0', ut3_develop.ut_utils.gc_before_all)); + l_suite.after_all_list := ut3_develop.ut_executables(ut3_develop.ut_executable('ut3_tester_helper', 'UT_EXAMPLE_TESTS', 'add_1_to_g_number', ut3_develop.ut_utils.gc_before_all)); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3_develop.ut_test(a_object_owner => 'ut3_tester_helper', 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_develop.ut_test(a_object_owner => 'ut3_tester_helper', a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); + --Act + l_suite.do_execute(); + --Assert + ut.expect(ut3_tester_helper.ut_example_tests.g_number).to_be_null; + ut.expect(l_suite.result).to_equal(ut3_develop.ut_utils.gc_disabled); + ut.expect(l_suite.results_count.disabled_count).to_equal(2); + ut.expect(l_suite.results_count.warnings_count).to_equal(0); + ut.expect(l_suite.results_count.success_count).to_equal(0); + ut.expect(l_suite.results_count.failure_count).to_equal(0); + ut.expect(l_suite.results_count.errored_count).to_equal(0); + end; + + procedure beforeall_errors is + l_suite ut3_develop.ut_suite; + begin + --Arrange + l_suite := ut3_develop.ut_suite(a_object_owner => 'ut3_tester_helper', a_object_name => 'UT_EXAMPLE_TESTS', a_line_no=> 1); + l_suite.path := 'ut3_tester_helper.ut_example_tests'; + l_suite.before_all_list := ut3_develop.ut_executables(ut3_develop.ut_executable('ut3_tester_helper', 'UT_EXAMPLE_TESTS', 'failing_procedure', ut3_develop.ut_utils.gc_before_all)); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3_develop.ut_test(a_object_owner => 'ut3_tester_helper',a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'set_g_number_0', a_line_no=> 1); + --Act + l_suite.do_execute(); + --Assert + ut.expect(ut3_tester_helper.ut_example_tests.g_number).to_be_null; + ut.expect(l_suite.result).to_equal(ut3_develop.ut_utils.gc_error); + ut.expect(l_suite.results_count.disabled_count).to_equal(0); + ut.expect(l_suite.results_count.warnings_count).to_equal(0); + ut.expect(l_suite.results_count.success_count).to_equal(0); + ut.expect(l_suite.results_count.failure_count).to_equal(0); + ut.expect(l_suite.results_count.errored_count).to_equal(1); + end; + + procedure aftereall_errors is + l_suite ut3_develop.ut_suite; + begin + --Arrange + l_suite := ut3_develop.ut_suite(a_object_owner => 'ut3_tester_helper', a_object_name => 'UT_EXAMPLE_TESTS', a_line_no=> 1); + l_suite.path := 'ut3_tester_helper.ut_example_tests'; + l_suite.after_all_list := ut3_develop.ut_executables(ut3_develop.ut_executable('ut3_tester_helper', 'UT_EXAMPLE_TESTS', 'failing_procedure', ut3_develop.ut_utils.gc_after_all)); + + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3_develop.ut_test(a_object_owner => 'ut3_tester_helper', 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_develop.ut_test(a_object_owner => 'ut3_tester_helper', a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); + --Act + l_suite.do_execute(); + --Assert + ut.expect(ut3_tester_helper.ut_example_tests.g_number).to_equal(1); + ut.expect(l_suite.result).to_equal(ut3_develop.ut_utils.gc_success); + ut.expect(l_suite.results_count.disabled_count).to_equal(0); + ut.expect(l_suite.results_count.warnings_count).to_equal(1); + ut.expect(l_suite.results_count.success_count).to_equal(2); + ut.expect(l_suite.results_count.failure_count).to_equal(0); + ut.expect(l_suite.results_count.errored_count).to_equal(0); + end; + + procedure package_without_body is + l_suite ut3_develop.ut_suite; + begin + l_suite := ut3_develop.ut_suite(a_object_owner => USER, a_object_name => 'UT_WITHOUT_BODY', a_line_no=> 1); + l_suite.path := 'UT_WITHOUT_BODY'; + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3_develop.ut_test(a_object_name => 'ut_without_body',a_name => 'test1', a_line_no=> 1); + --Act + l_suite.do_execute(); + --Assert + ut.expect(l_suite.result).to_equal(ut3_develop.ut_utils.gc_error); + end; + + procedure package_with_invalid_body is + l_suite ut3_develop.ut_suite; + begin + l_suite := ut3_develop.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.items.extend; + l_suite.items(l_suite.items.last) := ut3_develop.ut_test(a_object_name => 'ut_with_invalid_body',a_name => 'test1', a_line_no=> 1); + --Act + l_suite.do_execute(); + --Assert + ut.expect(l_suite.result).to_equal(ut3_develop.ut_utils.gc_error); + end; + + procedure rollback_auto is + l_suite ut3_develop.ut_suite; + begin + --Arrange + execute immediate 'delete from ut3_tester_helper.ut$test_table'; + l_suite := ut3_develop.ut_suite(a_object_owner => USER, a_object_name => 'UT_TRANSACTION_CONTROL', a_line_no=> 1); + l_suite.path := 'ut3_tester_helper.ut_transaction_control'; + l_suite.before_all_list := ut3_develop.ut_executables(ut3_develop.ut_executable(USER, 'UT_TRANSACTION_CONTROL', 'setup', ut3_develop.ut_utils.gc_before_all)); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3_develop.ut_test(a_object_owner => USER, a_object_name => 'ut_transaction_control',a_name => 'test', a_line_no=> 1); + l_suite.set_rollback_type(ut3_develop.ut_utils.gc_rollback_auto); + + --Act + l_suite.do_execute(); + + --Assert + ut.expect(ut3_tester_helper.main_helper.get_value(q'[ut3_tester_helper.ut_transaction_control.count_rows('t')]')).to_equal(0); + ut.expect(ut3_tester_helper.main_helper.get_value(q'[ut3_tester_helper.ut_transaction_control.count_rows('s')]')).to_equal(0); + end; + + procedure rollback_auto_on_failure is + begin + ut3_tester_helper.run_helper.test_rollback_type('test_failure', ut3_develop.ut_utils.gc_rollback_auto, equal(0) ); + end; + + procedure rollback_manual is + begin + ut3_tester_helper.run_helper.test_rollback_type('test', ut3_develop.ut_utils.gc_rollback_manual, be_greater_than(0) ); + end; + + procedure rollback_manual_on_failure is + begin + ut3_tester_helper.run_helper.test_rollback_type('test_failure', ut3_develop.ut_utils.gc_rollback_manual, be_greater_than(0) ); + end; + + procedure trim_transaction_invalidators is + l_suite ut3_develop.ut_suite; + begin + --arrange + l_suite := ut3_develop.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS', a_line_no=> 1); + for i in 1 .. 100 loop + l_suite.add_transaction_invalidator('schema_name.package_name.procedure_name'||i); + end loop; + --Act + l_suite.rollback_to_savepoint('dummy_savepoint'); + --Assert + ut.expect(l_suite.warnings.count).to_equal(1); + end; + +end; +/ \ No newline at end of file diff --git a/test/core/test_ut_suite.pks b/test/ut3_tester/core/test_ut_suite.pks similarity index 70% rename from test/core/test_ut_suite.pks rename to test/ut3_tester/core/test_ut_suite.pks index ba8386297..385d00fc7 100644 --- a/test/core/test_ut_suite.pks +++ b/test/ut3_tester/core/test_ut_suite.pks @@ -1,7 +1,7 @@ create or replace package test_ut_suite is --%suite(ut_suite) - --%suitepath(utplsql.core) + --%suitepath(utplsql.ut3_tester.core) --%beforeeach procedure cleanup_package_state; @@ -15,12 +15,21 @@ create or replace package test_ut_suite is --%test(Reports warnings for each test if afterall raises exception) procedure aftereall_errors; + --%beforetest(ut3_tester_helper.run_helper.package_no_body) + --%aftertest(ut3_tester_helper.run_helper.drop_package_no_body) --%test(Fails all tests in package when package has no body) procedure package_without_body; --%test(Fails all tests in package when package body is invalid) procedure package_with_invalid_body; + --%context( rollback_test ) + + --%beforeall + procedure create_trans_control; + --%afterall + procedure drop_trans_control; + --%test(Performs automatic rollback after a suite) procedure rollback_auto; @@ -32,6 +41,11 @@ create or replace package test_ut_suite is --%test(rollback(manual) - disables automatic rollback after a suite even if test fails) procedure rollback_manual_on_failure; + + --%endcontext + + --%test(Transaction invalidators list is trimmed in warnings when too long) + procedure trim_transaction_invalidators; end; / diff --git a/test/ut3_tester/core/test_ut_suite_tag_filter.pkb b/test/ut3_tester/core/test_ut_suite_tag_filter.pkb new file mode 100644 index 000000000..edfb27cfc --- /dev/null +++ b/test/ut3_tester/core/test_ut_suite_tag_filter.pkb @@ -0,0 +1,82 @@ +create or replace package body test_ut_suite_tag_filter is + + procedure test_conversion_to_rpn is + l_postfix ut3_develop.ut_varchar2_list; + l_postfix_string varchar2(4000); + l_input_token ut3_develop.ut_varchar2_list; + begin + l_input_token := ut3_develop.ut_suite_tag_filter.tokenize_tags_string('A'); + l_postfix := ut3_develop.ut_suite_tag_filter.shunt_logical_expression(l_input_token); + l_postfix_string := ut3_develop.ut_utils.table_to_clob(l_postfix,''); + ut.expect(l_postfix_string).to_equal('A'); + + l_input_token := ut3_develop.ut_suite_tag_filter.tokenize_tags_string('A|B'); + l_postfix := ut3_develop.ut_suite_tag_filter.shunt_logical_expression(l_input_token); + l_postfix_string := ut3_develop.ut_utils.table_to_clob(l_postfix,''); + ut.expect(l_postfix_string).to_equal('AB|'); + + l_input_token := ut3_develop.ut_suite_tag_filter.tokenize_tags_string('(a|b)|c&d'); + l_postfix := ut3_develop.ut_suite_tag_filter.shunt_logical_expression(l_input_token); + l_postfix_string := ut3_develop.ut_utils.table_to_clob(l_postfix,''); + ut.expect(l_postfix_string).to_equal('ab|cd&|'); + + l_input_token := ut3_develop.ut_suite_tag_filter.tokenize_tags_string('!a|b'); + l_postfix := ut3_develop.ut_suite_tag_filter.shunt_logical_expression(l_input_token); + l_postfix_string := ut3_develop.ut_utils.table_to_clob(l_postfix,''); + ut.expect(l_postfix_string).to_equal('a!b|'); + end; + + procedure test_conversion_opr_by_opr is + l_postfix ut3_develop.ut_varchar2_list; + l_input_token ut3_develop.ut_varchar2_list; + begin + l_input_token := ut3_develop.ut_varchar2_list('A','B'); + l_postfix := ut3_develop.ut_suite_tag_filter.shunt_logical_expression(l_input_token); + ut.fail('Expected exception but nothing was raised'); + end; + + procedure test_conversion_oprd_by_opd is + l_postfix ut3_develop.ut_varchar2_list; + l_input_token ut3_develop.ut_varchar2_list; + begin + l_input_token := ut3_develop.ut_varchar2_list('|','|'); + l_postfix := ut3_develop.ut_suite_tag_filter.shunt_logical_expression(l_input_token); + ut.fail('Expected exception but nothing was raised'); + end; + + procedure test_conversion_lb_by_oper is + l_postfix ut3_develop.ut_varchar2_list; + l_input_token ut3_develop.ut_varchar2_list; + begin + l_input_token := ut3_develop.ut_varchar2_list('(','A','|','B',')','('); + l_postfix := ut3_develop.ut_suite_tag_filter.shunt_logical_expression(l_input_token); + ut.fail('Expected exception but nothing was raised'); + end; + + procedure test_conversion_rb_by_oprd is + l_postfix ut3_develop.ut_varchar2_list; + l_input_token ut3_develop.ut_varchar2_list; + begin + l_input_token := ut3_develop.ut_varchar2_list(')','A'); + l_postfix := ut3_develop.ut_suite_tag_filter.shunt_logical_expression(l_input_token); + ut.fail('Expected exception but nothing was raised'); + end; + + procedure conv_from_tag_to_sql_filter is + l_sql_filter varchar2(4000); + begin + l_sql_filter := ut3_develop.ut_suite_tag_filter.create_where_filter('test1'); + ut.expect(l_sql_filter).to_equal(q'['test1' member of tags]'); + + l_sql_filter := ut3_develop.ut_suite_tag_filter.create_where_filter('test1|test2'); + ut.expect(l_sql_filter).to_equal(q'[('test1' member of tags or 'test2' member of tags)]'); + + l_sql_filter := ut3_develop.ut_suite_tag_filter.create_where_filter('test1|!test2'); + ut.expect(l_sql_filter).to_equal(q'[('test1' member of tags or not('test2' member of tags))]'); + + l_sql_filter := ut3_develop.ut_suite_tag_filter.create_where_filter('test1&!test2'); + ut.expect(l_sql_filter).to_equal(q'[('test1' member of tags and not('test2' member of tags))]'); + end; + +end test_ut_suite_tag_filter; +/ diff --git a/test/ut3_tester/core/test_ut_suite_tag_filter.pks b/test/ut3_tester/core/test_ut_suite_tag_filter.pks new file mode 100644 index 000000000..0f84b751b --- /dev/null +++ b/test/ut3_tester/core/test_ut_suite_tag_filter.pks @@ -0,0 +1,33 @@ +create or replace package test_ut_suite_tag_filter is + + --%suite(ut_suite_tag_filter) + --%suitepath(utplsql.ut3_tester.core) + + --%context( Conversion to Reverse Polish Notation) + + --%test( Test conversion of expression into Reverse Polish Notation) + procedure test_conversion_to_rpn; + + --%test( Operator is followed by operator) + --%throws(ut3_develop.ut_utils.gc_invalid_tag_expression) + procedure test_conversion_opr_by_opr; + + --%test( Operand is followed by operand) + --%throws(ut3_develop.ut_utils.gc_invalid_tag_expression) + procedure test_conversion_oprd_by_opd; + + --%test( Left Bracket is followed by operator) + --%throws(ut3_develop.ut_utils.gc_invalid_tag_expression) + procedure test_conversion_lb_by_oper; + + --%test( Right Bracket is followed by operand) + --%throws(ut3_develop.ut_utils.gc_invalid_tag_expression) + procedure test_conversion_rb_by_oprd; + + --%endcontext + + --%test( Test conversion of expression from tag into custom where filter for SQL) + procedure conv_from_tag_to_sql_filter; + +end test_ut_suite_tag_filter; +/ diff --git a/test/ut3_tester/core/test_ut_test.pkb b/test/ut3_tester/core/test_ut_test.pkb new file mode 100644 index 000000000..f6f59df08 --- /dev/null +++ b/test/ut3_tester/core/test_ut_test.pkb @@ -0,0 +1,727 @@ +create or replace package body test_ut_test is + + procedure cleanup_package_state is + begin + ut3_tester_helper.ut_example_tests.g_number := null; + end; + + procedure disabled_test is + l_suite ut3_develop.ut_suite; + l_test ut3_develop.ut_test; + begin + --Arrange + l_suite := ut3_develop.ut_suite(a_object_owner => 'ut3_tester_helper', a_object_name => 'ut_example_tests', a_line_no=> 1); + l_suite.path := 'ut3_tester_helper.ut_example_tests'; + l_suite.before_all_list := ut3_develop.ut_executables(ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', 'set_g_number_0', ut3_develop.ut_utils.gc_before_all)); + + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3_develop.ut_test(a_object_owner => 'ut3_tester_helper',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_develop.ut_test(a_object_owner => 'ut3_tester_helper',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_develop.ut_utils.boolean_to_int(true); + --Act + l_suite.do_execute(); + --Assert + ut.expect(ut3_tester_helper.ut_example_tests.g_number).to_equal(1); + ut.expect(l_suite.result).to_equal(ut3_develop.ut_utils.gc_success); + ut.expect(l_suite.results_count.disabled_count).to_equal(1); + ut.expect(l_suite.results_count.warnings_count).to_equal(0); + ut.expect(l_suite.results_count.success_count).to_equal(1); + ut.expect(l_suite.results_count.failure_count).to_equal(0); + ut.expect(l_suite.results_count.errored_count).to_equal(0); + end; + + procedure aftertest_errors is + l_suite ut3_develop.ut_suite; + l_test ut3_develop.ut_test; + begin + --Arrange + l_suite := ut3_develop.ut_suite(a_object_owner => 'ut3_tester_helper', a_object_name => 'ut_example_tests', a_line_no=> 1); + l_suite.path := 'ut3_tester_helper.ut_example_tests'; + l_suite.before_all_list := ut3_develop.ut_executables(ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', 'set_g_number_0', ut3_develop.ut_utils.gc_before_all)); + + l_test := ut3_develop.ut_test(a_object_owner => 'ut3_tester_helper',a_object_name => 'ut_example_tests',a_name => 'add_1_to_g_number', a_line_no=> 1); + l_test.before_test_list := ut3_develop.ut_executables(ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', 'add_1_to_g_number', ut3_develop.ut_utils.gc_before_test)); + l_test.after_test_list := ut3_develop.ut_executables(ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', 'failing_procedure', ut3_develop.ut_utils.gc_after_test)); + 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_develop.ut_test(a_object_owner => 'ut3_tester_helper',a_object_name => 'ut_example_tests',a_name => 'add_1_to_g_number', a_line_no=> 1); + --Act + l_suite.do_execute(); + --Assert + ut.expect(ut3_tester_helper.ut_example_tests.g_number).to_equal(3); + ut.expect(l_suite.result).to_equal(ut3_develop.ut_utils.gc_error); + ut.expect(l_suite.results_count.disabled_count).to_equal(0); + ut.expect(l_suite.results_count.warnings_count).to_equal(0); + ut.expect(l_suite.results_count.success_count).to_equal(1); + ut.expect(l_suite.results_count.failure_count).to_equal(0); + ut.expect(l_suite.results_count.errored_count).to_equal(1); + end; + + procedure aftereach_errors is + l_suite ut3_develop.ut_suite; + l_test ut3_develop.ut_test; + begin + --Arrange + l_suite := ut3_develop.ut_suite(a_object_owner => 'ut3_tester_helper', a_object_name => 'ut_example_tests', a_line_no=> 1); + l_suite.before_all_list := ut3_develop.ut_executables(ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', 'set_g_number_0', ut3_develop.ut_utils.gc_before_all)); + l_test := ut3_develop.ut_test(a_object_owner => 'ut3_tester_helper',a_object_name => 'ut_example_tests',a_name => 'add_1_to_g_number', a_line_no=> 1); + l_test.before_each_list := ut3_develop.ut_executables(ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', 'add_1_to_g_number', ut3_develop.ut_utils.gc_before_each)); + l_test.after_each_list := ut3_develop.ut_executables(ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', 'failing_procedure', ut3_develop.ut_utils.gc_after_each)); + 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_develop.ut_test(a_object_owner => 'ut3_tester_helper',a_object_name => 'ut_example_tests',a_name => 'add_1_to_g_number', a_line_no=> 1); + --Act + l_suite.do_execute(); + --Assert + ut.expect(ut3_tester_helper.ut_example_tests.g_number).to_equal(3); + ut.expect(l_suite.result).to_equal(ut3_develop.ut_utils.gc_error); + ut.expect(l_suite.results_count.disabled_count).to_equal(0); + ut.expect(l_suite.results_count.warnings_count).to_equal(0); + ut.expect(l_suite.results_count.success_count).to_equal(1); + ut.expect(l_suite.results_count.failure_count).to_equal(0); + ut.expect(l_suite.results_count.errored_count).to_equal(1); + end; + + procedure beforetest_errors is + l_suite ut3_develop.ut_suite; + l_test ut3_develop.ut_test; + begin + --Arrange + l_suite := ut3_develop.ut_suite(a_object_owner => 'ut3_tester_helper', a_object_name => 'ut_example_tests', a_line_no=> 1); + l_suite.before_all_list := ut3_develop.ut_executables(ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', 'set_g_number_0', ut3_develop.ut_utils.gc_before_all)); + l_test := ut3_develop.ut_test(a_object_owner =>'ut3_tester_helper',a_object_name => 'ut_example_tests',a_name => 'add_1_to_g_number', a_line_no=> 1); + l_test.before_test_list := ut3_develop.ut_executables(ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', 'failing_procedure', ut3_develop.ut_utils.gc_before_test)); + l_test.after_test_list := ut3_develop.ut_executables(ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', 'add_1_to_g_number', ut3_develop.ut_utils.gc_after_test)); + 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_develop.ut_test(a_object_owner =>'ut3_tester_helper',a_object_name => 'ut_example_tests',a_name => 'add_1_to_g_number', a_line_no=> 1); + --Act + l_suite.do_execute(); + --Assert + ut.expect(ut3_tester_helper.ut_example_tests.g_number).to_equal(2); + ut.expect(l_suite.result).to_equal(ut3_develop.ut_utils.gc_error); + ut.expect(l_suite.results_count.disabled_count).to_equal(0); + ut.expect(l_suite.results_count.warnings_count).to_equal(0); + ut.expect(l_suite.results_count.success_count).to_equal(1); + ut.expect(l_suite.results_count.failure_count).to_equal(0); + ut.expect(l_suite.results_count.errored_count).to_equal(1); + end; + + procedure beforeeach_errors is + l_suite ut3_develop.ut_suite; + l_test ut3_develop.ut_test; + begin + --Arrange + l_suite := ut3_develop.ut_suite(a_object_owner => 'ut3_tester_helper', a_object_name => 'ut_example_tests', a_line_no=> 1); + l_suite.before_all_list := ut3_develop.ut_executables(ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', 'set_g_number_0', ut3_develop.ut_utils.gc_before_all)); + l_test := ut3_develop.ut_test(a_object_owner => 'ut3_tester_helper',a_object_name => 'ut_example_tests',a_name => 'add_1_to_g_number', a_line_no=> 1); + l_test.before_each_list := ut3_develop.ut_executables(ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', 'failing_procedure', ut3_develop.ut_utils.gc_before_each)); + l_test.after_each_list := ut3_develop.ut_executables(ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', 'add_1_to_g_number', ut3_develop.ut_utils.gc_after_each)); + 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_develop.ut_test(a_object_owner => 'ut3_tester_helper',a_object_name => 'ut_example_tests',a_name => 'add_1_to_g_number', a_line_no=> 1); + --Act + l_suite.do_execute(); + --Assert + ut.expect(ut3_tester_helper.ut_example_tests.g_number).to_equal(2); + ut.expect(l_suite.result).to_equal(ut3_develop.ut_utils.gc_error); + ut.expect(l_suite.results_count.disabled_count).to_equal(0); + ut.expect(l_suite.results_count.warnings_count).to_equal(0); + ut.expect(l_suite.results_count.success_count).to_equal(1); + ut.expect(l_suite.results_count.failure_count).to_equal(0); + ut.expect(l_suite.results_count.errored_count).to_equal(1); + end; + + procedure after_each_executed is + --Arrange + l_test ut3_develop.ut_test := ut3_develop.ut_test( + a_object_owner => 'ut3_tester_helper', + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.after_each_list := ut3_develop.ut_executables( + ut3_develop.ut_executable( + 'ut3_tester_helper', + 'ut_example_tests', + 'add_1_to_g_number', + ut3_develop.ut_utils.gc_after_each + ) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3_develop.ut_utils.gc_success); + ut.expect(ut3_tester_helper.ut_example_tests.g_number).to_equal(1); + end; + + procedure after_each_proc_name_invalid is + --Arrange + l_test ut3_develop.ut_test := ut3_develop.ut_test( + a_object_owner => 'ut3_tester_helper', + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.after_each_list := ut3_develop.ut_executables( + ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', 'invalid setup name', ut3_develop.ut_utils.gc_after_each) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3_develop.ut_utils.gc_error); + ut.expect(ut3_tester_helper.ut_example_tests.g_number).to_equal(0); + end; + + procedure after_each_procedure_name_null is + --Arrange + l_test ut3_develop.ut_test := ut3_develop.ut_test( + a_object_owner => 'ut3_tester_helper', + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.after_each_list := ut3_develop.ut_executables( + ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', null, ut3_develop.ut_utils.gc_after_each) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3_develop.ut_utils.gc_error); + ut.expect(ut3_tester_helper.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_develop.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_develop.ut.run('ut_output_tests')); + l_output := ut3_develop.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_develop.ut_test := ut3_develop.ut_test( + a_object_owner => 'ut3_tester_helper', + a_object_name => 'ut_example_tests', + a_name => 'add_1_to_g_number', + a_line_no => null + ); + begin + l_test.before_each_list := ut3_develop.ut_executables(ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', 'set_g_number_0', ut3_develop.ut_utils.gc_before_each)); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3_develop.ut_utils.gc_success); + ut.expect(ut3_tester_helper.ut_example_tests.g_number).to_equal(1); + end; + + + procedure before_each_proc_name_invalid is + --Arrange + l_test ut3_develop.ut_test := ut3_develop.ut_test( + a_object_owner => 'ut3_tester_helper', + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.before_each_list := ut3_develop.ut_executables( + ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', 'invalid setup name', ut3_develop.ut_utils.gc_before_each) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3_develop.ut_utils.gc_error); + ut.expect(ut3_tester_helper.ut_example_tests.g_number).to_be_null; + end; + + procedure before_each_proc_name_null is + --Arrange + l_test ut3_develop.ut_test := ut3_develop.ut_test( + a_object_owner => 'ut3_tester_helper', + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.before_each_list := ut3_develop.ut_executables( + ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', null, ut3_develop.ut_utils.gc_before_each) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3_develop.ut_utils.gc_error); + ut.expect(ut3_tester_helper.ut_example_tests.g_number).to_be_null; + end; + + procedure ignore_savepoint_exception is + pragma autonomous_transaction; + --Arrange + l_test ut3_develop.ut_test := ut3_develop.ut_test( + a_object_owner => 'ut3_tester_helper', + a_object_name => 'ut_example_tests', + a_name => 'ut_commit_test', + a_line_no => null + ); + begin + l_test.rollback_type := ut3_develop.ut_utils.gc_rollback_auto; + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3_develop.ut_utils.gc_success); + end; + + procedure owner_name_invalid is + --Arrange + l_test ut3_develop.ut_test := ut3_develop.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_develop.ut_utils.gc_error); + end; + + procedure create_synonym is + begin + ut3_tester_helper.ut_example_tests.create_synonym; + end; + + procedure drop_synonym is + begin + ut3_tester_helper.ut_example_tests.drop_synonym; + end; + + procedure owner_name_null is + --Arrange + l_test ut3_develop.ut_test := ut3_develop.ut_test( + 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_develop.ut_utils.gc_success); + ut.expect(ut3_tester_helper.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_develop.ut_test := ut3_develop.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_develop.ut_utils.gc_error); + end; + + procedure package_name_invalid is + --Arrange + l_test ut3_develop.ut_test := ut3_develop.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_develop.ut_utils.gc_error); + end; + + procedure package_name_null is + --Arrange + l_test ut3_develop.ut_test := ut3_develop.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_develop.ut_utils.gc_error); + end; + + procedure procedure_name_invalid is + --Arrange + l_test ut3_develop.ut_test := ut3_develop.ut_test( + a_object_owner => 'ut3_tester_helper', + 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_develop.ut_utils.gc_error); + end; + + procedure procedure_name_null is + --Arrange + l_test ut3_develop.ut_test := ut3_develop.ut_test( + a_object_owner => 'ut3_tester_helper', + 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_develop.ut_utils.gc_error); + end; + + procedure before_test_executed is + --Arrange + l_test ut3_develop.ut_test := ut3_develop.ut_test( + a_object_owner => 'ut3_tester_helper', + a_object_name => 'ut_example_tests', + a_name => 'add_1_to_g_number', + a_line_no => null + ); + begin + l_test.before_test_list := ut3_develop.ut_executables(ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', 'set_g_number_0', ut3_develop.ut_utils.gc_before_test)); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3_develop.ut_utils.gc_success); + ut.expect(ut3_tester_helper.ut_example_tests.g_number).to_equal(1); + end; + + procedure before_test_proc_name_invalid is + --Arrange + l_test ut3_develop.ut_test := ut3_develop.ut_test( + a_object_owner => 'ut3_tester_helper', + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.before_test_list := ut3_develop.ut_executables( + ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', 'invalid setup name', ut3_develop.ut_utils.gc_before_test) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3_develop.ut_utils.gc_error); + ut.expect(ut3_tester_helper.ut_example_tests.g_number).to_be_null; + end; + + procedure before_test_proc_name_null is + --Arrange + l_test ut3_develop.ut_test := ut3_develop.ut_test( + a_object_owner => 'ut3_tester_helper', + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.before_test_list := ut3_develop.ut_executables( + ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', null, ut3_develop.ut_utils.gc_before_test) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3_develop.ut_utils.gc_error); + ut.expect(ut3_tester_helper.ut_example_tests.g_number).to_be_null; + end; + + procedure after_test_executed is + --Arrange + l_test ut3_develop.ut_test := ut3_develop.ut_test( + a_object_owner => 'ut3_tester_helper', + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.after_test_list := ut3_develop.ut_executables(ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', 'add_1_to_g_number', ut3_develop.ut_utils.gc_after_test)); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3_develop.ut_utils.gc_success); + ut.expect(ut3_tester_helper.ut_example_tests.g_number).to_equal(1); + end; + + procedure after_test_proce_name_invalid is + --Arrange + l_test ut3_develop.ut_test := ut3_develop.ut_test( + a_object_owner => 'ut3_tester_helper', + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.after_test_list := ut3_develop.ut_executables( + ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', 'invalid procedure name', ut3_develop.ut_utils.gc_after_test) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3_develop.ut_utils.gc_error); + ut.expect(ut3_tester_helper.ut_example_tests.g_number).to_equal(0); + end; + + procedure after_test_proc_name_null is + --Arrange + l_test ut3_develop.ut_test := ut3_develop.ut_test( + a_object_owner => 'ut3_tester_helper', + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.after_test_list := ut3_develop.ut_executables( + ut3_develop.ut_executable('ut3_tester_helper', 'ut_example_tests', null, ut3_develop.ut_utils.gc_after_test) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3_develop.ut_utils.gc_error); + ut.expect(ut3_tester_helper.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_develop.ut_varchar2_list; + l_output clob; + begin + select * bulk collect into l_output_data + from table(ut3_develop.ut.run('ut_output_tests')); + l_output := ut3_develop.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/ut3_tester/core/test_ut_test.pks b/test/ut3_tester/core/test_ut_test.pks new file mode 100644 index 000000000..caf75eb6c --- /dev/null +++ b/test/ut3_tester/core/test_ut_test.pks @@ -0,0 +1,101 @@ +create or replace package test_ut_test is + + --%suite(ut_test) + --%suitepath(utplsql.ut3_tester.core) + + --%beforeeach + procedure cleanup_package_state; + + --%test(Disabled flag for a test skips the tests execution in suite) + procedure disabled_test; + + --%test(Marks test as errored if aftertest raises exception) + procedure aftertest_errors; + + --%test(Marks each test as errored if aftereach raises exception) + procedure aftereach_errors; + + --%test(Marks test as errored if beforetest raises exception) + procedure beforetest_errors; + + --%test(Marks each test as errored if beforeeach raises exception) + 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(Fails 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; + + + procedure create_synonym; + procedure drop_synonym; + + --%test(Runs test as current schema when owner name null) + --%beforetest(create_synonym) + --%aftertest(drop_synonym) + 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/core/test_ut_utils.pkb b/test/ut3_tester/core/test_ut_utils.pkb similarity index 53% rename from test/core/test_ut_utils.pkb rename to test/ut3_tester/core/test_ut_utils.pkb index 326f5a49b..433987c01 100644 --- a/test/core/test_ut_utils.pkb +++ b/test/ut3_tester/core/test_ut_utils.pkb @@ -33,17 +33,17 @@ create or replace package body test_ut_utils is end; - procedure common_clob_to_table_exec(p_clob varchar2, p_delimiter varchar2, p_expected_list ut3.ut_varchar2_list, p_limit number) is + procedure common_clob_to_table_exec(p_clob varchar2, p_delimiter varchar2, p_expected_list ut3_develop.ut_varchar2_list, p_limit number) is begin execute immediate 'declare l_clob clob := '''||p_clob||'''; l_delimiter varchar2(1) := '''||p_delimiter||'''; - l_expected ut3.ut_varchar2_list := :p_expected_list; - l_result ut3.ut_varchar2_list; + l_expected ut3_develop.ut_varchar2_list := :p_expected_list; + l_result ut3_develop.ut_varchar2_list; l_limit integer := '||p_limit||q'[; l_result_str varchar2(32767); l_errors integer := 0; - function compare_element(a_element_id integer, a_expected ut3.ut_varchar2_list, a_actual ut3.ut_varchar2_list) return integer is + function compare_element(a_element_id integer, a_expected ut3_develop.ut_varchar2_list, a_actual ut3_develop.ut_varchar2_list) return integer is begin if a_expected.exists(a_element_id) and a_actual.exists(a_element_id) then if a_expected(a_element_id) = a_actual(a_element_id) or a_expected(a_element_id) is null and a_actual(a_element_id) is null then @@ -63,7 +63,7 @@ create or replace package body test_ut_utils is end; begin --Act - select column_value bulk collect into l_result from table( ut3.ut_utils.clob_to_table(l_clob, l_limit, l_delimiter) ); + select column_value bulk collect into l_result from table( ut3_develop.ut_utils.clob_to_table(l_clob, l_limit, l_delimiter) ); for i in 1 .. l_result.count loop l_result_str := l_result_str||''''||l_result(i)||''''||l_delimiter; end loop; @@ -78,68 +78,68 @@ end;]' using p_expected_list; procedure test_clob_to_table is begin - common_clob_to_table_exec('a,b,c,d', ',', ut3.ut_varchar2_list('a','b','c','d'), 1000); - common_clob_to_table_exec( '', ',', ut3.ut_varchar2_list(), 1000); - common_clob_to_table_exec( '1,b,c,d', '', ut3.ut_varchar2_list('1,b,','c,d'), 4); - common_clob_to_table_exec( 'abcdefg,hijk,axa,a', ',', ut3.ut_varchar2_list('abc','def','g','hij','k','axa','a'), 3); - common_clob_to_table_exec( ',a,,c,d,', ',', ut3.ut_varchar2_list('','a','','c','d',''), 1000); + common_clob_to_table_exec('a,b,c,d', ',', ut3_develop.ut_varchar2_list('a','b','c','d'), 1000); + common_clob_to_table_exec( '', ',', ut3_develop.ut_varchar2_list(), 1000); + common_clob_to_table_exec( '1,b,c,d', '', ut3_develop.ut_varchar2_list('1,b,','c,d'), 4); + common_clob_to_table_exec( 'abcdefg,hijk,axa,a', ',', ut3_develop.ut_varchar2_list('abc','def','g','hij','k','axa','a'), 3); + common_clob_to_table_exec( ',a,,c,d,', ',', ut3_develop.ut_varchar2_list('','a','','c','d',''), 1000); end; procedure test_test_result_to_char is begin - ut.expect(ut3.ut_utils.test_result_to_char(-1),'test unknown').to_equal('Unknown(-1)'); - ut.expect(ut3.ut_utils.test_result_to_char(null),'test unknown').to_equal('Unknown(NULL)'); - ut.expect(ut3.ut_utils.test_result_to_char(ut3.ut_utils.gc_success),'test unknown').to_equal(ut3.ut_utils.gc_success_char); + ut.expect(ut3_develop.ut_utils.test_result_to_char(-1),'test unknown').to_equal('Unknown(-1)'); + ut.expect(ut3_develop.ut_utils.test_result_to_char(null),'test unknown').to_equal('Unknown(NULL)'); + ut.expect(ut3_develop.ut_utils.test_result_to_char(ut3_develop.ut_utils.gc_success),'test unknown').to_equal(ut3_develop.ut_utils.gc_success_char); end; procedure to_string_emptyblob is begin - ut.expect(ut3.ut_data_value_blob(empty_blob()).to_string()).to_equal('EMPTY'); + ut.expect(ut3_develop.ut_data_value_blob(empty_blob()).to_string()).to_equal('EMPTY'); end; procedure to_string_emptyclob is begin - ut.expect(ut3.ut_data_value_clob(empty_clob()).to_string()).to_equal('EMPTY'); + ut.expect(ut3_develop.ut_data_value_clob(empty_clob()).to_string()).to_equal('EMPTY'); end; procedure to_string_nullblob is begin - ut.expect(ut3.ut_data_value_blob(null).to_string()).to_equal('NULL'); + ut.expect(ut3_develop.ut_data_value_blob(null).to_string()).to_equal('NULL'); end; procedure to_string_nullclob is begin - ut.expect(ut3.ut_data_value_clob(null).to_string()).to_equal('NULL'); + ut.expect(ut3_develop.ut_data_value_clob(null).to_string()).to_equal('NULL'); end; procedure to_string_nulldate is begin - ut.expect(ut3.ut_data_value_date(null).to_string()).to_equal('NULL'); + ut.expect(ut3_develop.ut_data_value_date(null).to_string()).to_equal('NULL'); end; procedure to_string_nullnumber is begin - ut.expect(ut3.ut_data_value_number(null).to_string()).to_equal('NULL'); + ut.expect(ut3_develop.ut_data_value_number(null).to_string()).to_equal('NULL'); end; procedure to_string_nulltimestamp is begin - ut.expect(ut3.ut_data_value_timestamp(null).to_string()).to_equal('NULL'); + ut.expect(ut3_develop.ut_data_value_timestamp(null).to_string()).to_equal('NULL'); end; procedure to_string_nulltimestamp_ltz is begin - ut.expect(ut3.ut_data_value_timestamp_ltz(null).to_string()).to_equal('NULL'); + ut.expect(ut3_develop.ut_data_value_timestamp_ltz(null).to_string()).to_equal('NULL'); end; procedure to_string_nulltimestamp_tz is begin - ut.expect(ut3.ut_data_value_timestamp_tz(null).to_string()).to_equal('NULL'); + ut.expect(ut3_develop.ut_data_value_timestamp_tz(null).to_string()).to_equal('NULL'); end; procedure to_string_nullvarchar2 is begin - ut.expect(ut3.ut_data_value_varchar2(null).to_string()).to_equal('NULL'); + ut.expect(ut3_develop.ut_data_value_varchar2(null).to_string()).to_equal('NULL'); end; procedure to_string_blob is @@ -147,49 +147,49 @@ end;]' using p_expected_list; l_value blob := utl_raw.cast_to_raw(l_text); l_expected varchar2(32767) := ''''||rawtohex(l_value)||''''; begin - ut.expect(ut3.ut_data_value_blob(l_value).to_string()).to_equal(l_expected); + ut.expect(ut3_develop.ut_data_value_blob(l_value).to_string()).to_equal(l_expected); end; procedure to_string_clob is l_value clob := 'A test char'; l_expected varchar2(32767) := ''''||l_value||''''; begin - ut.expect(ut3.ut_data_value_clob(l_value).to_string()).to_equal(l_expected); + ut.expect(ut3_develop.ut_data_value_clob(l_value).to_string()).to_equal(l_expected); end; procedure to_string_date is l_value date := to_date('2016-12-31 23:59:59', 'yyyy-mm-dd hh24:mi:ss'); - l_expected varchar2(100) := '2016-12-31T23:59:59'; + l_expected varchar2(100) := ' 2016-12-31T23:59:59'; begin - ut.expect(ut3.ut_data_value_date(l_value).to_string()).to_equal(l_expected); + ut.expect(ut3_develop.ut_data_value_date(l_value).to_string()).to_equal(l_expected); end; procedure to_string_timestamp is l_value timestamp(9) := to_timestamp('2016-12-31 23:59:59.123456789', 'yyyy-mm-dd hh24:mi:ss.ff'); - l_expected varchar2(100) := '2016-12-31T23:59:59'||gc_delimiter||'123456789'; + l_expected varchar2(100) := ' 2016-12-31T23:59:59'||gc_delimiter||'123456789'; begin - ut.expect(ut3.ut_data_value_timestamp(l_value).to_string()).to_equal(l_expected); + ut.expect(ut3_develop.ut_data_value_timestamp(l_value).to_string()).to_equal(l_expected); end; procedure to_string_timestamp_ltz is l_value timestamp(9) with local time zone := to_timestamp('2016-12-31 23:59:59.123456789', 'yyyy-mm-dd hh24:mi:ss.ff'); - l_expected varchar2(100) := '2016-12-31T23:59:59'||gc_delimiter||'123456789'; + l_expected varchar2(100) := ' 2016-12-31T23:59:59'||gc_delimiter||'123456789'; begin - ut.expect(ut3.ut_data_value_timestamp_ltz(l_value).to_string()).to_equal(l_expected); + ut.expect(ut3_develop.ut_data_value_timestamp_ltz(l_value).to_string()).to_equal(l_expected); end; procedure to_string_timestamp_tz is l_value timestamp(9) with time zone := to_timestamp_tz('2016-12-31 23:59:59.123456789 -8:00', 'yyyy-mm-dd hh24:mi:ss.ff tzh:tzm'); - l_expected varchar2(100) := '2016-12-31T23:59:59'||gc_delimiter||'123456789 -08:00'; + l_expected varchar2(100) := ' 2016-12-31T23:59:59'||gc_delimiter||'123456789 -08:00'; begin - ut.expect(ut3.ut_data_value_timestamp_tz(l_value).to_string()).to_equal(l_expected); + ut.expect(ut3_develop.ut_data_value_timestamp_tz(l_value).to_string()).to_equal(l_expected); end; procedure to_string_varchar2 is l_value varchar2(20) := 'A test char'; l_expected varchar2(100) := ''''||l_value||''''; begin - ut.expect(ut3.ut_data_value_varchar2(l_value).to_string()).to_equal(l_expected); + ut.expect(ut3_develop.ut_data_value_varchar2(l_value).to_string()).to_equal(l_expected); end; procedure to_string_verybigblob is @@ -197,53 +197,53 @@ end;]' using p_expected_list; l_value blob; begin l_value := clob_to_blob(l_text); - ut.expect(length(ut3.ut_data_value_blob(l_value).to_string())).to_equal(ut3.ut_utils.gc_max_output_string_length); - ut.expect(ut3.ut_data_value_blob(l_value).to_string()).to_be_like('%'||ut3.ut_utils.gc_more_data_string); + ut.expect(length(ut3_develop.ut_data_value_blob(l_value).to_string())).to_equal(ut3_develop.ut_utils.gc_max_output_string_length); + ut.expect(ut3_develop.ut_data_value_blob(l_value).to_string()).to_be_like('%'||ut3_develop.ut_utils.gc_more_data_string); end; procedure to_string_verybigclob is l_value clob := lpad('A test char',32767,'1')||lpad('1',32767,'1'); begin - ut.expect(length(ut3.ut_data_value_clob(l_value).to_string())).to_equal(ut3.ut_utils.gc_max_output_string_length); - ut.expect(ut3.ut_data_value_clob(l_value).to_string()).to_be_like('%'||ut3.ut_utils.gc_more_data_string); + ut.expect(length(ut3_develop.ut_data_value_clob(l_value).to_string())).to_equal(ut3_develop.ut_utils.gc_max_output_string_length); + ut.expect(ut3_develop.ut_data_value_clob(l_value).to_string()).to_be_like('%'||ut3_develop.ut_utils.gc_more_data_string); end; procedure to_string_verybignumber is l_value number := 1234567890123456789012345678901234567890; l_expected varchar2(100) := '1234567890123456789012345678901234567890'; begin - ut.expect(ut3.ut_data_value_number(l_value).to_string()).to_equal(l_expected); + ut.expect(ut3_develop.ut_data_value_number(l_value).to_string()).to_equal(l_expected); end; procedure to_string_verybigvarchar2 is l_value varchar2(32767) := lpad('A test char',32767,'1'); l_result varchar2(32767); begin - ut.expect(length(ut3.ut_data_value_varchar2(l_value).to_string())).to_equal(ut3.ut_utils.gc_max_output_string_length); - ut.expect(ut3.ut_data_value_varchar2(l_value).to_string()).to_be_like('%'||ut3.ut_utils.gc_more_data_string); + ut.expect(length(ut3_develop.ut_data_value_varchar2(l_value).to_string())).to_equal(ut3_develop.ut_utils.gc_max_output_string_length); + ut.expect(ut3_develop.ut_data_value_varchar2(l_value).to_string()).to_be_like('%'||ut3_develop.ut_utils.gc_more_data_string); end; procedure to_string_verysmallnumber is l_value number := 0.123456789012345678901234567890123456789; l_expected varchar2(100) := gc_delimiter||'123456789012345678901234567890123456789'; begin - ut.expect(ut3.ut_data_value_number(l_value).to_string()).to_equal(l_expected); + ut.expect(ut3_develop.ut_data_value_number(l_value).to_string()).to_equal(l_expected); end; procedure test_table_to_clob is - procedure exec_table_to_clob(a_list ut3.ut_varchar2_list, a_delimiter varchar2, a_expected clob) is + procedure exec_table_to_clob(a_list ut3_develop.ut_varchar2_list, a_delimiter varchar2, a_expected clob) is l_result clob; begin - l_result := ut3.ut_utils.table_to_clob(a_list, a_delimiter); + l_result := ut3_develop.ut_utils.table_to_clob(a_list, a_delimiter); ut.expect(l_result).to_equal(a_expected, a_nulls_are_equal => true); end; begin exec_table_to_clob(null, ',', ''); - exec_table_to_clob(ut3.ut_varchar2_list(), ',', ''); - exec_table_to_clob(ut3.ut_varchar2_list('a', 'b', 'c', 'd'), ',', 'a,b,c,d'); - exec_table_to_clob(ut3.ut_varchar2_list('1,b,', 'c,d'), ',', '1,b,,c,d'); - exec_table_to_clob(ut3.ut_varchar2_list('', 'a', '', 'c', 'd', ''), ',', ',a,,c,d,'); + exec_table_to_clob(ut3_develop.ut_varchar2_list(), ',', ''); + exec_table_to_clob(ut3_develop.ut_varchar2_list('a', 'b', 'c', 'd'), ',', 'a,b,c,d'); + exec_table_to_clob(ut3_develop.ut_varchar2_list('1,b,', 'c,d'), ',', '1,b,,c,d'); + exec_table_to_clob(ut3_develop.ut_varchar2_list('', 'a', '', 'c', 'd', ''), ',', ',a,,c,d,'); end; procedure test_append_with_multibyte is @@ -252,13 +252,13 @@ end;]' using p_expected_list; begin l_lines := sys.dbms_preprocessor.get_post_processed_source( object_type => 'PACKAGE', - schema_name => user, + schema_name => sys_context('USERENV', 'CURRENT_USER'), object_name => 'TST_CHARS' ); for i in 1..l_lines.count loop l_result := null; - ut3.ut_utils.append_to_clob(l_result, l_lines(i)); + ut3_develop.ut_utils.append_to_clob(l_result, l_lines(i)); --Assert ut.expect(dbms_lob.getlength(l_result),'Error for index '||i).to_equal(dbms_lob.getlength(l_lines(i))); @@ -289,21 +289,21 @@ end;'; l_singlebyte_string_max_size varchar2(32767 char) := rpad('x',l_varchar2_byte_limit,'x'); l_twobyte_character char(1 char) := '�?'; l_clob_multibyte clob := l_twobyte_character||l_singlebyte_string_max_size; --here we have 32769(2+32767) bytes and 32768 chars - l_expected ut3.ut_varchar2_list := ut3.ut_varchar2_list(); - l_result ut3.ut_varchar2_list; + l_expected ut3_develop.ut_varchar2_list := ut3_develop.ut_varchar2_list(); + l_result ut3_develop.ut_varchar2_list; begin l_expected.extend(1); l_expected(1) := l_twobyte_character||substr(l_singlebyte_string_max_size,1,l_workaround_byte_limit-1); --Act - l_result := ut3.ut_utils.clob_to_table(l_clob_multibyte); + l_result := ut3_develop.ut_utils.clob_to_table(l_clob_multibyte); --Assert ut.expect(l_result(1)).to_equal(l_expected(1)); end; procedure test_to_version_split is - l_version ut3.ut_utils.t_version; + l_version ut3_develop.ut_utils.t_version; begin - l_version := ut3.ut_utils.to_version('v034.0.0456.0333'); + l_version := ut3_develop.ut_utils.to_version('v034.0.0456.0333'); ut.expect(l_version.major).to_equal(34); ut.expect(l_version.minor).to_equal(0); ut.expect(l_version.bugfix).to_equal(456); @@ -312,62 +312,62 @@ end;'; procedure test_trim_list_elements is - l_list_to_be_equal ut3.ut_varchar2_list := ut3.ut_varchar2_list('hello', 'world', 'okay'); - l_list ut3.ut_varchar2_list := ut3.ut_varchar2_list(' hello ', chr(9)||'world ', 'okay'); + l_list_to_be_equal ut3_develop.ut_varchar2_list := ut3_develop.ut_varchar2_list('hello', 'world', 'okay'); + l_list ut3_develop.ut_varchar2_list := ut3_develop.ut_varchar2_list(' hello ', chr(9)||'world ', 'okay'); begin --Act - l_list := ut3.ut_utils.trim_list_elements(l_list); + l_list := ut3_develop.ut_utils.trim_list_elements(l_list); --Assert ut.expect(anydata.convertcollection(l_list)).to_equal(anydata.convertcollection(l_list_to_be_equal)); end; procedure trim_list_elemts_null_collect is - l_list_to_be_null ut3.ut_varchar2_list; + l_list_to_be_null ut3_develop.ut_varchar2_list; begin --Act - l_list_to_be_null := ut3.ut_utils.trim_list_elements(l_list_to_be_null); + l_list_to_be_null := ut3_develop.ut_utils.trim_list_elements(l_list_to_be_null); --Assert ut.expect(anydata.convertcollection(l_list_to_be_null)).to_be_null; end; procedure trim_list_elemts_empty_collect is - l_list_to_be_empty ut3.ut_varchar2_list := ut3.ut_varchar2_list(); + l_list_to_be_empty ut3_develop.ut_varchar2_list := ut3_develop.ut_varchar2_list(); begin --Act - l_list_to_be_empty := ut3.ut_utils.trim_list_elements(l_list_to_be_empty); + l_list_to_be_empty := ut3_develop.ut_utils.trim_list_elements(l_list_to_be_empty); --Assert ut.expect(anydata.convertcollection(l_list_to_be_empty)).to_be_empty; end; procedure test_filter_list is - l_list_to_be_equal ut3.ut_varchar2_list := ut3.ut_varchar2_list('-12458', '8956', '789'); - l_list ut3.ut_varchar2_list := ut3.ut_varchar2_list('-12458', '8956', 'okay', null,'458963', '789'); + l_list_to_be_equal ut3_develop.ut_varchar2_list := ut3_develop.ut_varchar2_list('-12458', '8956', '789'); + l_list ut3_develop.ut_varchar2_list := ut3_develop.ut_varchar2_list('-12458', '8956', 'okay', null,'458963', '789'); begin --Act - l_list := ut3.ut_utils.filter_list(l_list, '^-?[[:digit:]]{1,5}$'); + l_list := ut3_develop.ut_utils.filter_list(l_list, '^-?[[:digit:]]{1,5}$'); --Assert ut.expect(anydata.convertcollection(l_list)).to_equal(anydata.convertcollection(l_list_to_be_equal)); end; procedure filter_list_null_collection is - l_list_to_be_null ut3.ut_varchar2_list; + l_list_to_be_null ut3_develop.ut_varchar2_list; begin --Act - l_list_to_be_null := ut3.ut_utils.filter_list(l_list_to_be_null, '^-?[[:digit:]]{1,5}$'); + l_list_to_be_null := ut3_develop.ut_utils.filter_list(l_list_to_be_null, '^-?[[:digit:]]{1,5}$'); --Assert ut.expect(anydata.convertcollection(l_list_to_be_null)).to_be_null; end; procedure filter_list_empty_collection is - l_list_to_be_empty ut3.ut_varchar2_list := ut3.ut_varchar2_list(); + l_list_to_be_empty ut3_develop.ut_varchar2_list := ut3_develop.ut_varchar2_list(); begin --Act - l_list_to_be_empty := ut3.ut_utils.filter_list(l_list_to_be_empty, '^-?[[:digit:]]{1,5}$'); + l_list_to_be_empty := ut3_develop.ut_utils.filter_list(l_list_to_be_empty, '^-?[[:digit:]]{1,5}$'); --Assert ut.expect(anydata.convertcollection(l_list_to_be_empty)).to_be_empty; end; @@ -428,9 +428,84 @@ create or replace package dummy as end; ]'; --Act - l_actual := ut3.ut_utils.replace_multiline_comments(l_source); + l_actual := ut3_develop.ut_utils.replace_multiline_comments(l_source); --Assert ut.expect(l_actual).to_equal(l_expected); end; + + procedure int_conv_ds_sec is + l_expected varchar2(100) := '1 second'; + l_actual varchar2(200) := ut3_develop.ut_utils.interval_to_text(interval '1' second); + begin + ut.expect(l_expected).to_equal(l_actual); + end; + + procedure int_conv_ds_minute is + l_expected varchar2(100) := '1 minute'; + l_actual varchar2(200) := ut3_develop.ut_utils.interval_to_text(interval '1' minute); + begin + ut.expect(l_expected).to_equal(l_actual); + end; + + procedure int_conv_ds_hour is + l_expected varchar2(100) := '1 hour'; + l_actual varchar2(200) := ut3_develop.ut_utils.interval_to_text(interval '1' hour); + begin + ut.expect(l_expected).to_equal(l_actual); + end; + + procedure int_conv_ds_day is + l_expected varchar2(100) := '1 day'; + l_actual varchar2(200) := ut3_develop.ut_utils.interval_to_text(interval '1' day); + begin + ut.expect(l_expected).to_equal(l_actual); + end; + + procedure int_conv_ds_date is + l_expected varchar2(100) := '2 days 3 hours 4 minutes 11.333 seconds'; + l_actual varchar2(200) := ut3_develop.ut_utils.interval_to_text(INTERVAL '2 3:04:11.333' DAY TO SECOND); + begin + ut.expect(l_expected).to_equal(l_actual); + end; + + procedure int_conv_ym_year is + l_expected varchar2(100) := '1 year'; + l_actual varchar2(200) := ut3_develop.ut_utils.interval_to_text(interval '1' year); + begin + ut.expect(l_expected).to_equal(l_actual); + end; + + procedure int_conv_ym_month is + l_expected varchar2(100) := '1 month'; + l_actual varchar2(200) := ut3_develop.ut_utils.interval_to_text(interval '1' month); + begin + ut.expect(l_expected).to_equal(l_actual); + end; + + procedure int_conv_ym_date is + l_expected varchar2(100) := '1 year 2 months'; + l_actual varchar2(200) := ut3_develop.ut_utils.interval_to_text(INTERVAL '1-2' YEAR TO MONTH); + begin + ut.expect(l_expected).to_equal(l_actual); + end; + + procedure convert_collection_multibyte is + l_input ut3_develop.ut_varchar2_list; + l_max_len integer := ut3_develop.ut_utils.gc_max_storage_varchar2_len; + begin + --Arrange + l_input := ut3_develop.ut_varchar2_list( rpad( '❤', l_max_len, 'a' ) ); + ut.expect( lengthb( l_input( 1 ) ) ).to_be_greater_than(l_max_len); + + --Act + ut.expect( lengthb( ut3_develop.ut_utils.convert_collection(l_input)(1) ) ).to_be_less_or_equal(l_max_len); + end; + + procedure lengthb_gives_length_in_bytes is + l_clob clob; + begin + l_clob := '❤'; + ut.expect(ut3_develop.ut_utils.lengthb_clob(l_clob)).to_be_greater_than(1); + end; end test_ut_utils; / diff --git a/test/core/test_ut_utils.pks b/test/ut3_tester/core/test_ut_utils.pks similarity index 75% rename from test/core/test_ut_utils.pks rename to test/ut3_tester/core/test_ut_utils.pks index 8452f84c3..ca2e7b304 100644 --- a/test/core/test_ut_utils.pks +++ b/test/ut3_tester/core/test_ut_utils.pks @@ -1,7 +1,7 @@ create or replace package test_ut_utils is --%suite(ut_utils) - --%suitepath(utplsql.core) + --%suitepath(utplsql.ut3_tester.core) function get_numeric_delimiter return varchar2; @@ -128,5 +128,39 @@ create or replace package test_ut_utils is --%test(replace_multiline_comments - replaces multi-line comments with empty lines) procedure replace_multiline_comments; + --%context(interval_converter_to_strin) + + --%test(returns text representation of interval day to second for 1 second interval) + procedure int_conv_ds_sec; + + --%test(returns text representation of interval day to second for 1 minute interval) + procedure int_conv_ds_minute; + + --%test(returns text representation of interval day to second for 1 hour interval) + procedure int_conv_ds_hour; + + --%test(returns text representation of interval day to second for 1 day interval) + procedure int_conv_ds_day; + + --%test(returns text representation of interval day to second for combination interval) + procedure int_conv_ds_date; + + --%test(returns text representation of interval year to month for 1 year interval) + procedure int_conv_ym_year; + + --%test(returns text representation of interval year to month for 1 month interval) + procedure int_conv_ym_month; + + --%test(returns text representation of interval year to month for custom interval) + procedure int_conv_ym_date; + + --%endcontext + + --%test(convert_collection does not fail on multibyte strings - Issue #1245 ) + procedure convert_collection_multibyte; + + --%test(lengthb returns length of a CLOB in bytes ) + procedure lengthb_gives_length_in_bytes; + end test_ut_utils; / diff --git a/test/ut3_tester_helper/annotation_cache_helper.pkb b/test/ut3_tester_helper/annotation_cache_helper.pkb new file mode 100644 index 000000000..0715b6af1 --- /dev/null +++ b/test/ut3_tester_helper/annotation_cache_helper.pkb @@ -0,0 +1,169 @@ +create or replace package body annotation_cache_helper as + + procedure setup_two_suites is + pragma autonomous_transaction; + begin + execute immediate + 'create or replace package ut3_cache_test_owner.granted_test_suite authid definer is + --%suite + + --%test + procedure test1; + --%test + procedure test2; + end;'; + + execute immediate + 'create or replace package body ut3_cache_test_owner.granted_test_suite is + procedure test1 is begin ut3_develop.ut.expect( 1 ).to_equal( 1 ); end; + procedure test2 is begin ut3_develop.ut.expect( 1 ).to_equal( 1 ); end; + end;'; + execute immediate + 'create or replace package ut3_cache_test_owner.not_granted_test_suite authid definer is + --%suite + + --%test + procedure test1; + --%test + procedure test2; + end;'; + execute immediate + 'create or replace package body ut3_cache_test_owner.not_granted_test_suite is + procedure test1 is begin ut3_develop.ut.expect( 1 ).to_equal( 1 ); end; + procedure test2 is begin ut3_develop.ut.expect( 1 ).to_equal( 1 ); end; + end;'; + + execute immediate + 'grant execute on ut3_cache_test_owner.granted_test_suite to + ut3_execute_any_proc_user, ut3_select_any_table_user, ut3_select_catalog_user, ut3_no_extra_priv_user'; + end; + + procedure revoke_granted_suite is + pragma autonomous_transaction; + begin + execute immediate + 'revoke execute on ut3_cache_test_owner.granted_test_suite from + ut3_execute_any_proc_user, ut3_select_any_table_user, ut3_select_catalog_user, ut3_no_extra_priv_user'; + exception + when others then + null; + end; + + + procedure add_new_suite is + pragma autonomous_transaction; + begin + execute immediate + 'create or replace package ut3_cache_test_owner.new_suite authid definer is + --%suite + + --%test + procedure test1; + --%test + procedure test2; + end;'; + + execute immediate + 'create or replace package body ut3_cache_test_owner.new_suite is + procedure test1 is begin ut3_develop.ut.expect( 1 ).to_equal( 1 ); end; + procedure test2 is begin ut3_develop.ut.expect( 1 ).to_equal( 1 ); end; + end;'; + execute immediate + 'grant execute on ut3_cache_test_owner.new_suite to + ut3_execute_any_proc_user, ut3_select_any_table_user, ut3_select_catalog_user, ut3_no_extra_priv_user'; + end; + + procedure cleanup_two_suites is + pragma autonomous_transaction; + begin + begin + execute immediate 'drop package ut3_cache_test_owner.not_granted_test_suite'; + exception + when others then + null; + end; + begin + execute immediate 'drop package ut3_cache_test_owner.granted_test_suite'; + exception + when others then + null; + end; + end; + + procedure cleanup_new_suite is + pragma autonomous_transaction; + begin + execute immediate 'drop package ut3_cache_test_owner.new_suite'; + exception + when others then + null; + end; + + procedure purge_annotation_cache is + begin + ut3_develop.ut_runner.purge_cache( 'UT3_CACHE_TEST_OWNER' ); + end; + + + procedure disable_ddl_trigger is + pragma autonomous_transaction; + begin + execute immediate 'alter trigger ut3_develop.ut_trigger_annotation_parsing disable'; + execute immediate 'begin ut3_develop.ut_trigger_check.is_alive( ); end;'; + end; + + procedure enable_ddl_trigger is + pragma autonomous_transaction; + begin + execute immediate 'alter trigger ut3_develop.ut_trigger_annotation_parsing enable'; + end; + + procedure create_run_function_for_user(a_user varchar2) is + pragma autonomous_transaction; + begin + execute immediate + 'create or replace function ' || a_user || '.call_ut_run return clob is + l_data ut3_develop.ut_varchar2_list; + l_results clob; + begin + select * bulk collect into l_data from table (ut3_develop.ut.run( ''ut3_cache_test_owner'' )); + return ut3_tester_helper.main_helper.table_to_clob( l_data ); + end; + '; + execute immediate 'grant execute on ' || a_user || '.call_ut_run to public '; + end; + + procedure drop_run_function_for_user(a_user varchar2) is + pragma autonomous_transaction; + begin + execute immediate 'drop function ' || a_user || '.call_ut_run'; + end; + + procedure create_run_function_for_users is + begin + create_run_function_for_user( 'ut3_no_extra_priv_user' ); + create_run_function_for_user( 'ut3_select_catalog_user' ); + create_run_function_for_user( 'ut3_select_any_table_user' ); + create_run_function_for_user( 'ut3_execute_any_proc_user' ); + create_run_function_for_user( 'ut3_cache_test_owner' ); + create_run_function_for_user( 'ut3_develop' ); + end; + + procedure drop_run_function_for_users is + begin + drop_run_function_for_user( 'ut3_no_extra_priv_user' ); + drop_run_function_for_user( 'ut3_select_catalog_user' ); + drop_run_function_for_user( 'ut3_select_any_table_user' ); + drop_run_function_for_user( 'ut3_execute_any_proc_user' ); + drop_run_function_for_user( 'ut3_cache_test_owner' ); + drop_run_function_for_user( 'ut3_develop' ); + end; + + function run_tests_as(a_user varchar2) return clob is + l_results clob; + begin + execute immediate 'begin :x := '||a_user||'.call_ut_run; end;' using out l_results; + return l_results; + end; +end; +/ \ No newline at end of file diff --git a/test/ut3_tester_helper/annotation_cache_helper.pks b/test/ut3_tester_helper/annotation_cache_helper.pks new file mode 100644 index 000000000..d6ab1f8e2 --- /dev/null +++ b/test/ut3_tester_helper/annotation_cache_helper.pks @@ -0,0 +1,21 @@ +create or replace package annotation_cache_helper as + + procedure setup_two_suites; + procedure add_new_suite; + procedure revoke_granted_suite; + + procedure cleanup_two_suites; + procedure cleanup_new_suite; + + procedure purge_annotation_cache; + + procedure disable_ddl_trigger; + procedure enable_ddl_trigger; + + procedure create_run_function_for_users; + procedure drop_run_function_for_users; + + function run_tests_as(a_user varchar2) return clob; + +end; +/ \ No newline at end of file diff --git a/test/ut3_tester_helper/coverage_helper.pkb b/test/ut3_tester_helper/coverage_helper.pkb new file mode 100644 index 000000000..ef14c586f --- /dev/null +++ b/test/ut3_tester_helper/coverage_helper.pkb @@ -0,0 +1,577 @@ +create or replace package body coverage_helper is + + g_job_no integer := 0; + + function block_coverage_available return boolean is + begin + $if dbms_db_version.version = 12 and dbms_db_version.release >= 2 or dbms_db_version.version > 12 $then + return true; + $else + return false; + $end + end; + + function covered_package_name return varchar2 is + begin + $if dbms_db_version.version = 12 and dbms_db_version.release >= 2 or dbms_db_version.version > 12 $then + return 'dummy_coverage_package_with_an_amazingly_long_name_that_you_would_not_think_of_in_real_life_project_because_its_simply_too_long'; + $else + return 'dummy_coverage'; + $end + end; + + function substitute_covered_package( a_text varchar2, a_substitution varchar2 ) return varchar2 is + begin + return replace( replace( a_text, a_substitution, covered_package_name() ), upper(a_substitution), upper(covered_package_name()) ); + end; + + procedure set_develop_mode is + begin + ut3_develop.ut_coverage.set_develop_mode(true); + end; + + + procedure create_dummy_coverage is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package ut3_develop.]'||covered_package_name||q'[ is + procedure do_stuff(i_input in number); + end;]'; + + execute immediate q'[create or replace package body ut3_develop.]'||covered_package_name||q'[ is + procedure do_stuff(i_input in number) is + begin + if i_input = 2 then dbms_output.put_line('should not get here'); elsif i_input = 1 then dbms_output.put_line('should get here'); + else + dbms_output.put_line('should not get here'); + end if; + end; + end;]'; + + execute immediate q'[create or replace package ut3_develop.some_other_package is + procedure do_stuff(i_input in number); + end;]'; + + execute immediate q'[create or replace package body ut3_develop.some_other_package is + procedure do_stuff(i_input in number) is + begin + if i_input = 2 then dbms_output.put_line('should not get here'); elsif i_input = 1 then dbms_output.put_line('should get here'); + else + dbms_output.put_line('should not get here'); + end if; + end; + end;]'; + + execute immediate q'[create or replace package ut3_develop.test_dummy_coverage is + --%suite(dummy coverage test) + --%suitepath(coverage_testing) + + --%test + procedure test_do_stuff; + + --%test + procedure zero_coverage; + end;]'; + + execute immediate q'[create or replace package body ut3_develop.test_dummy_coverage is + procedure test_do_stuff is + begin + ]'||covered_package_name||q'[.do_stuff(1); + ut.expect(1).to_equal(1); + end; + procedure zero_coverage is + begin + null; + end; + end;]'; + + end; + + procedure drop_dummy_coverage is + pragma autonomous_transaction; + begin + begin execute immediate q'[drop package ut3_develop.test_dummy_coverage]'; exception when others then null; end; + begin execute immediate q'[drop package ut3_develop.some_other_package]'; exception when others then null; end; + begin execute immediate q'[drop package ut3_develop.]'||covered_package_name; exception when others then null; end; + end; + + + procedure create_dummy_coverage_1 is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package ut3_develop.dummy_coverage_1 is + procedure do_stuff; + end;]'; + + execute immediate q'[create or replace package body ut3_develop.dummy_coverage_1 is + procedure do_stuff is + begin + if 1 = 2 then + dbms_output.put_line('should not get here'); + else + dbms_output.put_line('should get here'); + end if; + end; + end;]'; + + execute immediate q'[create or replace package ut3_develop.test_dummy_coverage_1 is + --%suite(dummy coverage test 1) + --%suitepath(coverage_testing) + + --%test + procedure test_do_stuff; + end;]'; + + execute immediate q'[create or replace package body ut3_develop.test_dummy_coverage_1 is + procedure test_do_stuff is + begin + dummy_coverage_1.do_stuff; + end; + + end;]'; + end; + + procedure drop_dummy_coverage_1 is + pragma autonomous_transaction; + begin + begin execute immediate q'[drop package ut3_develop.dummy_coverage_1]'; exception when others then null; end; + begin execute immediate q'[drop package ut3_develop.test_dummy_coverage_1]'; exception when others then null; end; + end; + + procedure create_cov_with_dbms_stats is + pragma autonomous_transaction; + begin + execute immediate q'[create table ut3_develop.table_to_test_stats as select * from user_objects]'; + + execute immediate q'[create or replace package ut3_develop.stats is + procedure gather; + end;]'; + + execute immediate q'[create or replace package body ut3_develop.stats is + procedure gather is + begin + dbms_Stats.gather_table_stats('UT3_DEVELOP','TABLE_TO_TEST_STATS'); + end; + end;]'; + + execute immediate q'[create or replace package ut3_develop.test_stats is + --%suite(stats gathering coverage test) + --%suitepath(coverage_testing) + + --%test + procedure test_stats_gather; + + end;]'; + + execute immediate q'[create or replace package body ut3_develop.test_stats is + procedure test_stats_gather is + begin + stats.gather; + ut.expect(1).to_equal(1); + end; + end;]'; + + end; + + procedure create_regex_dummy_for_schema(p_schema in varchar2) is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package ]'||p_schema||q'[.regex_dummy_cov is + procedure do_stuff(i_input in number); + end;]'; + + execute immediate q'[create or replace package body ]'||p_schema||q'[.regex_dummy_cov is + procedure do_stuff(i_input in number) is + begin + if i_input = 2 then dbms_output.put_line('should not get here'); elsif i_input = 1 then dbms_output.put_line('should get here'); + else + dbms_output.put_line('should not get here'); + end if; + end; + end;]'; + + execute immediate q'[create or replace package ]'||p_schema||q'[.test_regex_dummy_cov is + --%suite(dummy coverage test) + --%suitepath(coverage_testing) + + --%test + procedure test_do_stuff; + + --%test + procedure zero_coverage; + end;]'; + + execute immediate q'[create or replace package body ]'||p_schema||q'[.test_regex_dummy_cov is + procedure test_do_stuff is + begin + regex_dummy_cov.do_stuff(1); + ut.expect(1).to_equal(1); + end; + procedure zero_coverage is + begin + null; + end; + end;]'; + end; + + procedure create_regex_dummy_obj is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package ut3_develop.regex123_dummy_cov is + procedure do_stuff(i_input in number); + end;]'; + + execute immediate q'[create or replace package body ut3_develop.regex123_dummy_cov is + procedure do_stuff(i_input in number) is + begin + if i_input = 2 then dbms_output.put_line('should not get here'); elsif i_input = 1 then dbms_output.put_line('should get here'); + else + dbms_output.put_line('should not get here'); + end if; + end; + end;]'; + + execute immediate q'[create or replace package ut3_develop.test_regex123_dummy_cov is + --%suite(dummy coverage test) + --%suitepath(coverage_testing) + + --%test + procedure test_do_stuff; + + --%test + procedure zero_coverage; + end;]'; + + execute immediate q'[create or replace package body ut3_develop.test_regex123_dummy_cov is + procedure test_do_stuff is + begin + regex123_dummy_cov.do_stuff(1); + ut.expect(1).to_equal(1); + end; + procedure zero_coverage is + begin + null; + end; + end;]'; + end; + + procedure create_regex_dummy_cov is + begin + create_regex_dummy_for_schema('ut3_develop'); + create_regex_dummy_for_schema('ut3_tester_helper'); + create_regex_dummy_obj; + end; + + procedure drop_regex_dummy_cov is + pragma autonomous_transaction; + begin + begin execute immediate q'[drop package ut3_develop.regex_dummy_cov]'; exception when others then null; end; + begin execute immediate q'[drop package ut3_develop.test_regex_dummy_cov]'; exception when others then null; end; + begin execute immediate q'[drop package ut3_tester_helper.regex_dummy_cov]'; exception when others then null; end; + begin execute immediate q'[drop package ut3_tester_helper.test_regex_dummy_cov]'; exception when others then null; end; + begin execute immediate q'[drop package ut3_develop.regex123_dummy_cov]'; exception when others then null; end; + begin execute immediate q'[drop package ut3_develop.test_regex123_dummy_cov]'; exception when others then null; end; + end; + + + procedure drop_cov_with_dbms_stats is + pragma autonomous_transaction; + begin + begin execute immediate q'[drop package ut3_develop.test_stats]'; exception when others then null; end; + begin execute immediate q'[drop package ut3_develop.stats]'; exception when others then null; end; + begin execute immediate q'[drop table ut3_develop.table_to_test_stats]'; exception when others then null; end; + end; + + + procedure run_standalone_coverage(a_coverage_run_id raw, a_input integer) is + begin + ut3_develop.ut_runner.coverage_start(a_coverage_run_id); + execute immediate 'begin ut3_develop.'||covered_package_name||'.do_stuff(:a_input); end;' using in a_input; + ut3_develop.ut_runner.coverage_stop(); + end; + + function get_job_status(a_job_name varchar2, a_job_started_after timestamp with time zone) return user_scheduler_job_run_details%rowtype is + l_result user_scheduler_job_run_details%rowtype; + begin + begin + select * into l_result + from user_scheduler_job_run_details + where job_name = upper(a_job_name) + and req_start_date >= a_job_started_after; + exception + when no_data_found then + null; + end; + return l_result; + end; + + procedure run_job_and_wait_for_finish(a_job_action varchar2) is + l_job_run_info user_scheduler_job_run_details%rowtype; + l_job_name varchar2(30); + l_timestamp timestamp with time zone := current_timestamp; + i integer := 0; + pragma autonomous_transaction; + begin + g_job_no := g_job_no + 1; + l_job_name := 'utPLSQL_selftest_job_'||g_job_no; + dbms_lock.sleep(0.15); + dbms_scheduler.create_job( + job_name => l_job_name, + job_type => 'PLSQL_BLOCK', + job_action => a_job_action, + start_date => l_timestamp, + enabled => TRUE, + auto_drop => TRUE, + comments => 'one-time-job' + ); + while (l_job_run_info.status is null or l_job_run_info.status not in ('SUCCEEDED','FAILED')) and i < 6000 loop + l_job_run_info := get_job_status( l_job_name, l_timestamp ); + dbms_lock.sleep(0.1); + i := i + 1; + end loop; + commit; + if nvl(l_job_run_info.status,'null') <> 'SUCCEEDED' then + raise_application_error(-20000, 'Scheduler job '''||l_job_name||''', status='''||l_job_run_info.status||'''. Additional info: '||l_job_run_info.additional_info); + end if; + end; + + procedure run_coverage_job(a_coverage_run_id raw, a_input integer) is + begin + run_job_and_wait_for_finish( + 'begin coverage_helper.run_standalone_coverage('''||a_coverage_run_id||''', '||a_input||'); end;' + ); + end; + + procedure create_test_results_table is + pragma autonomous_transaction; + e_exists exception; + pragma exception_init ( e_exists, -955 ); + begin + execute immediate 'create table test_results (id integer, text varchar2(4000))'; + exception + when e_exists then + null; + end; + + procedure drop_test_results_table is + pragma autonomous_transaction; + e_not_exists exception; + pragma exception_init ( e_not_exists, -942 ); + begin + execute immediate 'drop table test_results'; + exception + when e_not_exists then + null; + end; + + function run_code_as_job( a_plsql_block varchar2 ) return clob is + l_result_clob clob; + pragma autonomous_transaction; + begin + run_job_and_wait_for_finish( a_plsql_block ); + dbms_lock.sleep(0.1); + execute immediate q'[ + declare + l_results ut3_develop.ut_varchar2_list; + begin + select text + bulk collect into l_results + from test_results + order by id; + delete from test_results; + commit; + :clob_results := ut3_tester_helper.main_helper.table_to_clob(l_results); + end; + ]' + using out l_result_clob; + + return l_result_clob; + end; + + procedure copy_coverage_data_to_ut3(a_coverage_run_id raw) is + pragma autonomous_transaction; + l_current_coverage_run_id raw(32) := hextoraw(sys_context('UT3_INFO','COVERAGE_RUN_ID')); + begin + insert into ut3.ut_coverage_runs(coverage_run_id, line_coverage_id, block_coverage_id) + select l_current_coverage_run_id, -line_coverage_id, -block_coverage_id + from ut3_develop.ut_coverage_runs + where coverage_run_id = a_coverage_run_id; + + insert into ut3.plsql_profiler_runs(runid, related_run, run_owner, run_date, run_comment, run_total_time, run_system_info, run_comment1, spare1) + select -runid, related_run, run_owner, run_date, run_comment, run_total_time, run_system_info, run_comment1, spare1 + from ut3_develop.plsql_profiler_runs c + join ut3_develop.ut_coverage_runs r + on r.line_coverage_id = c.runid + where r.coverage_run_id = a_coverage_run_id; + + insert into ut3.plsql_profiler_units(runid, unit_number, unit_type, unit_owner, unit_name, unit_timestamp, total_time, spare1, spare2) + select -runid, unit_number, unit_type, unit_owner, unit_name, unit_timestamp, total_time, spare1, spare2 + from ut3_develop.plsql_profiler_units c + join ut3_develop.ut_coverage_runs r + on r.line_coverage_id = c.runid + where r.coverage_run_id = a_coverage_run_id; + + insert into ut3.plsql_profiler_data(runid, unit_number, line#, total_occur, total_time, min_time, max_time, spare1, spare2, spare3, spare4) + select -runid, unit_number, line#, total_occur, total_time, min_time, max_time, spare1, spare2, spare3, spare4 + from ut3_develop.plsql_profiler_data c + join ut3_develop.ut_coverage_runs r + on r.line_coverage_id = c.runid + where r.coverage_run_id = a_coverage_run_id; + + insert into ut3.dbmspcc_runs(run_id, run_comment, run_owner, run_timestamp) + select -run_id, run_comment, run_owner, run_timestamp + from ut3_develop.dbmspcc_runs c + join ut3_develop.ut_coverage_runs r + on r.block_coverage_id = c.run_id + where r.coverage_run_id = a_coverage_run_id; + + insert into ut3.dbmspcc_units(run_id, object_id, owner, name, type, last_ddl_time) + select -run_id, object_id, owner, name, type, last_ddl_time + from ut3_develop.dbmspcc_units c + join ut3_develop.ut_coverage_runs r + on r.block_coverage_id = c.run_id + where r.coverage_run_id = a_coverage_run_id; + + insert into ut3.dbmspcc_blocks(run_id, object_id, block, line, col, covered, not_feasible) + select -run_id, object_id, block, line, col, covered, not_feasible + from ut3_develop.dbmspcc_blocks c + join ut3_develop.ut_coverage_runs r + on r.block_coverage_id = c.run_id + where r.coverage_run_id = a_coverage_run_id; + + commit; + end; + + function gather_coverage_on_coverage( a_cov_options varchar2) return clob is + pragma autonomous_transaction; + l_plsql_block varchar2(32767); + l_result_clob clob; + l_coverage_id raw(32) := sys_guid(); + begin + l_plsql_block := q'[ + declare + l_coverage_options ut3_develop.ut_coverage_options; + l_coverage_run_id raw(32) := ']'||rawtohex(l_coverage_id)||q'['; + l_result ut3_develop.ut_coverage.t_coverage; + begin + ut3_develop.ut_runner.coverage_start(l_coverage_run_id); + ut3_develop.ut_coverage.set_develop_mode(a_develop_mode => true); + l_coverage_options := {a_cov_options}; + l_result := ut3_develop.ut_coverage.get_coverage_data(l_coverage_options); + ut3_develop.ut_coverage.set_develop_mode(a_develop_mode => false); + ut3_develop.ut_runner.coverage_stop(); + insert into test_results select rownum, owner||'.'||name from ut3_develop.ut_coverage_sources_tmp; + commit; + end;]'; + l_plsql_block := replace(l_plsql_block,'{a_cov_options}',a_cov_options); + run_job_and_wait_for_finish( l_plsql_block ); + execute immediate q'[ + declare + l_results ut3_develop.ut_varchar2_list; + begin + select text + bulk collect into l_results + from test_results + order by id; + delete from test_results; + commit; + :clob_results := ut3_tester_helper.main_helper.table_to_clob(l_results); + end; + ]' + using out l_result_clob; + copy_coverage_data_to_ut3(l_coverage_id); + return l_result_clob; + end; + + function run_tests_as_job( a_run_command varchar2 ) return clob is + l_plsql_block varchar2(32767); + l_result_clob clob; + l_coverage_id raw(32) := sys_guid(); + begin + l_plsql_block := q'[ + declare + x dbms_output.chararr; + i integer := 100000; + begin +/* + execute immediate 'alter session set statistics_level=all'; + dbms_hprof.start_profiling( + location => 'PLSHPROF_DIR' + , filename => 'profiler_utPLSQL_run_]'||rawtohex(l_coverage_id)||q'[.txt' + ); +*/ + ut3_develop.ut_runner.coverage_start(']'||rawtohex(l_coverage_id)||q'['); + ut3_develop.ut_coverage.set_develop_mode(a_develop_mode => true); + --gather coverage on the command executed + begin {a_run_command}; end; + dbms_output.get_lines(x,i); + ut3_develop.ut_coverage.set_develop_mode(a_develop_mode => false); + ut3_develop.ut_runner.coverage_stop(); + --get the actual results of the command gathering the coverage + insert into test_results select rownum as id, x.* from table( {a_run_command} ) x; + commit; +/* + dbms_hprof.stop_profiling; +*/ + end;]'; + l_plsql_block := replace(l_plsql_block,'{a_run_command}',a_run_command); + l_result_clob := run_code_as_job( l_plsql_block ); + copy_coverage_data_to_ut3(l_coverage_id); + return l_result_clob; + end; + + procedure create_dup_object_name is + pragma autonomous_transaction; + begin + execute immediate 'create table ut3_develop.test_table(id integer)'; + execute immediate q'[ + create or replace trigger ut3_develop.duplicate_name + before insert on ut3_develop.test_table + begin + + dbms_output.put_line('A'); + end; + ]'; + execute immediate q'[ + create or replace package ut3_develop.duplicate_name is + procedure some_procedure; + end; + ]'; + execute immediate q'[ + create or replace package body ut3_develop.duplicate_name is + procedure some_procedure is + begin + insert into test_table(id) values(1); + end; + end; + ]'; + execute immediate q'[ + create or replace package ut3_develop.test_duplicate_name is + --%suite + + --%test + procedure run_duplicate_name; + end; + ]'; + execute immediate q'[ + create or replace package body ut3_develop.test_duplicate_name is + procedure run_duplicate_name is + l_actual sys_refcursor; + begin + ut3_develop.duplicate_name.some_procedure; + ut.expect(l_actual).to_have_count(1); + end; + end; + ]'; + end; + + procedure drop_dup_object_name is + pragma autonomous_transaction; + begin + execute immediate 'drop table ut3_develop.test_table'; + execute immediate 'drop package ut3_develop.duplicate_name'; + execute immediate 'drop package ut3_develop.test_duplicate_name'; + end; + +end; +/ diff --git a/test/ut3_tester_helper/coverage_helper.pks b/test/ut3_tester_helper/coverage_helper.pks new file mode 100644 index 000000000..8d2c1c150 --- /dev/null +++ b/test/ut3_tester_helper/coverage_helper.pks @@ -0,0 +1,36 @@ +create or replace package coverage_helper is + + function block_coverage_available return boolean; + + function covered_package_name return varchar2; + + function substitute_covered_package( a_text varchar2, a_substitution varchar2 := '{p}' ) return varchar2; + + procedure set_develop_mode; + + procedure create_dummy_coverage; + procedure drop_dummy_coverage; + + procedure create_dummy_coverage_1; + procedure drop_dummy_coverage_1; + + procedure create_regex_dummy_cov; + procedure drop_regex_dummy_cov; + + procedure create_cov_with_dbms_stats; + procedure drop_cov_with_dbms_stats; + + procedure run_standalone_coverage(a_coverage_run_id raw, a_input integer); + procedure run_coverage_job(a_coverage_run_id raw, a_input integer); + + function gather_coverage_on_coverage( a_cov_options varchar2) return clob; + function run_tests_as_job( a_run_command varchar2 ) return clob; + function run_code_as_job( a_plsql_block varchar2 ) return clob; + procedure create_test_results_table; + procedure drop_test_results_table; + + procedure drop_dup_object_name; + procedure create_dup_object_name; + +end; +/ diff --git a/test/core/expectations.pkb b/test/ut3_tester_helper/expectations_helper.pkb similarity index 68% rename from test/core/expectations.pkb rename to test/ut3_tester_helper/expectations_helper.pkb index cc2bae436..c5c1f379f 100644 --- a/test/core/expectations.pkb +++ b/test/ut3_tester_helper/expectations_helper.pkb @@ -1,4 +1,4 @@ -create or replace package body expectations is +create or replace package body expectations_helper is function unary_expectation_block( a_matcher_name varchar2, @@ -12,7 +12,7 @@ create or replace package body expectations is l_expected '||a_data_type||' := '||a_data_value||'; begin --act - execute the expectation - ut3.ut.expect(l_expected).'||a_matcher_name||'(); + ut3_develop.ut.expect(l_expected).'||a_matcher_name||'(); end;'; return l_execute; end; @@ -28,7 +28,7 @@ create or replace package body expectations is declare l_object '||a_object_name||' := '||a_object_value||'; begin - ut3.ut.expect(anydata.convert'||a_object_type||'(l_object)).'||a_matcher_name||'(); + ut3_develop.ut.expect(anydata.convert'||a_object_type||'(l_object)).'||a_matcher_name||'(); end;'; end; @@ -48,20 +48,10 @@ create or replace package body expectations is l_expected '||a_expected_data_type||' := '||a_expected_data||'; begin --act - execute the expectation - ut3.ut.expect( l_actual ).'||a_matcher_name||'(l_expected); + ut3_develop.ut.expect( l_actual ).'||a_matcher_name||'(l_expected); end;'; return l_execute; end; - - function failed_expectations_data return anydata is - begin - return anydata.convertCollection(ut3.ut_expectation_processor.get_failed_expectations()); - end; - - procedure cleanup_expectations is - begin - ut3.ut_expectation_processor.clear_expectations(); - end; - -end expectations; + +end; / diff --git a/test/core/expectations.pks b/test/ut3_tester_helper/expectations_helper.pks similarity index 78% rename from test/core/expectations.pks rename to test/ut3_tester_helper/expectations_helper.pks index 9abc29400..9c1d54333 100644 --- a/test/core/expectations.pks +++ b/test/ut3_tester_helper/expectations_helper.pks @@ -1,4 +1,4 @@ -create or replace package expectations is +create or replace package expectations_helper is function unary_expectation_block( a_matcher_name varchar2, @@ -20,10 +20,6 @@ create or replace package expectations is a_expected_data_type varchar2, a_expected_data varchar2 ) return varchar2; - - function failed_expectations_data return anydata; - - procedure cleanup_expectations; - -end expectations; + +end; / diff --git a/test/ut3_tester_helper/main_helper.pkb b/test/ut3_tester_helper/main_helper.pkb new file mode 100644 index 000000000..f1dadec66 --- /dev/null +++ b/test/ut3_tester_helper/main_helper.pkb @@ -0,0 +1,160 @@ +create or replace package body main_helper is + + function get_dbms_output_as_clob return clob is + l_status number; + l_line varchar2(32767); + l_result clob; + begin + + dbms_output.get_line(line => l_line, status => l_status); + if l_status != 1 then + dbms_lob.createtemporary(l_result, true, dur => dbms_lob.session); + end if; + while l_status != 1 loop + if l_line is not null then + ut3_develop.ut_utils.append_to_clob(l_result, l_line||chr(10)); + end if; + dbms_output.get_line(line => l_line, status => l_status); + end loop; + return l_result; + end; + + procedure execute_autonomous(a_sql varchar2) is + pragma autonomous_transaction; + begin + if a_sql is not null then + execute immediate a_sql; + end if; + commit; + end; + + function run_test(a_path varchar2) return clob is + l_lines ut3_develop.ut_varchar2_list; + begin + select * bulk collect into l_lines from table(ut3_develop.ut.run(a_path)); + return ut3_develop.ut_utils.table_to_clob(l_lines); + end; + + function get_value(a_variable varchar2) return integer is + l_glob_val integer; + begin + execute immediate 'begin :l_glob_val := '||a_variable||'; end;' using out l_glob_val; + return l_glob_val; + end; + + function get_failed_expectations return ut3_develop.ut_varchar2_list is + l_expectations_result ut3_develop.ut_expectation_results := ut3_develop.ut_expectation_processor.get_failed_expectations(); + l_result ut3_develop.ut_varchar2_list := ut3_develop.ut_varchar2_list(); + begin + for i in 1..l_expectations_result.count loop + l_result := l_result multiset union l_expectations_result(i).get_result_lines(); + end loop; + return l_result; + end; + + function get_failed_expectations(a_pos in number) return varchar2 is + l_result varchar2(32767) := ut3_develop.ut_expectation_processor.get_failed_expectations()(a_pos).message; + begin + return l_result; + end; + + function failed_expectations_data return anydata is + begin + return anydata.convertCollection(ut3_develop.ut_expectation_processor.get_failed_expectations()); + end; + + function get_failed_expectations_num return number is + l_num_failed number; + l_results ut3_develop.ut_expectation_results := ut3_develop.ut_expectation_processor.get_failed_expectations(); + begin + l_num_failed := l_results.count; + return l_num_failed; + end; + + procedure clear_expectations is + begin + ut3_develop.ut_expectation_processor.clear_expectations(); + end; + + function table_to_clob(a_results in ut3_develop.ut_varchar2_list) return clob is + begin + return ut3_develop.ut_utils.table_to_clob(a_results); + end; + + function get_warnings return ut3_develop.ut_varchar2_rows is + begin + return ut3_develop.ut_expectation_processor.get_warnings(); + end; + + procedure reset_nulls_equal is + begin + ut3_develop.ut_expectation_processor.nulls_Are_equal(ut3_develop.ut_expectation_processor.gc_default_nulls_are_equal); + end; + + procedure nulls_are_equal(a_nulls_equal boolean := true) is + begin + ut3_develop.ut_expectation_processor.nulls_Are_equal(a_nulls_equal); + end; + + procedure cleanup_annotation_cache is + pragma autonomous_transaction; + begin + delete from ut3_develop.ut_annotation_cache_info + where object_owner = 'UT3_TESTER' and object_type = 'PACKAGE' and object_name in ('DUMMY_PACKAGE','DUMMY_TEST_PACKAGE'); + commit; + 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_develop.ut_runner.rebuild_annotation_cache('UT3_TESTER','PACKAGE'); + end;]'; + end; + + procedure drop_parse_proc_as_ut3_user is + pragma autonomous_transaction; + begin + execute immediate 'drop procedure ut3_user.parse_annotations'; + end; + + procedure parse_dummy_test_as_ut3_user is + pragma autonomous_transaction; + begin + execute immediate 'begin ut3_user.parse_annotations; end;'; + end; + + procedure append_to_list(a_list in out nocopy ut3_develop.ut_varchar2_list, a_item varchar2) is + begin + ut3_develop.ut_utils.append_to_list(a_list,a_item); + end; + + procedure append_to_list(a_list in out nocopy ut3_develop.ut_varchar2_rows, a_item varchar2) is + begin + ut3_develop.ut_utils.append_to_list(a_list,a_item); + end; + + procedure append_to_list(a_list in out nocopy ut3_develop.ut_varchar2_rows, a_item clob) is + begin + ut3_develop.ut_utils.append_to_list(a_list,a_item); + end; + + procedure append_to_list(a_list in out nocopy ut3_develop.ut_varchar2_rows, a_items ut3_develop.ut_varchar2_rows) is + begin + ut3_develop.ut_utils.append_to_list(a_list,a_items); + end; + + procedure set_ut_run_context is + begin + ut3_develop.ut_session_context.set_context('RUN_PATHS',' '); + end; + + procedure clear_ut_run_context is + begin + ut3_develop.ut_session_context.clear_all_context; + end; + +end; +/ diff --git a/test/ut3_tester_helper/main_helper.pks b/test/ut3_tester_helper/main_helper.pks new file mode 100644 index 000000000..7decad88d --- /dev/null +++ b/test/ut3_tester_helper/main_helper.pks @@ -0,0 +1,51 @@ +create or replace package main_helper is + + gc_success number := ut3_develop.ut_utils.gc_success; + gc_failure number := ut3_develop.ut_utils.gc_failure; + + procedure execute_autonomous(a_sql varchar2); + + function run_test(a_path varchar2) return clob; + + function get_value(a_variable varchar2) return integer; + + function get_dbms_output_as_clob return clob; + + function get_failed_expectations return ut3_develop.ut_varchar2_list; + + function get_failed_expectations(a_pos in number) return varchar2; + + function get_failed_expectations_num return number; + + procedure clear_expectations; + + function table_to_clob(a_results in ut3_develop.ut_varchar2_list) return clob; + + function get_warnings return ut3_develop.ut_varchar2_rows; + + procedure reset_nulls_equal; + + procedure nulls_are_equal(a_nulls_equal boolean := true); + + procedure cleanup_annotation_cache; + + procedure create_parse_proc_as_ut3_user; + + procedure drop_parse_proc_as_ut3_user; + + procedure parse_dummy_test_as_ut3_user; + + procedure append_to_list(a_list in out nocopy ut3_develop.ut_varchar2_list, a_item varchar2); + + procedure append_to_list(a_list in out nocopy ut3_develop.ut_varchar2_rows, a_item varchar2); + + procedure append_to_list(a_list in out nocopy ut3_develop.ut_varchar2_rows, a_item clob); + + procedure append_to_list(a_list in out nocopy ut3_develop.ut_varchar2_rows, a_items ut3_develop.ut_varchar2_rows); + + procedure set_ut_run_context; + + procedure clear_ut_run_context; + +end; +/ diff --git a/test/helpers/other_dummy_object.tps b/test/ut3_tester_helper/other_dummy_object.tps similarity index 99% rename from test/helpers/other_dummy_object.tps rename to test/ut3_tester_helper/other_dummy_object.tps index c1019c415..7453d5dcf 100644 --- a/test/helpers/other_dummy_object.tps +++ b/test/ut3_tester_helper/other_dummy_object.tps @@ -13,4 +13,4 @@ create or replace type other_dummy_object as object ( "name" varchar2(30), "Value" varchar2(30) ) -/ \ No newline at end of file +/ diff --git a/test/ut3_tester_helper/run_helper.pkb b/test/ut3_tester_helper/run_helper.pkb new file mode 100644 index 000000000..6289b1642 --- /dev/null +++ b/test/ut3_tester_helper/run_helper.pkb @@ -0,0 +1,919 @@ +create or replace package body run_helper is + + procedure setup_cache_objects is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package ut3_user.dummy_test_package as + --%suite(dummy_test_suite) + --%suitepath(some.path) + --%rollback(manual) + + --%test(dummy_test) + --%beforetest(some_procedure) + procedure some_dummy_test_procedure; + end;]'; + execute immediate q'[create or replace procedure ut3_user.dummy_test_procedure as + --%some_annotation(some_text) + --%rollback(manual) + begin + null; + end;]'; + execute immediate q'[create or replace procedure ut3_tester_helper.dummy_test_procedure as + --%some_annotation(some_text) + --%rollback(manual) + begin + null; + end;]'; + + execute immediate q'[grant execute on ut3_tester_helper.dummy_test_procedure to public]'; + + execute immediate q'[create or replace package ut3_user.bad_test_package as + --%rollback(manual) + --%test(dummy_test) + procedure some_dummy_test_procedure; + end;]'; + end; + + procedure setup_cache_objectstag is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package ut3_user.dummy_test_package as + --%suite(dummy_test_suite) + --%suitepath(some.path) + --%tags(dummy) + --%rollback(manual) + + --%test(dummy_test) + --%tags(testtag) + --%beforetest(some_procedure) + procedure some_dummy_test_procedure; + end;]'; + execute immediate q'[create or replace procedure ut3_user.dummy_test_procedure as + --%some_annotation(some_text) + --%rollback(manual) + begin + null; + end;]'; + execute immediate q'[create or replace procedure ut3_tester_helper.dummy_test_procedure as + --%some_annotation(some_text) + --%rollback(manual) + begin + null; + end;]'; + + execute immediate q'[grant execute on ut3_tester_helper.dummy_test_procedure to public]'; + end; + + procedure setup_cache_twotags is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package ut3_user.dummy_test_package as + --%suite(dummy_test_suite) + --%tags(suitetag1,suitetag2) + --%rollback(manual) + + --%test(dummy_test) + --%tags(testtag1,testtag2) + --%beforetest(some_procedure) + procedure some_dummy_test_procedure; + end;]'; + execute immediate q'[create or replace procedure ut3_user.dummy_test_procedure as + --%some_annotation(some_text) + --%rollback(manual) + begin + null; + end;]'; + execute immediate q'[create or replace procedure ut3_tester_helper.dummy_test_procedure as + --%some_annotation(some_text) + --%rollback(manual) + begin + null; + end;]'; + + execute immediate q'[grant execute on ut3_tester_helper.dummy_test_procedure to public]'; + end; + + procedure create_trans_control is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package ut_transaction_control as + function count_rows(a_val varchar2) return number; + procedure setup; + procedure test; + procedure test_failure; + end;]'; + + execute immediate + q'[create or replace package body ut_transaction_control + as + + function count_rows(a_val varchar2) return number is + l_cnt number; + begin + select count(*) into l_cnt from ut$test_table t where t.val = a_val; + return l_cnt; + end; + procedure setup is begin + insert into ut$test_table values ('s'); + end; + procedure test is + begin + insert into ut$test_table values ('t'); + end; + procedure test_failure is + begin + insert into ut$test_table values ('t'); + --raise no_data_found; + raise_application_error(-20001,'Error'); + end; + end;]'; + + execute immediate 'grant execute on ut_transaction_control to public'; + end; + + procedure drop_trans_control is + pragma autonomous_transaction; + begin + execute immediate 'drop package ut_transaction_control'; + end; + + procedure setup_cache is + pragma autonomous_transaction; + begin + setup_cache_objects(); + ut3_develop.ut_annotation_manager.rebuild_annotation_cache('UT3_USER','PACKAGE'); + ut3_develop.ut_annotation_manager.rebuild_annotation_cache('UT3_USER','PROCEDURE'); + ut3_develop.ut_annotation_manager.rebuild_annotation_cache('UT3_TESTER_HELPER','PROCEDURE'); + end; + + procedure cleanup_cache is + pragma autonomous_transaction; + begin + delete from ut3_develop.ut_annotation_cache_info + where object_type = 'PROCEDURE' and object_owner in ('UT3_USER','UT3_TESTER_HELPER') + or object_type = 'PACKAGE' and object_owner = user and object_name = 'DUMMY_TEST_PACKAGE'; + execute immediate q'[drop package ut3_user.dummy_test_package]'; + execute immediate q'[drop procedure ut3_user.dummy_test_procedure]'; + execute immediate q'[drop procedure ut3_tester_helper.dummy_test_procedure]'; + end; + + procedure create_db_link is + l_service_name varchar2(100); + pragma autonomous_transaction; + begin + select global_name into l_service_name from global_name; + execute immediate + 'create public database link db_loopback connect to ut3_tester_helper identified by ut3 + using ''(DESCRIPTION= + (ADDRESS=(PROTOCOL=TCP) + (HOST='||sys_context('userenv','SERVER_HOST')||') + (PORT=1521) + ) + (CONNECT_DATA=(SERVICE_NAME='||l_service_name||')))'''; + end; + + procedure drop_db_link is + begin + execute immediate 'drop public database link db_loopback'; + exception + when others then + null; + end; + + procedure db_link_setup is + l_service_name varchar2(100); + begin + create_db_link; + execute immediate q'[ + create or replace package ut3_user.test_db_link is + --%suite + + --%test + procedure runs_with_db_link; + end;]'; + + execute immediate q'[ + create or replace package body ut3_user.test_db_link is + procedure runs_with_db_link is + a_value integer; + begin + select 1 into a_value + from dual@db_loopback; + ut3_develop.ut.expect(a_value).to_be_null(); + end; + end;]'; + + end; + + procedure db_link_cleanup is + begin + drop_db_link; + begin execute immediate 'drop package ut3_user.test_db_link'; exception when others then null; end; + end; + + procedure create_suite_with_link is + pragma autonomous_transaction; + begin + create_db_link; + execute immediate 'create table tst(id number(18,0))'; + execute immediate q'[ + create or replace package test_distributed_savepoint is + --%suite + --%suitepath(alltests) + + --%beforeall + procedure setup; + + --%test + procedure test; + end;]'; + + execute immediate q'[ + create or replace package body test_distributed_savepoint is + + g_expected constant integer := 1; + + procedure setup is + begin + insert into tst@db_loopback values(g_expected); + end; + + procedure test is + l_actual integer := 0; + begin + select id into l_actual from tst@db_loopback; + + ut.expect(l_actual).to_equal(g_expected); + end; + + end;]'; + execute immediate 'grant execute on test_distributed_savepoint to public'; + end; + + procedure drop_suite_with_link is + pragma autonomous_transaction; + begin + drop_db_link; + execute immediate 'drop table tst'; + execute immediate 'drop package test_distributed_savepoint'; + end; + + procedure create_ut3_user_tests is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package test_package_1 is + --%suite + --%tags(suite1,helper) + --%suitepath(tests) + --%rollback(manual) + + --%test(Test1 from test package 1) + --%tags(test1,suite1test1,subtest1) + procedure test1; + + --%test(Test2 from test package 1) + --%tags(test1,suite1test2) + procedure test2; + + end test_package_1; + ]'; + execute immediate q'[create or replace package body test_package_1 is + procedure test1 is + begin + dbms_output.put_line('test_package_1.test1 executed'); + raise_application_error(-20111,'test'); + end; + procedure test2 is + begin + dbms_output.put_line('test_package_1.test2 executed'); + end; + end test_package_1; + ]'; + + execute immediate q'[create or replace package test_package_2 is + --%suite + --%tags(suite2,helper) + --%suitepath(tests.test_package_1) + + --%test + --%tags(test2,suite2test1,subtest2) + procedure test1; + + --%test + --%tags(suite2test2) + procedure test2; + + end test_package_2; + ]'; + execute immediate q'[create or replace package body test_package_2 is + procedure test1 is + begin + dbms_output.put_line('test_package_2.test1 executed'); + end; + procedure test2 is + begin + dbms_output.put_line('test_package_2.test2 executed'); + end; + end test_package_2; + ]'; + + execute immediate q'[create or replace package test_package_3 is + --%suite + --%tags(suite3,helper) + --%suitepath(tests2) + + --%test + --%tags(test1suite3) + procedure test1; + + --%test + --%tags(test2suite3) + procedure test2; + + end test_package_3; + ]'; + execute immediate q'[create or replace package body test_package_3 is + procedure test1 is + begin + dbms_output.put_line('test_package_3.test1 executed'); + end; + procedure test2 is + begin + dbms_output.put_line('test_package_3.test2 executed'); + end; + end test_package_3; + ]'; + + execute immediate q'[create or replace package test_tag_pkg_1 is + --%suite + --%tags(suite1,release_3_1_13,development,complex,end_to_end) + --%suitepath(suite1) + --%rollback(manual) + + --%test(Test1 from test_tag_pkg_1) + --%tags(test1,development,fast) + procedure test1; + + --%test(Test2 from test_tag_pkg_1) + --%tags(test2,production,slow,patch_3_1_13) + procedure test2; + + end test_tag_pkg_1; + ]'; + + execute immediate q'[create or replace package body test_tag_pkg_1 is + procedure test1 is + begin + dbms_output.put_line('test_tag_pkg_1.test1 executed'); + end; + procedure test2 is + begin + dbms_output.put_line('test_tag_pkg_1.test2 executed'); + end; + end test_tag_pkg_1; + ]'; + + execute immediate q'[create or replace package test_tag_pkg_2 is + --%suite + --%tags(suite2,release_3_1_12,development,simple) + --%suitepath(suite1.suite2) + --%rollback(manual) + + --%test(Test3 from test_tag_pkg_2) + --%tags(test3,development,fast) + procedure test3; + + --%test(Test4 from test_tag_pkg_1) + --%tags(test4,production,slow) + procedure test4; + + end test_tag_pkg_2; + ]'; + + execute immediate q'[create or replace package body test_tag_pkg_2 is + procedure test3 is + begin + dbms_output.put_line('test_tag_pkg_2.test3 executed'); + end; + procedure test4 is + begin + dbms_output.put_line('test_tag_pkg_2.test4 executed'); + end; + end test_tag_pkg_2; + ]'; + + execute immediate q'[create or replace package test_tag_pkg_3 is + --%suite + --%tags(suite3,release_3_1_13,production,simple,end_to_end) + --%suitepath(suite3) + --%rollback(manual) + + --%test(Test5 from test_tag_pkg_3) + --%tags(test5,release_3_1_13,production,patch_3_1_13) + procedure test5; + + --%test(Test6 from test_tag_pkg_3) + --%tags(test6,development,patch_3_1_14) + procedure test6; + + end test_tag_pkg_3; + ]'; + + execute immediate q'[create or replace package body test_tag_pkg_3 is + procedure test5 is + begin + dbms_output.put_line('test_tag_pkg_3.test5 executed'); + end; + procedure test6 is + begin + dbms_output.put_line('test_tag_pkg_3.test6 executed'); + end; + end test_tag_pkg_3; + ]'; + + execute immediate q'[create or replace package suite1_level1_pkg is + + --%suite(suite1_level1) + --%suitepath(any_none) + --%rollback(manual) + + --%test(Test 1 from Suite1 on level 1) + --%tags(suite1,level1,test1,test1_level1) + procedure test1_level1; + + --%test(Test 2 from Suite1 on level 1) + procedure test2_level1; + + end suite1_level1_pkg; + ]'; + + execute immediate q'[create or replace package body suite1_level1_pkg is + procedure test1_level1 is + begin + dbms_output.put_line('suite1_level1_pkg.test1_level1 executed'); + end; + procedure test2_level1 is + begin + dbms_output.put_line('suite1_level1_pkg.test2_level1 executed'); + end; + end suite1_level1_pkg; + ]'; + + execute immediate q'[create or replace package suite1_1_level2_pkg is + + --%suite(suite1_1_level2) + --%suitepath(any_none.suite1_level1) + --%rollback(manual) + + --%test(Test 1 from Suite1_2 on level 2) + --%tags(level2,test1,test1_level2) + procedure suite1_1_test1_level2; + + --%test(Test 2 from Suite1_2 on level 2) + procedure suite1_1_test2_level2; + + end suite1_1_level2_pkg; + ]'; + + execute immediate q'[create or replace package body suite1_1_level2_pkg is + procedure suite1_1_test1_level2 is + begin + dbms_output.put_line('suite1_1_level2_pkg.suite1_1_test1_level2 executed'); + end; + procedure suite1_1_test2_level2 is + begin + dbms_output.put_line('suite1_1_level2_pkg.suite1_1_test2_level2 executed'); + end; + end suite1_1_level2_pkg; + ]'; + + execute immediate q'[create or replace package suite1_2_level2_pkg is + + --%suite(suite1_2_level2) + --%tags(level2,suite1_2,suites) + --%suitepath(any_none.suite1_level1) + --%rollback(manual) + + --%test(Test 1 from Suite1_2 on level 2) + procedure suite1_2_test1_level2; + + --%test(Test 2 from Suite1_2 on level 2) + --%tags(level2,test2,test2_level2) + procedure suite1_2_test2_level1; + + end suite1_2_level2_pkg; + ]'; + + execute immediate q'[create or replace package body suite1_2_level2_pkg is + procedure suite1_2_test1_level2 is + begin + dbms_output.put_line('suite1_2_level2_pkg.suite1_2_test1_level2 executed'); + end; + procedure suite1_2_test2_level1 is + begin + dbms_output.put_line('suite1_2_level2_pkg.suite1_2_test2_level1 executed'); + end; + end suite1_2_level2_pkg; + ]'; + + execute immediate q'[create or replace package suite2_level1_pkg is + + --%suite(suite2_level1) + --%tags(level1,suite2,suites) + --%suitepath(any_none) + --%rollback(manual) + + --%test(Test 1 from Suite1 on level 1) + --%tags(suite2,level1,test1,test1_level1) + procedure test1_level1; + + --%test(Test 2 from Suite1 on level 1) + procedure test2_level1; + + end suite2_level1_pkg; + ]'; + + execute immediate q'[create or replace package body suite2_level1_pkg is + procedure test1_level1 is + begin + dbms_output.put_line('suite2_level1_pkg.test1_level1 executed'); + end; + procedure test2_level1 is + begin + dbms_output.put_line('suite2_level1_pkg.test2_level1 executed'); + end; + end suite2_level1_pkg; + ]'; + + execute immediate q'[create or replace package suite2_2_level2_pkg is + + --%suite(suite2_2_level2) + --%tags(level2,suite2_2,suites) + --%suitepath(any_none.suite2_level1) + --%rollback(manual) + + --%test(Test 1 from Suite2_2 on level 2) + procedure suite2_2_test1_level2; + + --%test(Test 2 from Suite2_2 on level 2) + --%tags(level2,test2,test2_level2) + procedure suite2_2_test2_level2; + + end suite2_2_level2_pkg; + ]'; + + execute immediate q'[create or replace package body suite2_2_level2_pkg is + procedure suite2_2_test1_level2 is + begin + dbms_output.put_line('suite2_2_level2_pkg.suite2_2_test1_level2 executed'); + end; + procedure suite2_2_test2_level2 is + begin + dbms_output.put_line('suite2_2_level2_pkg.suite2_2_test2_level2 executed'); + end; + end suite2_2_level2_pkg; + ]'; + + + execute immediate q'[grant execute on test_package_1 to public]'; + execute immediate q'[grant execute on test_package_2 to public]'; + execute immediate q'[grant execute on test_package_3 to public]'; + execute immediate q'[grant execute on test_tag_pkg_1 to public]'; + execute immediate q'[grant execute on test_tag_pkg_2 to public]'; + execute immediate q'[grant execute on test_tag_pkg_3 to public]'; + + execute immediate q'[grant execute on suite1_level1_pkg to public]'; + execute immediate q'[grant execute on suite1_1_level2_pkg to public]'; + execute immediate q'[grant execute on suite1_2_level2_pkg to public]'; + execute immediate q'[grant execute on suite2_level1_pkg to public]'; + execute immediate q'[grant execute on suite2_2_level2_pkg to public]'; + end; + + procedure drop_ut3_user_tests is + pragma autonomous_transaction; + begin + execute immediate q'[drop package test_package_1]'; + execute immediate q'[drop package test_package_2]'; + execute immediate q'[drop package test_package_3]'; + execute immediate q'[drop package test_tag_pkg_1]'; + execute immediate q'[drop package test_tag_pkg_2]'; + execute immediate q'[drop package test_tag_pkg_3]'; + + execute immediate q'[drop package suite2_2_level2_pkg]'; + execute immediate q'[drop package suite2_level1_pkg]'; + execute immediate q'[drop package suite1_2_level2_pkg]'; + execute immediate q'[drop package suite1_level1_pkg]'; + execute immediate q'[drop package suite1_1_level2_pkg]'; + end; + + procedure create_test_suite is + pragma autonomous_transaction; + begin + ut3_tester_helper.run_helper.create_db_link; + execute immediate q'[ + create or replace package stateful_package as + function get_state return varchar2; + end; + ]'; + execute immediate q'[ + create or replace package body stateful_package as + g_state varchar2(1) := 'A'; + function get_state return varchar2 is begin return g_state; end; + end; + ]'; + execute immediate q'[ + create or replace package test_stateful as + --%suite + --%suitepath(test_state) + + --%test + --%beforetest(acquire_state_via_db_link,rebuild_stateful_package) + procedure failing_stateful_test; + + procedure rebuild_stateful_package; + procedure acquire_state_via_db_link; + + end; + ]'; + execute immediate q'{ + create or replace package body test_stateful as + + procedure failing_stateful_test is + begin + ut3_develop.ut.expect(stateful_package.get_state@db_loopback).to_equal('abc'); + end; + + procedure rebuild_stateful_package is + pragma autonomous_transaction; + begin + execute immediate q'[ + create or replace package body stateful_package as + g_state varchar2(3) := 'abc'; + function get_state return varchar2 is begin return g_state; end; + end; + ]'; + end; + + procedure acquire_state_via_db_link is + begin + dbms_output.put_line('stateful_package.get_state@db_loopback='||stateful_package.get_state@db_loopback); + end; + end; + }'; + execute immediate 'grant execute on test_stateful to public'; + end; + + procedure drop_test_suite is + pragma autonomous_transaction; + begin + drop_db_link; + execute immediate 'drop package stateful_package'; + execute immediate 'drop package test_stateful'; + end; + + procedure package_no_body is + pragma autonomous_transaction; + begin + execute immediate 'create or replace package ut_without_body as + procedure test1; + end;'; + end; + + procedure drop_package_no_body is + pragma autonomous_transaction; + begin + execute immediate 'drop package ut_without_body'; + end; + + procedure run(a_reporter ut3_develop.ut_reporter_base := null) is + begin + ut3_develop.ut.run(a_reporter); + end; + + procedure run(a_path varchar2, a_reporter ut3_develop.ut_reporter_base := null) is + begin + ut3_develop.ut.run(a_path, a_reporter); + end; + + procedure run(a_paths ut3_develop.ut_varchar2_list, a_reporter ut3_develop.ut_reporter_base := null) is + begin + ut3_develop.ut.run(a_paths, a_reporter); + end; + + procedure run(a_paths ut3_develop.ut_varchar2_list, a_test_files ut3_develop.ut_varchar2_list, a_reporter ut3_develop.ut_reporter_base) is + begin + ut3_develop.ut.run( + a_paths, + a_reporter, + a_source_files => ut3_develop.ut_varchar2_list(), + a_test_files => a_test_files + ); + end; + + function run(a_reporter ut3_develop.ut_reporter_base := null) return ut3_develop.ut_varchar2_list is + l_results ut3_develop.ut_varchar2_list; + begin + select * bulk collect into l_results from table (ut3_develop.ut.run(a_reporter)); + return l_results; + end; + + function run(a_paths ut3_develop.ut_varchar2_list, a_test_files ut3_develop.ut_varchar2_list, a_reporter ut3_develop.ut_reporter_base) return ut3_develop.ut_varchar2_list is + l_results ut3_develop.ut_varchar2_list; + begin + select * bulk collect into l_results from table ( + ut3_develop.ut.run( + a_paths, + a_reporter, a_source_files => ut3_develop.ut_varchar2_list(), + a_test_files => a_test_files + )); + return l_results; + end; + + function run(a_path varchar2, a_reporter ut3_develop.ut_reporter_base := null) + return ut3_develop.ut_varchar2_list is + l_results ut3_develop.ut_varchar2_list; + begin + select * bulk collect into l_results from table (ut3_develop.ut.run(a_path, a_reporter)); + return l_results; + end; + + function run(a_paths ut3_develop.ut_varchar2_list, a_reporter ut3_develop.ut_reporter_base := null) + return ut3_develop.ut_varchar2_list is + l_results ut3_develop.ut_varchar2_list; + begin + select * bulk collect into l_results from table (ut3_develop.ut.run(a_paths, a_reporter)); + return l_results; + end; + + function run(a_test_files ut3_develop.ut_varchar2_list, a_reporter ut3_develop.ut_reporter_base) + return ut3_develop.ut_varchar2_list is + l_results ut3_develop.ut_varchar2_list; + begin + select * bulk collect into l_results from table ( + ut3_develop.ut.run( + a_reporter, a_source_files => ut3_develop.ut_varchar2_list(), + a_test_files => a_test_files + )); + return l_results; + end; + + procedure run(a_reporter ut3_develop.ut_reporter_base := null,a_tags varchar2) is + begin + ut3_develop.ut.run(a_reporter,a_tags => a_tags); + end; + + procedure run(a_path varchar2, a_reporter ut3_develop.ut_reporter_base := null,a_tags varchar2) is + begin + ut3_develop.ut.run(a_path, a_reporter,a_tags => a_tags); + end; + + procedure run(a_paths ut3_develop.ut_varchar2_list, a_reporter ut3_develop.ut_reporter_base := null, a_tags varchar2) is + begin + ut3_develop.ut.run(a_paths, a_reporter,a_tags => a_tags); + end; + + function run(a_reporter ut3_develop.ut_reporter_base := null,a_tags varchar2) return ut3_develop.ut_varchar2_list is + l_results ut3_develop.ut_varchar2_list; + begin + select * bulk collect into l_results from table (ut3_develop.ut.run(a_reporter, a_tags => a_tags)); + return l_results; + end; + + function run(a_path varchar2, a_reporter ut3_develop.ut_reporter_base := null, a_tags varchar2) + return ut3_develop.ut_varchar2_list is + l_results ut3_develop.ut_varchar2_list; + begin + select * bulk collect into l_results from table (ut3_develop.ut.run(a_path, a_reporter,a_tags => a_tags)); + return l_results; + end; + + function run(a_paths ut3_develop.ut_varchar2_list, a_reporter ut3_develop.ut_reporter_base := null, a_tags varchar2) + return ut3_develop.ut_varchar2_list is + l_results ut3_develop.ut_varchar2_list; + begin + select * bulk collect into l_results from table (ut3_develop.ut.run(a_paths, a_reporter, a_tags => a_tags)); + return l_results; + end; + + procedure test_rollback_type(a_procedure_name varchar2, a_rollback_type integer, a_expectation ut_matcher) is + l_suite ut3_develop.ut_suite; + begin + --Arrange + execute immediate 'delete from ut$test_table'; + l_suite := ut3_develop.ut_suite(a_object_owner => 'ut3_tester_helper', a_object_name => 'UT_TRANSACTION_CONTROL', a_line_no=> 1); + l_suite.path := 'ut_transaction_control'; + l_suite.before_all_list := ut3_develop.ut_executables(ut3_develop.ut_executable('ut3_tester_helper', 'UT_TRANSACTION_CONTROL', 'setup', ut3_develop.ut_utils.gc_before_all)); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3_develop.ut_test(a_object_owner => 'ut3_tester_helper', a_object_name => 'ut_transaction_control',a_name => a_procedure_name, a_line_no=> 1); + l_suite.set_rollback_type(a_rollback_type); + + --Act + l_suite.do_execute(); + + --Assert + ut.expect(main_helper.get_value(q'[ut_transaction_control.count_rows('t')]')).to_( a_expectation ); + ut.expect(main_helper.get_value(q'[ut_transaction_control.count_rows('s')]')).to_( a_expectation ); + end; + + procedure create_dummy_long_test_package is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package ut3_develop.dummy_long_test_package as + + --%suitepath(verylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtext) + --%suite(dummy_test_suite) + + --%test(dummy_test) + procedure some_dummy_test_procedure; + end;]'; + + execute immediate q'[create or replace package ut3_develop.dummy_long_test_package1 as + + --%suitepath(verylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtextverylongtext) + --%suite(dummy_test_suite1) + + --%test(dummy_test) + procedure some_dummy_test_procedure; + end;]'; + end; + + procedure drop_dummy_long_test_package is + pragma autonomous_transaction; + begin + execute immediate q'[drop package ut3_develop.dummy_long_test_package]'; + execute immediate q'[drop package ut3_develop.dummy_long_test_package1]'; + end; + + procedure create_ut3_suite is + pragma autonomous_transaction; + begin + execute immediate q'[ + create or replace package ut3_develop.some_test_package + as + --%suite + + --%test + procedure some_test; + + end;]'; + end; + + procedure drop_ut3_suite is + pragma autonomous_transaction; + begin + execute immediate q'[drop package ut3_develop.some_test_package]'; + end; + + function get_schema_ut_packages(a_owner in varchar2) return ut3_develop.ut_object_names is + begin + return ut3_develop.ut_suite_manager.get_schema_ut_packages(ut3_develop.ut_varchar2_rows(a_owner), null); + end; + + function ut_output_buffer_tmp return t_out_buff_tab pipelined is + l_buffer_tab t_out_buff_tab; + cursor get_buffer is + select * from ut3_develop.ut_output_buffer_tmp; + begin + open get_buffer; + fetch get_buffer bulk collect into l_buffer_tab; + for idx in 1..l_buffer_tab.count loop + pipe row(l_buffer_tab(idx)); + end loop; + end; + + procedure delete_buffer is + begin + delete from ut3_develop.ut_output_buffer_tmp; + end; + + function get_annotation_cache_info_cur( + a_owner varchar2, + a_type varchar2 + ) return sys_refcursor is + l_result sys_refcursor; + begin + open l_result for + select * from ut3_develop.ut_annotation_cache_info + where object_owner = a_owner and object_type = a_type; + + return l_result; + end; + + function get_annotation_cache_cursor( + a_owner varchar2, + a_type varchar2, + a_name varchar2 := null + ) return sys_refcursor is + l_result sys_refcursor; + begin + open l_result for + select * + from ut3_develop.ut_annotation_cache_info i + join ut3_develop.ut_annotation_cache c on c.cache_id = i.cache_id + where object_owner = a_owner and object_type = a_type and object_name = nvl( a_name, object_name ); + + return l_result; + end; + +end; +/ diff --git a/test/ut3_tester_helper/run_helper.pks b/test/ut3_tester_helper/run_helper.pks new file mode 100644 index 000000000..ad0f615e5 --- /dev/null +++ b/test/ut3_tester_helper/run_helper.pks @@ -0,0 +1,78 @@ +create or replace package run_helper is + + g_run_id integer; + + type t_out_buff_tab is table of ut3_develop.ut_output_buffer_tmp%rowtype; + + procedure setup_cache_objects; + procedure setup_cache_objectstag; + procedure setup_cache_twotags; + procedure setup_cache; + procedure cleanup_cache; + procedure create_db_link; + procedure drop_db_link; + procedure db_link_setup; + procedure db_link_cleanup; + + procedure create_suite_with_link; + procedure drop_suite_with_link; + + procedure create_ut3_user_tests; + procedure drop_ut3_user_tests; + + procedure create_test_suite; + procedure drop_test_suite; + procedure package_no_body; + procedure drop_package_no_body; + + procedure create_trans_control; + procedure drop_trans_control; + + procedure run(a_reporter ut3_develop.ut_reporter_base := null); + procedure run(a_path varchar2, a_reporter ut3_develop.ut_reporter_base := null); + procedure run(a_paths ut3_develop.ut_varchar2_list, a_reporter ut3_develop.ut_reporter_base := null); + procedure run(a_paths ut3_develop.ut_varchar2_list, a_test_files ut3_develop.ut_varchar2_list, + a_reporter ut3_develop.ut_reporter_base); + function run(a_reporter ut3_develop.ut_reporter_base := null) return ut3_develop.ut_varchar2_list; + function run(a_paths ut3_develop.ut_varchar2_list, a_test_files ut3_develop.ut_varchar2_list, + a_reporter ut3_develop.ut_reporter_base) return ut3_develop.ut_varchar2_list; + function run(a_path varchar2, a_reporter ut3_develop.ut_reporter_base := null) + return ut3_develop.ut_varchar2_list; + function run(a_paths ut3_develop.ut_varchar2_list, a_reporter ut3_develop.ut_reporter_base := null) + return ut3_develop.ut_varchar2_list; + function run(a_test_files ut3_develop.ut_varchar2_list, a_reporter ut3_develop.ut_reporter_base) + return ut3_develop.ut_varchar2_list; + + procedure run(a_reporter ut3_develop.ut_reporter_base := null,a_tags varchar2); + procedure run(a_path varchar2, a_reporter ut3_develop.ut_reporter_base := null,a_tags varchar2); + procedure run(a_paths ut3_develop.ut_varchar2_list, a_reporter ut3_develop.ut_reporter_base := null, a_tags varchar2); + function run(a_reporter ut3_develop.ut_reporter_base := null,a_tags varchar2) return ut3_develop.ut_varchar2_list; + function run(a_path varchar2, a_reporter ut3_develop.ut_reporter_base := null, a_tags varchar2) + return ut3_develop.ut_varchar2_list; + function run(a_paths ut3_develop.ut_varchar2_list, a_reporter ut3_develop.ut_reporter_base := null, a_tags varchar2) + return ut3_develop.ut_varchar2_list; + + procedure test_rollback_type(a_procedure_name varchar2, a_rollback_type integer, a_expectation ut_matcher); + + procedure create_dummy_long_test_package; + procedure drop_dummy_long_test_package; + procedure create_ut3_suite; + procedure drop_ut3_suite; + function get_schema_ut_packages(a_owner in varchar2) return ut3_develop.ut_object_names; + + function ut_output_buffer_tmp return t_out_buff_tab pipelined; + procedure delete_buffer; + + function get_annotation_cache_info_cur( + a_owner varchar2, + a_type varchar2 + ) return sys_refcursor; + + function get_annotation_cache_cursor( + a_owner varchar2, + a_type varchar2, + a_name varchar2 := null + ) return sys_refcursor; + +end; +/ diff --git a/test/ut3_tester_helper/test_dummy_dble_nest_lst_obj.tps b/test/ut3_tester_helper/test_dummy_dble_nest_lst_obj.tps new file mode 100644 index 000000000..5134fef21 --- /dev/null +++ b/test/ut3_tester_helper/test_dummy_dble_nest_lst_obj.tps @@ -0,0 +1,17 @@ +declare + l_exists integer; +begin + select count(1) into l_exists from user_types where type_name = 'TEST_DUMMY_DBLE_NEST_LST_OBJ'; + if l_exists > 0 then + execute immediate 'drop type test_dummy_dble_nest_lst_obj force'; + end if; +end; +/ + +CREATE TYPE test_dummy_dble_nest_lst_obj AS OBJECT +( + some_number_id NUMBER, + some_name VARCHAR2 (25), + dummy_list test_dummy_double_nested_list +); +/ \ No newline at end of file diff --git a/test/ut3_tester_helper/test_dummy_double_nested_list.tps b/test/ut3_tester_helper/test_dummy_double_nested_list.tps new file mode 100644 index 000000000..625462824 --- /dev/null +++ b/test/ut3_tester_helper/test_dummy_double_nested_list.tps @@ -0,0 +1,13 @@ +declare + l_exists integer; +begin + select count(1) into l_exists from user_types where type_name = 'TEST_DUMMY_DOUBLE_NESTED_LIST'; + if l_exists > 0 then + execute immediate 'drop type test_dummy_double_nested_list force'; + end if; +end; +/ + +CREATE TYPE test_dummy_double_nested_list AS + TABLE OF test_dummy_nested_object_list; +/ diff --git a/test/ut3_tester_helper/test_dummy_double_nested_object.tps b/test/ut3_tester_helper/test_dummy_double_nested_object.tps new file mode 100644 index 000000000..8f74f7ecb --- /dev/null +++ b/test/ut3_tester_helper/test_dummy_double_nested_object.tps @@ -0,0 +1,15 @@ +declare + l_exists integer; +begin + select count(1) into l_exists from user_types where type_name = 'TEST_DUMMY_DOUBLE_NESTED_OBJ'; + if l_exists > 0 then + execute immediate 'drop type test_dummy_double_nested_obj force'; + end if; +end; +/ + +create or replace type test_dummy_double_nested_obj as object ( + first_double_nested_obj test_dummy_nested_object, + "Value" varchar2(30) +) +/ \ No newline at end of file diff --git a/test/ut3_tester_helper/test_dummy_nested_object.tps b/test/ut3_tester_helper/test_dummy_nested_object.tps new file mode 100644 index 000000000..6aef3bef8 --- /dev/null +++ b/test/ut3_tester_helper/test_dummy_nested_object.tps @@ -0,0 +1,15 @@ +declare + l_exists integer; +begin + select count(1) into l_exists from user_types where type_name = 'TEST_DUMMY_NESTED_OBJECT'; + if l_exists > 0 then + execute immediate 'drop type test_dummy_nested_object force'; + end if; +end; +/ + +create or replace type test_dummy_nested_object as object ( + first_nested_obj test_dummy_object, + sec_nested_obj test_dummy_object +) +/ \ No newline at end of file diff --git a/test/ut3_tester_helper/test_dummy_nested_object_list.tps b/test/ut3_tester_helper/test_dummy_nested_object_list.tps new file mode 100644 index 000000000..fd47b55bd --- /dev/null +++ b/test/ut3_tester_helper/test_dummy_nested_object_list.tps @@ -0,0 +1,15 @@ +declare + l_exists integer; +begin + select count(1) into l_exists from user_types where type_name = 'TEST_DUMMY_NESTED_OBJECT_LIST'; + if l_exists > 0 then + execute immediate 'drop type test_dummy_nested_object_list force'; + end if; +end; +/ + +create or replace type test_dummy_nested_object_list as object ( + first_nested_obj test_dummy_object_list, + somename varchar2(50) +) +/ \ No newline at end of file diff --git a/test/ut3_tester_helper/test_dummy_number.tps b/test/ut3_tester_helper/test_dummy_number.tps new file mode 100644 index 000000000..b6283c93b --- /dev/null +++ b/test/ut3_tester_helper/test_dummy_number.tps @@ -0,0 +1,14 @@ +declare + l_exists integer; +begin + select count(1) into l_exists from user_types where type_name = 'TEST_DUMMY_NUMBER'; + if l_exists > 0 then + execute immediate 'drop type test_dummy_number force'; + end if; +end; +/ + +create or replace type test_dummy_number as object ( + id number +) +/ diff --git a/test/helpers/test_dummy_object.tps b/test/ut3_tester_helper/test_dummy_object.tps similarity index 99% rename from test/helpers/test_dummy_object.tps rename to test/ut3_tester_helper/test_dummy_object.tps index 4305f73ce..7f095fc0a 100644 --- a/test/helpers/test_dummy_object.tps +++ b/test/ut3_tester_helper/test_dummy_object.tps @@ -13,4 +13,4 @@ create or replace type test_dummy_object as object ( "name" varchar2(30), "Value" varchar2(30) ) -/ \ No newline at end of file +/ diff --git a/test/ut3_tester_helper/test_dummy_object_list.tps b/test/ut3_tester_helper/test_dummy_object_list.tps new file mode 100644 index 000000000..849974da1 --- /dev/null +++ b/test/ut3_tester_helper/test_dummy_object_list.tps @@ -0,0 +1,12 @@ +declare + l_exists integer; +begin + select count(1) into l_exists from user_types where type_name = 'TEST_DUMMY_OBJECT_LIST'; + if l_exists > 0 then + execute immediate 'drop type test_dummy_object_list force'; + end if; +end; +/ + +create or replace type test_dummy_object_list as table of test_dummy_object +/ diff --git a/test/ut3_tester_helper/test_event_list.tps b/test/ut3_tester_helper/test_event_list.tps new file mode 100644 index 000000000..8abf71b13 --- /dev/null +++ b/test/ut3_tester_helper/test_event_list.tps @@ -0,0 +1,2 @@ +create or replace type test_event_list as table of test_event_object; +/ diff --git a/test/ut3_tester_helper/test_event_object.tps b/test/ut3_tester_helper/test_event_object.tps new file mode 100644 index 000000000..da458d2c2 --- /dev/null +++ b/test/ut3_tester_helper/test_event_object.tps @@ -0,0 +1,15 @@ +declare + l_exists integer; +begin + select count(1) into l_exists from user_types where type_name = 'TEST_EVENT_OBJECT'; + if l_exists > 0 then + execute immediate 'drop type test_event_object force'; + end if; +end; +/ + +create or replace type test_event_object as object ( + event_type varchar2(1000), + event_doc xmltype +) +/ \ No newline at end of file diff --git a/test/ut3_tester_helper/test_nested_tab_varray.tps b/test/ut3_tester_helper/test_nested_tab_varray.tps new file mode 100644 index 000000000..9f58d090e --- /dev/null +++ b/test/ut3_tester_helper/test_nested_tab_varray.tps @@ -0,0 +1,14 @@ +declare + l_exists integer; +begin + select count(1) into l_exists from user_types where type_name = 'TEST_NESTED_TAB_VARRAY'; + if l_exists > 0 then + execute immediate 'drop type test_nested_tab_varray force'; + end if; +end; +/ + +create or replace type test_nested_tab_varray as object ( + n_varray t_varray +) +/ diff --git a/test/ut3_tester_helper/test_tab_varchar2.tps b/test/ut3_tester_helper/test_tab_varchar2.tps new file mode 100644 index 000000000..17086292a --- /dev/null +++ b/test/ut3_tester_helper/test_tab_varchar2.tps @@ -0,0 +1,12 @@ +declare + l_exists integer; +begin + select count(1) into l_exists from user_types where type_name = 'T_TAB_VARCHAR'; + if l_exists > 0 then + execute immediate 'drop type t_tab_varchar force'; + end if; +end; +/ + +create or replace type t_tab_varchar is table of varchar2(1) +/ \ No newline at end of file diff --git a/test/ut3_tester_helper/test_tab_varray.tps b/test/ut3_tester_helper/test_tab_varray.tps new file mode 100644 index 000000000..3c684afca --- /dev/null +++ b/test/ut3_tester_helper/test_tab_varray.tps @@ -0,0 +1,13 @@ +declare + l_exists integer; +begin + select count(1) into l_exists from user_types where type_name = 'T_VARRAY'; + if l_exists > 0 then + execute immediate 'drop type t_varray force'; + end if; +end; +/ + + +create or replace type t_varray is varray(1) of number +/ \ No newline at end of file diff --git a/test/ut3_tester_helper/ut_example_tests.pkb b/test/ut3_tester_helper/ut_example_tests.pkb new file mode 100644 index 000000000..7e795d184 --- /dev/null +++ b/test/ut3_tester_helper/ut_example_tests.pkb @@ -0,0 +1,36 @@ +create or replace package body ut_example_tests +as + procedure create_synonym is + pragma autonomous_transaction; + begin + execute immediate 'create or replace synonym ut3_tester.ut_example_tests for ut3_tester_helper.ut_example_tests'; + end; + + procedure drop_synonym is + pragma autonomous_transaction; + begin + execute immediate 'drop synonym ut3_tester.ut_example_tests'; + end; + + procedure set_g_number_0 as + begin + g_number := 0; + end; + + procedure add_1_to_g_number as + begin + g_number := g_number + 1; + end; + + procedure failing_procedure as + begin + g_number := 1 / 0; + end; + + procedure ut_commit_test is + begin + commit; + end; + +end; +/ diff --git a/test/ut3_tester_helper/ut_example_tests.pks b/test/ut3_tester_helper/ut_example_tests.pks new file mode 100644 index 000000000..a62c02332 --- /dev/null +++ b/test/ut3_tester_helper/ut_example_tests.pks @@ -0,0 +1,12 @@ +create or replace package ut_example_tests is + g_number number; + + procedure create_synonym; + procedure drop_synonym; + + procedure set_g_number_0; + procedure add_1_to_g_number; + procedure failing_procedure; + procedure ut_commit_test; +end; +/ diff --git a/test/helpers/ut_test_table.sql b/test/ut3_tester_helper/ut_test_table.sql similarity index 80% rename from test/helpers/ut_test_table.sql rename to test/ut3_tester_helper/ut_test_table.sql index bccd07bc4..c4832a10f 100644 --- a/test/helpers/ut_test_table.sql +++ b/test/ut3_tester_helper/ut_test_table.sql @@ -9,3 +9,4 @@ end; / create table ut$test_table (val varchar2(1)); +grant select,insert,update,delete on ut$test_table to public; diff --git a/test/ut3_user/api/test_ut_run.pkb b/test/ut3_user/api/test_ut_run.pkb new file mode 100644 index 000000000..f0cfd8373 --- /dev/null +++ b/test/ut3_user/api/test_ut_run.pkb @@ -0,0 +1,1657 @@ +create or replace package body test_ut_run is + + gc_owner constant varchar2(250) := sys_context('userenv', 'current_schema'); + gc_module constant varchar2(32767) := 'test module'; + gc_action constant varchar2(32767) := 'test action'; + gc_client_info constant varchar2(32767) := 'test client info'; + + g_context_test_results clob; + g_timestamp timestamp; + + procedure clear_expectations is + begin + ut3_tester_helper.main_helper.clear_expectations(); + end; + + procedure create_ut3_user_tests is + begin + ut3_tester_helper.run_helper.create_ut3_user_tests(); + end; + + procedure drop_ut3_user_tests is + begin + ut3_tester_helper.run_helper.drop_ut3_user_tests(); + end; + + procedure ut_version is + begin + ut.expect(ut3_develop.ut.version()).to_match('^v\d+\.\d+\.\d+\.\d+(-\w+)?$'); + end; + + procedure ut_fail is + begin + --Act + ut3_develop.ut.fail('Testing failure message'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations(1)) + .to_be_like('%Testing failure message%'); + end; + + procedure run_proc_no_params is + l_results clob; + begin + ut3_tester_helper.run_helper.run(); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); + end; + + procedure run_proc_specific_reporter is + l_results clob; + begin + --Act + ut3_develop.ut.run('ut3_tester_helper',a_reporter => ut3_develop.ut_documentation_reporter() ); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); + end; + + procedure run_proc_cov_file_list is + l_results clob; + begin + --Act + ut3_develop.ut.run( + 'ut3_tester_helper', + a_reporter => ut3_develop.ut_sonar_test_reporter(), + a_source_files => ut3_develop.ut_varchar2_list(), + a_test_files => ut3_develop.ut_varchar2_list('tests/ut3_tester_helper.test_package_1.pkb', + 'tests/ut3_tester_helper.test_package_2.pkb', + 'tests/ut3_tester_helper.test_package_3.pkb') + ); + + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%tests/ut3_tester_helper.test_package_2.pkb'|| + '%tests/ut3_tester_helper.test_package_1.pkb'|| + '%tests/ut3_tester_helper.test_package_3.pkb%' ); + end; + + procedure run_proc_pkg_name is + l_results clob; + begin + ut3_develop.ut.run('ut3_tester_helper.test_package_1'); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%test_package_1%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_2%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_3%' ); + end; + + procedure run_proc_pkg_name_file_list is + l_results clob; + begin + ut3_develop.ut.run( + 'ut3_tester_helper.test_package_3', + ut3_develop.ut_sonar_test_reporter(), a_source_files => ut3_develop.ut_varchar2_list(), + a_test_files => ut3_develop.ut_varchar2_list('tests/ut3_tester_helper.test_package_1.pkb', + 'tests/ut3_tester_helper.test_package_2.pkb', + 'tests/ut3_tester_helper.test_package_3.pkb') + ); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%tests/ut3_tester_helper.test_package_3.pkb%' ); + ut.expect( l_results ).not_to_be_like( '%tests/ut3_tester_helper.test_package_1.pkb%' ); + ut.expect( l_results ).not_to_be_like( '%tests/ut3_tester_helper.test_package_2.pkb%' ); + end; + + procedure run_proc_path_list is + l_results clob; + begin + ut3_tester_helper.run_helper.run(ut3_develop.ut_varchar2_list(':tests.test_package_1',':tests')); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%test_package_1%' ); + ut.expect( l_results ).to_be_like( '%test_package_2%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_3%' ); + end; + + procedure run_proc_path_list_file_list is + l_results clob; + begin + ut3_tester_helper.run_helper.run( + a_paths => ut3_develop.ut_varchar2_list(':tests.test_package_1',':tests'), + a_reporter => ut3_develop.ut_sonar_test_reporter(), + a_test_files => ut3_develop.ut_varchar2_list('tests/ut3_tester_helper.test_package_1.pkb', + 'tests/ut3_tester_helper.test_package_2.pkb', + 'tests/ut3_tester_helper.test_package_3.pkb') + ); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%tests/ut3_tester_helper.test_package_1.pkb%' ); + ut.expect( l_results ).to_be_like( '%tests/ut3_tester_helper.test_package_2.pkb%' ); + ut.expect( l_results ).not_to_be_like( '%tests/ut3_tester_helper.test_package_3.pkb%' ); + end; + + procedure run_proc_null_reporter is + l_results clob; + begin + --Act + ut3_develop.ut.run('ut3_tester_helper', cast(null as ut3_develop.ut_reporter_base)); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%tests%test_package_1%test_package_2%tests2%test_package_3%' ); + end; + + procedure run_proc_null_path is + l_results clob; + begin + --Act + ut3_tester_helper.run_helper.run(cast(null as varchar2)); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); + end; + + procedure run_proc_null_path_list is + l_results clob; + l_paths ut3_develop.ut_varchar2_list; + begin + --Act + ut3_tester_helper.run_helper.run(l_paths); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); + end; + + procedure run_proc_empty_path_list is + l_results clob; + begin + --Act + ut3_tester_helper.run_helper.run(ut3_develop.ut_varchar2_list()); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + 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_develop.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_develop.ut.run('test_commit_warning'); + l_results := ut3_tester_helper.main_helper.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_develop.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_develop.ut.run('child_suite'); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + ut.expect(l_results).to_be_like( + '%1) does_stuff%' || + 'ORA-01403: no data found%' || + 'ORA-06512: at "UT3_USER.PARENT_SUITE%' + ); + end; + + procedure transaction_setup is + pragma autonomous_transaction; + begin + execute immediate 'create table transaction_test_table(message varchar2(100))'; + execute immediate 'create or replace package test_transaction is + --%suite + + --%test + procedure insert_row; + + --%test + procedure insert_and_raise; + end; + '; + execute immediate 'create or replace package body test_transaction is + procedure insert_row is + begin + insert into transaction_test_table values (''2 - inside the test_transaction.insert_row test''); + end; + procedure insert_and_raise is + begin + insert into transaction_test_table values (''2 - inside the test_transaction.insert_row test''); + raise no_data_found; + end; + end; + '; + + end; + + procedure transaction_cleanup is + pragma autonomous_transaction; + begin + begin + execute immediate 'drop table transaction_test_table'; + exception + when others then null; + end; + begin + execute immediate 'drop package test_transaction'; + exception + when others then null; + end; + end; + + procedure run_proc_keep_test_data is + l_expected sys_refcursor; + l_actual sys_refcursor; + l_results clob; + begin + --Arrange + execute immediate ' + insert into transaction_test_table values (''1 - inside the test_ut_run.run_proc_keep_test_changes test'')'; + + --Act + ut3_develop.ut.run('test_transaction.insert_row', a_force_manual_rollback => true); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + + --Assert + open l_expected for + select '1 - inside the test_ut_run.run_proc_keep_test_changes test' as message from dual + union all + select '2 - inside the test_transaction.insert_row test' from dual + order by 1; + + open l_actual for 'select * from transaction_test_table order by 1'; + + ut.expect( l_actual ).to_equal(l_expected); + end; + + procedure run_proc_keep_test_data_raise is + l_expected sys_refcursor; + l_actual sys_refcursor; + l_results clob; + begin + --Arrange + execute immediate ' + insert into transaction_test_table values (''1 - inside the test_ut_run.run_proc_keep_test_changes test'')'; + + --Act + ut3_develop.ut.run('test_transaction.insert_and_raise', a_force_manual_rollback => true); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + + --Assert + open l_expected for + select '1 - inside the test_ut_run.run_proc_keep_test_changes test' as message from dual + union all + select '2 - inside the test_transaction.insert_row test' from dual + order by 1; + + open l_actual for 'select * from transaction_test_table order by 1'; + + ut.expect( l_actual ).to_equal(l_expected); + end; + + procedure run_proc_discard_test_data is + l_expected sys_refcursor; + l_actual sys_refcursor; + l_results clob; + begin + --Arrange + execute immediate ' + insert into transaction_test_table values (''1 - inside the test_ut_run.run_proc_keep_test_changes test'')'; + + --Act + ut3_develop.ut.run('test_transaction.insert_row'); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + + --Assert + open l_expected for + select '1 - inside the test_ut_run.run_proc_keep_test_changes test' as message from dual; + + open l_actual for 'select * from transaction_test_table order by 1'; + + ut.expect( l_actual ).to_equal(l_expected); + end; + + procedure run_func_no_params is + l_results ut3_develop.ut_varchar2_list; + begin + l_results := ut3_tester_helper.run_helper.run(); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); + end; + + procedure run_func_specific_reporter is + l_results ut3_develop.ut_varchar2_list; + begin + --Act + l_results := ut3_tester_helper.run_helper.run(ut3_develop.ut_documentation_reporter()); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); + end; + + procedure run_func_cov_file_list is + l_results ut3_develop.ut_varchar2_list; + begin + --Act + select * bulk collect into l_results from table ( + ut3_develop.ut.run('ut3_tester_helper', + ut3_develop.ut_sonar_test_reporter(), + a_source_files => ut3_develop.ut_varchar2_list(), + a_test_files => ut3_develop.ut_varchar2_list('tests/ut3_tester_helper.test_package_1.pkb', + 'tests/ut3_tester_helper.test_package_2.pkb', + 'tests/ut3_tester_helper.test_package_3.pkb') + )); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%tests/ut3_tester_helper.test_package_2.pkb%tests/ut3_tester_helper.test_package_1.pkb%tests/ut3_tester_helper.test_package_3.pkb%' ); + end; + + procedure run_func_pkg_name is + l_results ut3_develop.ut_varchar2_list; + begin + select * bulk collect into l_results from table (ut3_develop.ut.run('ut3_tester_helper.test_package_1')); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_2%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_3%' ); + end; + + procedure run_func_pkg_name_file_list is + l_results ut3_develop.ut_varchar2_list; + begin + select * bulk collect into l_results from table ( + ut3_develop.ut.run('ut3_tester_helper.test_package_3', + ut3_develop.ut_sonar_test_reporter(), + a_source_files => ut3_develop.ut_varchar2_list(), + a_test_files => ut3_develop.ut_varchar2_list('tests/ut3_tester_helper.test_package_1.pkb', + 'tests/ut3_tester_helper.test_package_2.pkb', + 'tests/ut3_tester_helper.test_package_3.pkb') + )); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%tests/ut3_tester_helper.test_package_3.pkb%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%tests/ut3_tester_helper.test_package_1.pkb%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%tests/ut3_tester_helper.test_package_2.pkb%' ); + end; + + procedure run_func_path_list is + l_results ut3_develop.ut_varchar2_list; + begin + l_results := ut3_tester_helper.run_helper.run(ut3_develop.ut_varchar2_list(':tests.test_package_1',':tests')); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_2%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_3%' ); + end; + + procedure run_func_path_list_file_list is + l_results ut3_develop.ut_varchar2_list; + begin + l_results := ut3_tester_helper.run_helper.run( + a_paths => ut3_develop.ut_varchar2_list(':tests.test_package_1',':tests'), + a_reporter => ut3_develop.ut_sonar_test_reporter(), + a_test_files => ut3_develop.ut_varchar2_list('tests/ut3_tester_helper.test_package_1.pkb', + 'tests/ut3_tester_helper.test_package_2.pkb', + 'tests/ut3_tester_helper.test_package_3.pkb') + ); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%tests/ut3_tester_helper.test_package_1.pkb%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%tests/ut3_tester_helper.test_package_2.pkb%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%tests/ut3_tester_helper.test_package_3.pkb%' ); + end; + + procedure run_func_null_reporter is + l_results ut3_develop.ut_varchar2_list; + begin + --Act + select * bulk collect into l_results from table (ut3_develop.ut.run('ut3_tester_helper',cast(null as ut3_develop.ut_reporter_base))); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%tests%test_package_1%test_package_2%tests2%test_package_3%' ); + end; + + procedure run_func_null_path is + l_results ut3_develop.ut_varchar2_list; + begin + --Act + l_results := ut3_tester_helper.run_helper.run(cast(null as varchar2)); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); + end; + + procedure run_func_null_path_list is + l_results ut3_develop.ut_varchar2_list; + l_paths ut3_develop.ut_varchar2_list; + begin + --Act + l_results := ut3_tester_helper.run_helper.run(l_paths); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); + end; + + procedure run_func_empty_path_list is + l_results ut3_develop.ut_varchar2_list; + begin + --Act + l_results := ut3_tester_helper.run_helper.run(ut3_develop.ut_varchar2_list()); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); + end; + + procedure run_func_cov_file_lst_null_rep is + l_results ut3_develop.ut_varchar2_list; + begin + --Act + l_results := ut3_tester_helper.run_helper.run( + a_test_files => ut3_develop.ut_varchar2_list('tests/ut3_tester_helper.test_package_1.pkb', + 'tests/ut3_tester_helper.test_package_2.pkb', + 'tests/ut3_tester_helper.test_package_3.pkb'), + a_reporter => cast(null as ut3_develop.ut_reporter_base)); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); + end; + + procedure run_func_empty_suite is + l_results ut3_develop.ut_varchar2_list; + l_expected varchar2(32767); + pragma autonomous_transaction; + begin + --Arrange + execute immediate q'[create or replace package empty_suite as + -- %suite + + procedure not_a_test; + end;]'; + execute immediate q'[create or replace package body empty_suite as + procedure not_a_test is begin null; end; + end;]'; + l_expected := '%empty_suite%0 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'; + --Act + select * bulk collect into l_results from table(ut3_develop.ut.run('empty_suite')); + + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( l_expected ); + + --Cleanup + execute immediate q'[drop package empty_suite]'; + end; + + procedure raise_in_invalid_state is + l_results ut3_develop.ut_varchar2_list; + l_expected varchar2(32767); + begin + --Arrange + l_expected := 'test_state + test_stateful + failing_stateful_test [% sec] (FAILED - 1)% +Failures:% + 1) failing_stateful_test + ORA-04068: existing state of packages (DB_LOOPBACK%) has been discarded + ORA-04061: existing state of package body "%.STATEFUL_PACKAGE" has been invalidated + ORA-04065: not executed, altered or dropped package body "%.STATEFUL_PACKAGE"% + ORA-06512: at line 6% +1 tests, 0 failed, 1 errored, 0 disabled, 0 warning(s)%'; + + --Act + select * bulk collect into l_results from table(ut3_develop.ut.run('ut3_tester_helper.test_stateful')); + + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( l_expected ); + ut.fail('Expected exception but nothing was raised'); + exception + when others then + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( l_expected ); + ut.expect(sqlcode).to_equal(-4068); + end; + + procedure create_test_suite is + begin + ut3_tester_helper.run_helper.create_test_suite; + end; + + procedure drop_test_suite is + begin + ut3_tester_helper.run_helper.drop_test_suite; + end; + + procedure run_in_invalid_state is + l_results ut3_develop.ut_varchar2_list; + l_actual clob; + l_expected varchar2(32767); + begin + select * bulk collect into l_results from table(ut3_develop.ut.run('failing_invalid_spec')); + + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + ut.expect(l_actual).to_be_like('%Call params for % are not valid: package %FAILING_INVALID_SPEC% does not exist or is invalid.%'); + + end; + + procedure compile_invalid_package is + ex_compilation_error exception; + pragma exception_init(ex_compilation_error,-24344); + pragma autonomous_transaction; + begin + begin + execute immediate q'[ + create or replace package failing_invalid_spec as + --%suite + gv_glob_val non_existing_table.id%type := 0; + + --%test + procedure test1; + end;]'; + exception when ex_compilation_error then null; + end; + begin + execute immediate q'[ + create or replace package body failing_invalid_spec as + procedure test1 is begin ut.expect(1).to_equal(1); end; + end;]'; + exception when ex_compilation_error then null; + end; + end; + procedure drop_invalid_package is + pragma autonomous_transaction; + begin + execute immediate 'drop package failing_invalid_spec'; + end; + + procedure run_and_revalidate_specs is + l_results ut3_develop.ut_varchar2_list; + l_actual clob; + l_is_invalid number; + begin + execute immediate q'[select count(1) from all_objects o where o.owner = :object_owner and o.object_type = 'PACKAGE' + and o.status = 'INVALID' and o.object_name= :object_name]' into l_is_invalid + using 'UT3_USER','INVALID_PCKAG_THAT_REVALIDATES'; + + select * bulk collect into l_results from table(ut3_develop.ut.run('invalid_pckag_that_revalidates')); + + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + ut.expect(1).to_equal(l_is_invalid); + ut.expect(l_actual).to_be_like('%invalid_pckag_that_revalidates%invalidspecs [% sec]% +%Finished in % seconds% +%1 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'); + + end; + + procedure generate_invalid_spec is + ex_compilation_error exception; + pragma exception_init(ex_compilation_error,-24344); + pragma autonomous_transaction; + begin + + execute immediate q'[ + create or replace package parent_specs as + c_test constant varchar2(1) := 'Y'; + end;]'; + + execute immediate q'[ + create or replace package invalid_pckag_that_revalidates as + --%suite + g_var varchar2(1) := parent_specs.c_test; + + --%test(invalidspecs) + procedure test1; + end;]'; + + execute immediate q'[ + create or replace package body invalid_pckag_that_revalidates as + procedure test1 is begin ut.expect('Y').to_equal(g_var); end; + end;]'; + + -- That should invalidate test package and we can then revers + execute immediate q'[ + create or replace package parent_specs as + c_test_error constant varchar2(1) := 'Y'; + end;]'; + + execute immediate q'[ + create or replace package parent_specs as + c_test constant varchar2(1) := 'Y'; + end;]'; + + end; + procedure drop_invalid_spec is + pragma autonomous_transaction; + begin + execute immediate 'drop package invalid_pckag_that_revalidates'; + execute immediate 'drop package parent_specs'; + end; + + procedure run_and_report_warnings is + l_results ut3_develop.ut_varchar2_list; + l_actual clob; + begin + + select * bulk collect into l_results from table(ut3_develop.ut.run('bad_annotations')); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + + ut.expect(l_actual).to_be_like('%Missing "--%endcontext" annotation for a "--%context" annotation. The end of package is considered end of context.% +%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; + + procedure create_suite_with_link is + begin + ut3_tester_helper.run_helper.create_suite_with_link; + end; + + procedure drop_suite_with_link is + begin + ut3_tester_helper.run_helper.drop_suite_with_link; + end; + + procedure savepoints_on_db_links is + l_results clob; + begin + ut3_develop.ut.run('ut3_tester_helper.test_distributed_savepoint'); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + ut.expect(l_results).to_be_like('%1 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'); + end; + + procedure remove_time_from_results(a_results in out nocopy ut3_develop.ut_varchar2_list) is + begin + for i in 1 .. a_results.count loop + a_results(i) := regexp_replace(a_results(i),'\[[0-9]*[\.,]?[0-9]+ sec\]',''); + a_results(i) := regexp_replace(a_results(i),'Finished in [0-9]*[\.,][0-9]+ seconds',''); + end loop; + end; + + procedure run_schema_name_test is + l_results ut3_develop.ut_varchar2_list; + l_expected clob; + begin + select * bulk collect into l_results + from table ( ut3_develop.ut.run( gc_owner||'.'||gc_owner ) ); + l_expected := '%1 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'; + ut.expect(ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( l_expected ); + end; + + procedure create_schema_name_package is + pragma autonomous_transaction; + begin + execute immediate ' + create or replace package '||gc_owner||'.'||gc_owner||' as + --%suite + + --%test + procedure sample_test; + end;'; + + execute immediate ' + create or replace package body '||gc_owner||'.'||gc_owner||' as + procedure sample_test is begin ut.expect(1).to_equal(1); end; + end;'; + + end; + + procedure drop_schema_name_package is + pragma autonomous_transaction; + begin + execute immediate 'drop package '||gc_owner||'.'||gc_owner; + end; + + procedure create_suites_with_path is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package ut_abc is + -- %suite + -- %suitepath(main.abc) + + -- %test + procedure ut_test_01; + end ut_abc;]'; + + execute immediate q'[create or replace package body ut_abc + is + procedure ut_test_01 as begin ut.expect(true).to_be_true(); end; + end;]'; + + execute immediate q'[create or replace package ut_abc_def + is + -- %suite + -- %suitepath(main.abc_def) + + -- %test + procedure ut_test_01; + end ut_abc_def;]'; + + execute immediate q'[create or replace package body ut_abc_def + is + procedure ut_test_01 as begin ut.expect(true).to_be_true(); end; + end;]'; + + end; + + procedure drop_suites_with_path is + pragma autonomous_transaction; + begin + execute immediate q'[drop package ut_abc]'; + execute immediate q'[drop package ut_abc_def]'; + end; + + procedure run_suite_with_nls_sort is + L_current_sort varchar2(2000); + l_results ut3_develop.ut_varchar2_list; + l_expected clob; + begin + --Arrange + select value + into l_current_sort + from nls_session_parameters where parameter = 'NLS_SORT'; + + execute immediate 'alter session set nls_sort=GERMAN'; + + --Act + select * + bulk collect into l_results + from table ( ut3_develop.ut.run( gc_owner||':main' ) ); + --Assert + l_expected := q'[main% + abc_def% + ut_abc_def% + ut_test_01% + abc% + ut_abc% + ut_test_01%]'; + ut.expect(ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( l_expected ); + + execute immediate 'alter session set nls_sort='||l_current_sort; + end; + + procedure run_with_random_order is + l_random_results ut3_develop.ut_varchar2_list; + l_results ut3_develop.ut_varchar2_list; + begin + select * bulk collect into l_random_results + from table ( ut3_develop.ut.run( 'ut3_tester_helper.test_package_1', a_random_test_order_seed => 6 ) ) + where trim(column_value) is not null and column_value not like 'Finished in %' + and column_value not like '%Tests were executed with random order %'; + + select * bulk collect into l_results + from table ( ut3_develop.ut.run( 'ut3_tester_helper.test_package_1' ) ) + --TODO this condition should be removed once issues with unordered compare and 'blank text rows' are resolved. + where trim(column_value) is not null and column_value not like 'Finished in %'; + + remove_time_from_results(l_results); + remove_time_from_results(l_random_results); + + ut.expect(anydata.convertCollection(l_random_results)).to_equal(anydata.convertCollection(l_results)).unordered(); + ut.expect(anydata.convertCollection(l_random_results)).not_to_equal(anydata.convertCollection(l_results)); + end; + + procedure run_and_report_random_ord_seed is + l_actual ut3_develop.ut_varchar2_list; + begin + select * bulk collect into l_actual + from table ( ut3_develop.ut.run( 'ut3_tester_helper.test_package_1', a_random_test_order_seed => 123456789 ) ); + + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_actual) ).to_be_like( q'[%Tests were executed with random order seed '123456789'.%]' ); + end; + + procedure run_with_random_order_seed is + l_expected ut3_develop.ut_varchar2_list; + l_actual ut3_develop.ut_varchar2_list; + begin + + select * bulk collect into l_expected + from table ( ut3_develop.ut.run( 'ut3_tester_helper.test_package_1', a_random_test_order_seed => 3 ) ); + select * bulk collect into l_actual + from table ( ut3_develop.ut.run( 'ut3_tester_helper.test_package_1', a_random_test_order_seed => 3 ) ); + + remove_time_from_results(l_actual); + remove_time_from_results(l_expected); + l_actual.delete(l_actual.count); + l_expected.delete(l_expected.count); + + ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); + end; + + procedure test_run_by_one_tag is + l_results clob; + begin + ut3_tester_helper.run_helper.run(a_tags => 'suite1test1'); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%test_package_1%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_2%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_3%' ); + end; + + procedure suite_run_by_one_tag is + l_results clob; + begin + ut3_tester_helper.run_helper.run(a_tags => 'suite2'); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).not_to_be_like( '%test_package_1.%executed%' ); + ut.expect( l_results ).to_be_like( '%test_package_1%' ); + ut.expect( l_results ).to_be_like( '%test_package_2%' ); + ut.expect( l_results ).to_be_like( '%test_package_2.%executed%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_3.%executed%' ); + end; + + procedure two_test_run_by_one_tag is + l_results clob; + begin + ut3_tester_helper.run_helper.run(a_tags => 'test2'); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).not_to_be_like( '%test_package_1.%executed%' ); + ut.expect( l_results ).to_be_like( '%test_package_1%' ); + ut.expect( l_results ).to_be_like( '%test_package_2%' ); + ut.expect( l_results ).to_be_like( '%test_package_2.%executed%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_3.%executed%' ); + end; + + procedure all_suites_run_by_one_tag is + l_results clob; + begin + ut3_tester_helper.run_helper.run(a_tags => 'helper'); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%test_package_1%' ); + ut.expect( l_results ).to_be_like( '%test_package_2%' ); + ut.expect( l_results ).to_be_like( '%test_package_3%' ); + end; + + procedure two_test_run_by_two_tags is + l_results clob; + begin + ut3_tester_helper.run_helper.run(a_tags => 'subtest1|subtest2'); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%test_package_1%' ); + ut.expect( l_results ).to_be_like( '%test_package_2%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_1.test2%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_2.test2%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_3%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_3%' ); + end; + + procedure two_test_run_by_two_tags_leg is + l_results clob; + begin + ut3_tester_helper.run_helper.run(a_tags => 'subtest1,subtest2'); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%test_package_1%' ); + ut.expect( l_results ).to_be_like( '%test_package_2%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_1.test2%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_2.test2%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_3%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_3%' ); + end; + + procedure suite_with_children_tag is + l_results clob; + begin + ut3_tester_helper.run_helper.run(a_tags => 'suite1'); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%test_package_1%' ); + ut.expect( l_results ).to_be_like( '%test_package_2%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_3%' ); + end; + + procedure suite_with_tag_parent is + l_results clob; + begin + ut3_tester_helper.run_helper.run(a_tags => 'suite2'); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%test_package_1%' ); + ut.expect( l_results ).to_be_like( '%test_package_2%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_3%' ); + end; + + procedure test_nonexists_tag is + l_results clob; + l_exp_message varchar2(4000); + begin + ut3_tester_helper.run_helper.run(a_tags => 'nonexisting'); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + ut.expect( l_results ).not_to_be_like( '%test_package_1%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_2%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_3%' ); + end; + + procedure test_duplicate_tag is + l_results clob; + begin + ut3_tester_helper.run_helper.run(a_tags => 'suite1test1,suite1test1'); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%test_package_1%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_2%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_3%' ); + end; + + procedure suite_duplicate_tag is + l_results clob; + begin + ut3_tester_helper.run_helper.run(a_tags => 'suite1,suite1'); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%test_package_1%' ); + ut.expect( l_results ).to_be_like( '%test_package_2%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_3%' ); + end; + + procedure run_proc_pkg_name_tag is + l_results clob; + begin + ut3_develop.ut.run('ut3_tester_helper.test_package_1',a_tags => 'suite1test1'); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%test_package_1%' ); + ut.expect( l_results ).to_be_like( '%test_package_1.test1%executed%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_1.test2%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_2%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_3%' ); + end; + + procedure run_pkg_name_file_list_tag is + l_results clob; + begin + ut3_develop.ut.run('ut3_tester_helper.test_package_1',a_tags => 'suite1test1'); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%test_package_1%' ); + ut.expect( l_results ).to_be_like( '%test_package_1.test1%executed%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_1.test2%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_2%' ); + ut.expect( l_results ).not_to_be_like( '%test_package_3%' ); + end; + + procedure run_proc_path_list_tag is + l_results clob; + begin + ut3_develop.ut.run( + 'ut3_tester_helper.test_package_1', + ut3_develop.ut_sonar_test_reporter(), a_source_files => ut3_develop.ut_varchar2_list(),a_tags => 'suite1', + a_test_files => ut3_develop.ut_varchar2_list('tests/ut3_tester_helper.test_package_1.pkb', + 'tests/ut3_tester_helper.test_package_2.pkb', + 'tests/ut3_tester_helper.test_package_3.pkb') + ); + l_results := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + --Assert + ut.expect( l_results ).to_be_like( '%tests/ut3_tester_helper.test_package_1.pkb%' ); + ut.expect( l_results ).not_to_be_like( '%tests/ut3_tester_helper.test_package_2.pkb%' ); + ut.expect( l_results ).not_to_be_like( '%tests/ut3_tester_helper.test_package_3.pkb%' ); + end; + + procedure tag_run_func_no_params is + l_results ut3_develop.ut_varchar2_list; + begin + l_results := ut3_tester_helper.run_helper.run(a_tags => 'helper'); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); + end; + + procedure tag_run_func_pkg_name is + l_results ut3_develop.ut_varchar2_list; + begin + select * bulk collect into l_results from table (ut3_develop.ut.run('ut3_tester_helper.test_package_1', a_tags => 'suite1test1')); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1.test1%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_1.test2%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_2%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_3%' ); + end; + + procedure tag_run_func_path_list is + l_results ut3_develop.ut_varchar2_list; + begin + l_results := ut3_tester_helper.run_helper.run(ut3_develop.ut_varchar2_list(':tests.test_package_1',':tests'),a_tags => 'suite1test1|suite2test1'); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_2%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1.test1%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_1.test2%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_2.test1%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_2.test2%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_3%' ); + end; + + procedure tag_run_func_path_list_leg is + l_results ut3_develop.ut_varchar2_list; + begin + l_results := ut3_tester_helper.run_helper.run(ut3_develop.ut_varchar2_list(':tests.test_package_1',':tests'),a_tags => 'suite1test1,suite2test1'); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_2%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1.test1%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_1.test2%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_2.test1%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_2.test2%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_3%' ); + end; + + procedure tag_inc_exc_run_func_path_list is + l_results ut3_develop.ut_varchar2_list; + begin + l_results := ut3_tester_helper.run_helper.run(ut3_develop.ut_varchar2_list(':tests.test_package_1',':tests'),a_tags => '(suite1test1|suite2test1)&!suite2'); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_2%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1.test1%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_1.test2%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_3%' ); + end; + + procedure tag_inc_exc_run_fun_pth_lst_lg is + l_results ut3_develop.ut_varchar2_list; + begin + l_results := ut3_tester_helper.run_helper.run(ut3_develop.ut_varchar2_list(':tests.test_package_1',':tests'),a_tags => 'suite1test1,suite2test1,-suite2'); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_2%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1.test1%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_1.test2%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_3%' ); + end; + + procedure tag_exclude_run_func_path_list is + l_results ut3_develop.ut_varchar2_list; + begin + l_results := ut3_tester_helper.run_helper.run(ut3_develop.ut_varchar2_list(':tests,:tests2'),a_tags => '!suite1test2&!suite2test1&!test1suite3'); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_2%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_3%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1.test1%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_1.test2%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_2.test1%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_2.test2%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_3.test1%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_3.test2%executed%' ); + end; + +procedure tag_exclude_run_fun_pth_lst_lg is + l_results ut3_develop.ut_varchar2_list; + begin + l_results := ut3_tester_helper.run_helper.run(ut3_develop.ut_varchar2_list(':tests,:tests2'),a_tags => '-suite1test2,-suite2test1,-test1suite3'); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_2%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_3%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1.test1%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_1.test2%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_2.test1%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_2.test2%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_3.test1%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_3.test2%executed%' ); + end; + + procedure tag_include_exclude_run_func is + l_results ut3_develop.ut_varchar2_list; + begin + l_results := ut3_tester_helper.run_helper.run(a_tags => '(suite1)&(!suite1test2&!suite2test1&!test1suite3)'); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_2%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_3%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1.test1%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_1.test2%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_2.test1%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_2.test2%executed%' ); + end; + + procedure tag_include_exclude_run_fun_lg is + l_results ut3_develop.ut_varchar2_list; + begin + l_results := ut3_tester_helper.run_helper.run(a_tags => 'suite1,-suite1test2,-suite2test1,-test1suite3'); + --Assert + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_2%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_3%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_1.test1%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_1.test2%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_2.test1%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_package_2.test2%executed%' ); + end; + + procedure tag_complex_expressions is + l_results ut3_develop.ut_varchar2_list; + begin + l_results := ut3_tester_helper.run_helper.run(a_tags => 'release_3_1_13&(fast|simple)'); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_tag_pkg_3.test5 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_tag_pkg_3.test6 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_1.test1%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_1.test2%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_2.test3%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_2.test4%executed%' ); + + l_results := ut3_tester_helper.run_helper.run(a_tags => 'release_3_1_13&(!patch_3_1_13&!patch_3_1_14)'); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_tag_pkg_1.test1 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_1.test2%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_2.test3%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_2.test4%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_3.test5%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_3.test6%executed%' ); + + l_results := ut3_tester_helper.run_helper.run(a_tags => 'release_3_1_13&(patch_3_1_13&!slow)'); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_tag_pkg_3.test5 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_1.test1%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_1.test2%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_2.test3%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_2.test4%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_3.test6%executed%' ); + + l_results := ut3_tester_helper.run_helper.run(a_tags => '(simple&end_to_end)|(development&fast)'); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_tag_pkg_1.test1 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_tag_pkg_2.test3 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_tag_pkg_3.test5 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_tag_pkg_3.test6 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_1.test2%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_2.test4%executed%' ); + + l_results := ut3_tester_helper.run_helper.run(a_tags => '(!development&end_to_end)'); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%test_tag_pkg_3.test5 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_1.test1%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_1.test2%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_2.test3%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_2.test4%executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_3.test6%executed%' ); + + l_results := ut3_tester_helper.run_helper.run(a_tags => 'any'); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%suite2_level1_pkg.test1_level1 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%suite2_level1_pkg.test2_level1 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%suite1_level1_pkg.test1_level1 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%suite2_2_level2_pkg.suite2_2_test1_level2 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%suite2_2_level2_pkg.suite2_2_test2_level2 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%suite1_2_level2_pkg.suite1_2_test1_level2 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%suite1_2_level2_pkg.suite1_2_test2_level1 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%suite1_1_level2_pkg.suite1_1_test1_level2 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%suite1_level1_pkg.test2_level1 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%suite1_1_level2_pkg.suite1_1_test2_level2 executed%' ); + + l_results := ut3_tester_helper.run_helper.run(a_tags => 'none'); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%suite1_level1_pkg.test2_level1 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%suite1_1_level2_pkg.suite1_1_test2_level2 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%suite2_level1_pkg.test1_level1 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%suite2_level1_pkg.test2_level1 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%suite1_level1_pkg.test1_level1 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%suite2_2_level2_pkg.suite2_2_test1_level2 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%suite2_2_level2_pkg.suite2_2_test2_level2 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%suite1_2_level2_pkg.suite1_2_test1_level2 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%suite1_2_level2_pkg.suite1_2_test2_level1 executed%' ); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%suite1_1_level2_pkg.suite1_1_test1_level2 executed%' ); + + + end; + + procedure invalid_tag_expression is + l_results ut3_develop.ut_varchar2_list; + begin + l_results := ut3_tester_helper.run_helper.run(a_tags => '(!development!&end_to_end)'); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_match('^\s*invalid_tag_expression \[[,\.0-9]+ sec\]\s*$','m'); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like('%(FAILED -%'); + + l_results := ut3_tester_helper.run_helper.run(a_tags => '(!development&&end_to_end)'); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_match('^\s*invalid_tag_expression \[[,\.0-9]+ sec\]\s*$','m'); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like('%(FAILED -%'); + + l_results := ut3_tester_helper.run_helper.run(a_tags => '(!development&end_to_end|)'); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_match('^\s*invalid_tag_expression \[[,\.0-9]+ sec\]\s*$','m'); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like('%(FAILED -%'); + + l_results := ut3_tester_helper.run_helper.run(a_tags => '(!development&!!end_to_end)'); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_match('^\s*invalid_tag_expression \[[,\.0-9]+ sec\]\s*$','m'); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like('%(FAILED -%'); + + l_results := ut3_tester_helper.run_helper.run(a_tags => '(&development&end_to_end)'); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_match('^\s*invalid_tag_expression \[[,\.0-9]+ sec\]\s*$','m'); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like('%(FAILED -%'); + + l_results := ut3_tester_helper.run_helper.run(a_tags => '(development|end_to_end))'); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_match('^\s*invalid_tag_expression \[[,\.0-9]+ sec\]\s*$','m'); + ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like('%(FAILED -%'); + + end; + + procedure set_application_info is + begin + dbms_application_info.set_module( gc_module, gc_action ); + dbms_application_info.set_client_info( gc_client_info ); + end; + + procedure create_context_test_suite is + pragma autonomous_transaction; + begin + execute immediate q'[ + create or replace package check_context is + --%suite(Suite description) + --%suitepath(some.suite.path) + + --%beforeall + procedure before_suite; + + --%context(context description) + --%name(some_context) + + --%beforeall + procedure before_context; + + --%beforeeach + procedure before_each_test; + + --%test(Some test description) + --%beforetest(before_test) + --%aftertest(after_test) + procedure the_test; + procedure before_test; + procedure after_test; + + --%aftereach + procedure after_each_test; + + --%afterall + procedure after_context; + + --%endcontext + + + --%afterall + procedure after_suite; + + end;]'; + execute immediate q'[ + create or replace package body check_context is + + procedure print_context( a_procedure_name varchar2 ) is + l_results ut_varchar2_rows; + l_module varchar2(32767); + l_action varchar2(32767); + l_client_info varchar2(32767); + begin + select attribute||'='||value + bulk collect into l_results + from session_context where namespace = 'UT3_DEVELOP_INFO' + order by attribute; + for i in 1 .. l_results.count loop + dbms_output.put_line( upper(a_procedure_name) ||':'|| l_results(i) ); + end loop; + dbms_application_info.read_module( l_module, l_action ); + dbms_application_info.read_client_info( l_client_info ); + + dbms_output.put_line( 'APPLICATION_INFO:MODULE=' || l_module ); + dbms_output.put_line( 'APPLICATION_INFO:ACTION=' || l_action ); + dbms_output.put_line( 'APPLICATION_INFO:CLIENT_INFO=' || l_client_info ); + end; + + procedure before_suite is + begin + print_context('before_suite'); + end; + + procedure before_context is + begin + print_context('before_context'); + end; + + procedure before_each_test is + begin + print_context('before_each_test'); + end; + + procedure the_test is + begin + print_context('the_test'); + end; + + procedure before_test is + begin + print_context('before_test'); + end; + + procedure after_test is + begin + print_context('after_test'); + end; + + procedure after_each_test is + begin + print_context('after_each_test'); + end; + + procedure after_context is + begin + print_context('after_context'); + end; + + procedure after_suite is + begin + print_context('after_suite'); + end; + + end;]'; + end; + + procedure drop_context_test_suite is + pragma autonomous_transaction; + begin + execute immediate q'[drop package check_context]'; + end; + + procedure run_context_test_suite is + l_lines ut3_develop.ut_varchar2_list; + begin + select * bulk collect into l_lines from table(ut3_develop.ut.run('check_context')); + g_context_test_results := ut3_tester_helper.main_helper.table_to_clob(l_lines); + g_timestamp := current_timestamp; + end; + + + procedure sys_ctx_on_suite_beforeall is + begin + ut.expect(g_context_test_results).to_be_like( + '%BEFORE_SUITE:COVERAGE_RUN_ID=________________________________%' + ||'%BEFORE_SUITE:CURRENT_EXECUTABLE_NAME='||gc_owner||'.check_context.before_suite' + ||'%BEFORE_SUITE:CURRENT_EXECUTABLE_TYPE=beforeall' + ||'%BEFORE_SUITE:RUN_PATHS=check_context' + ||'%BEFORE_SUITE:SUITE_DESCRIPTION=Suite description' + ||'%BEFORE_SUITE:SUITE_PACKAGE='||gc_owner||'.check_context' + ||'%BEFORE_SUITE:SUITE_PATH=some.suite.path.check_context' + ||'%BEFORE_SUITE:SUITE_START_TIME='||to_char(g_timestamp,'syyyy-mm-dd"T"hh24:mi') + ||'%APPLICATION_INFO:MODULE=utPLSQL' + ||'%APPLICATION_INFO:ACTION=check_context' + ||'%APPLICATION_INFO:CLIENT_INFO=before_suite%' + ); + ut.expect(g_context_test_results).not_to_be_like('%BEFORE_SUITE:CONTEXT_%'); + ut.expect(g_context_test_results).not_to_be_like('%BEFORE_SUITE:TEST_%'); + end; + + procedure sys_ctx_on_context_beforeall is + begin + ut.expect(g_context_test_results).to_be_like( + '%BEFORE_CONTEXT:CONTEXT_DESCRIPTION=context description' + ||'%BEFORE_CONTEXT:CONTEXT_NAME=some_context' + ||'%BEFORE_CONTEXT:CONTEXT_PATH=some.suite.path.check_context.some_context' + ||'%BEFORE_CONTEXT:CONTEXT_START_TIME='||to_char(g_timestamp,'syyyy-mm-dd"T"hh24:mi') + ||'%BEFORE_CONTEXT:CURRENT_EXECUTABLE_NAME='||gc_owner||'.check_context.before_context' + ||'%BEFORE_CONTEXT:CURRENT_EXECUTABLE_TYPE=beforeall' + ||'%BEFORE_CONTEXT:RUN_PATHS=check_context' + ||'%BEFORE_CONTEXT:SUITE_DESCRIPTION=Suite description' + ||'%BEFORE_CONTEXT:SUITE_PACKAGE='||gc_owner||'.check_context' + ||'%BEFORE_CONTEXT:SUITE_PATH=some.suite.path.check_context' + ||'%BEFORE_CONTEXT:SUITE_START_TIME='||to_char(g_timestamp,'syyyy-mm-dd"T"hh24:mi') + ||'%APPLICATION_INFO:MODULE=utPLSQL' + ||'%APPLICATION_INFO:ACTION=check_context' + ||'%APPLICATION_INFO:CLIENT_INFO=before_context%' + ); + ut.expect(g_context_test_results).not_to_be_like('%BEFORE_CONTEXT:TEST_%'); + end; + + procedure sys_ctx_on_beforeeach is + begin + ut.expect(g_context_test_results).to_be_like( + '%BEFORE_EACH_TEST:CONTEXT_DESCRIPTION=context description' + ||'%BEFORE_EACH_TEST:CONTEXT_NAME=some_context' + ||'%BEFORE_EACH_TEST:CONTEXT_PATH=some.suite.path.check_context.some_context' + ||'%BEFORE_EACH_TEST:CONTEXT_START_TIME='||to_char(g_timestamp,'syyyy-mm-dd"T"hh24:mi') + ||'%BEFORE_EACH_TEST:CURRENT_EXECUTABLE_NAME='||gc_owner||'.check_context.before_each_test' + ||'%BEFORE_EACH_TEST:CURRENT_EXECUTABLE_TYPE=beforeeach' + ||'%BEFORE_EACH_TEST:RUN_PATHS=check_context' + ||'%BEFORE_EACH_TEST:SUITE_DESCRIPTION=Suite description' + ||'%BEFORE_EACH_TEST:SUITE_PACKAGE='||gc_owner||'.check_context' + ||'%BEFORE_EACH_TEST:SUITE_PATH=some.suite.path.check_context' + ||'%BEFORE_EACH_TEST:SUITE_START_TIME='||to_char(g_timestamp,'syyyy-mm-dd"T"hh24:mi') + ||'%BEFORE_EACH_TEST:TEST_DESCRIPTION=Some test description' + ||'%BEFORE_EACH_TEST:TEST_NAME='||gc_owner||'.check_context.the_test' + ||'%BEFORE_EACH_TEST:TEST_START_TIME='||to_char(g_timestamp,'syyyy-mm-dd"T"hh24:mi') + ||'%APPLICATION_INFO:MODULE=utPLSQL' + ||'%APPLICATION_INFO:ACTION=check_context' + ||'%APPLICATION_INFO:CLIENT_INFO=before_each_test%' + ); + end; + + procedure sys_ctx_on_beforetest is + begin + ut.expect(g_context_test_results).to_be_like( + '%BEFORE_TEST:CONTEXT_DESCRIPTION=context description' + ||'%BEFORE_TEST:CONTEXT_NAME=some_context' + ||'%BEFORE_TEST:CONTEXT_PATH=some.suite.path.check_context.some_context' + ||'%BEFORE_TEST:CONTEXT_START_TIME='||to_char(g_timestamp,'syyyy-mm-dd"T"hh24:mi') + ||'%BEFORE_TEST:CURRENT_EXECUTABLE_NAME='||gc_owner||'.check_context.before_test' + ||'%BEFORE_TEST:CURRENT_EXECUTABLE_TYPE=beforetest' + ||'%BEFORE_TEST:RUN_PATHS=check_context' + ||'%BEFORE_TEST:SUITE_DESCRIPTION=Suite description' + ||'%BEFORE_TEST:SUITE_PACKAGE='||gc_owner||'.check_context' + ||'%BEFORE_TEST:SUITE_PATH=some.suite.path.check_context' + ||'%BEFORE_TEST:SUITE_START_TIME='||to_char(g_timestamp,'syyyy-mm-dd"T"hh24:mi') + ||'%BEFORE_TEST:TEST_DESCRIPTION=Some test description' + ||'%BEFORE_TEST:TEST_NAME='||gc_owner||'.check_context.the_test' + ||'%BEFORE_TEST:TEST_START_TIME='||to_char(g_timestamp,'syyyy-mm-dd"T"hh24:mi') + ||'%APPLICATION_INFO:MODULE=utPLSQL' + ||'%APPLICATION_INFO:ACTION=check_context' + ||'%APPLICATION_INFO:CLIENT_INFO=before_test%' + ); + end; + + procedure sys_ctx_on_test is + begin + ut.expect(g_context_test_results).to_be_like( + '%THE_TEST:CONTEXT_DESCRIPTION=context description' + ||'%THE_TEST:CONTEXT_NAME=some_context' + ||'%THE_TEST:CONTEXT_PATH=some.suite.path.check_context.some_context' + ||'%THE_TEST:CONTEXT_START_TIME='||to_char(g_timestamp,'syyyy-mm-dd"T"hh24:mi') + ||'%THE_TEST:CURRENT_EXECUTABLE_NAME='||gc_owner||'.check_context.the_test' + ||'%THE_TEST:CURRENT_EXECUTABLE_TYPE=test' + ||'%THE_TEST:RUN_PATHS=check_context' + ||'%THE_TEST:SUITE_DESCRIPTION=Suite description' + ||'%THE_TEST:SUITE_PACKAGE='||gc_owner||'.check_context' + ||'%THE_TEST:SUITE_PATH=some.suite.path.check_context' + ||'%THE_TEST:SUITE_START_TIME='||to_char(g_timestamp,'syyyy-mm-dd"T"hh24:mi') + ||'%THE_TEST:TEST_DESCRIPTION=Some test description' + ||'%THE_TEST:TEST_NAME='||gc_owner||'.check_context.the_test' + ||'%THE_TEST:TEST_START_TIME='||to_char(g_timestamp,'syyyy-mm-dd"T"hh24:mi') + ||'%APPLICATION_INFO:MODULE=utPLSQL' + ||'%APPLICATION_INFO:ACTION=check_context' + ||'%APPLICATION_INFO:CLIENT_INFO=the_test%' + ); + end; + + procedure sys_ctx_on_aftertest is + begin + ut.expect(g_context_test_results).to_be_like( + '%AFTER_TEST:CONTEXT_DESCRIPTION=context description' + ||'%AFTER_TEST:CONTEXT_NAME=some_context' + ||'%AFTER_TEST:CONTEXT_PATH=some.suite.path.check_context.some_context' + ||'%AFTER_TEST:CONTEXT_START_TIME='||to_char(g_timestamp,'syyyy-mm-dd"T"hh24:mi') + ||'%AFTER_TEST:CURRENT_EXECUTABLE_NAME='||gc_owner||'.check_context.after_test' + ||'%AFTER_TEST:CURRENT_EXECUTABLE_TYPE=aftertest' + ||'%AFTER_TEST:RUN_PATHS=check_context' + ||'%AFTER_TEST:SUITE_DESCRIPTION=Suite description' + ||'%AFTER_TEST:SUITE_PACKAGE='||gc_owner||'.check_context' + ||'%AFTER_TEST:SUITE_PATH=some.suite.path.check_context' + ||'%AFTER_TEST:SUITE_START_TIME='||to_char(g_timestamp,'syyyy-mm-dd"T"hh24:mi') + ||'%AFTER_TEST:TEST_DESCRIPTION=Some test description' + ||'%AFTER_TEST:TEST_NAME='||gc_owner||'.check_context.the_test' + ||'%AFTER_TEST:TEST_START_TIME='||to_char(g_timestamp,'syyyy-mm-dd"T"hh24:mi') + ||'%APPLICATION_INFO:MODULE=utPLSQL' + ||'%APPLICATION_INFO:ACTION=check_context' + ||'%APPLICATION_INFO:CLIENT_INFO=after_test%' + ); + end; + + procedure sys_ctx_on_aftereach is + begin + ut.expect(g_context_test_results).to_be_like( + '%AFTER_EACH_TEST:CONTEXT_DESCRIPTION=context description' + ||'%AFTER_EACH_TEST:CONTEXT_NAME=some_context' + ||'%AFTER_EACH_TEST:CONTEXT_PATH=some.suite.path.check_context.some_context' + ||'%AFTER_EACH_TEST:CONTEXT_START_TIME='||to_char(g_timestamp,'syyyy-mm-dd"T"hh24:mi') + ||'%AFTER_EACH_TEST:CURRENT_EXECUTABLE_NAME='||gc_owner||'.check_context.after_each_test' + ||'%AFTER_EACH_TEST:CURRENT_EXECUTABLE_TYPE=aftereach' + ||'%AFTER_EACH_TEST:RUN_PATHS=check_context' + ||'%AFTER_EACH_TEST:SUITE_DESCRIPTION=Suite description' + ||'%AFTER_EACH_TEST:SUITE_PACKAGE='||gc_owner||'.check_context' + ||'%AFTER_EACH_TEST:SUITE_PATH=some.suite.path.check_context' + ||'%AFTER_EACH_TEST:SUITE_START_TIME='||to_char(g_timestamp,'syyyy-mm-dd"T"hh24:mi') + ||'%AFTER_EACH_TEST:TEST_DESCRIPTION=Some test description' + ||'%AFTER_EACH_TEST:TEST_NAME='||gc_owner||'.check_context.the_test' + ||'%AFTER_EACH_TEST:TEST_START_TIME='||to_char(g_timestamp,'syyyy-mm-dd"T"hh24:mi') + ||'%APPLICATION_INFO:MODULE=utPLSQL' + ||'%APPLICATION_INFO:ACTION=check_context' + ||'%APPLICATION_INFO:CLIENT_INFO=after_each_test%' + ); + end; + + procedure sys_ctx_on_context_afterall is + begin + ut.expect(g_context_test_results).to_be_like( + '%AFTER_CONTEXT:CONTEXT_DESCRIPTION=context description' + ||'%AFTER_CONTEXT:CONTEXT_NAME=some_context' + ||'%AFTER_CONTEXT:CONTEXT_PATH=some.suite.path.check_context.some_context' + ||'%AFTER_CONTEXT:CONTEXT_START_TIME='||to_char(g_timestamp,'syyyy-mm-dd"T"hh24:mi') + ||'%AFTER_CONTEXT:CURRENT_EXECUTABLE_NAME='||gc_owner||'.check_context.after_context' + ||'%AFTER_CONTEXT:CURRENT_EXECUTABLE_TYPE=afterall' + ||'%AFTER_CONTEXT:RUN_PATHS=check_context' + ||'%AFTER_CONTEXT:SUITE_DESCRIPTION=Suite description' + ||'%AFTER_CONTEXT:SUITE_PACKAGE='||gc_owner||'.check_context' + ||'%AFTER_CONTEXT:SUITE_PATH=some.suite.path.check_context' + ||'%AFTER_CONTEXT:SUITE_START_TIME='||to_char(g_timestamp,'syyyy-mm-dd"T"hh24:mi') + ||'%APPLICATION_INFO:MODULE=utPLSQL' + ||'%APPLICATION_INFO:ACTION=check_context' + ||'%APPLICATION_INFO:CLIENT_INFO=after_context%' + ); + ut.expect(g_context_test_results).not_to_be_like('%AFTER_CONTEXT:TEST_%'); + end; + + procedure sys_ctx_on_suite_afterall is + begin + ut.expect(g_context_test_results).to_be_like( + '%AFTER_SUITE:CURRENT_EXECUTABLE_NAME='||gc_owner||'.check_context.after_suite' + ||'%AFTER_SUITE:CURRENT_EXECUTABLE_TYPE=afterall' + ||'%AFTER_SUITE:RUN_PATHS=check_context' + ||'%AFTER_SUITE:SUITE_DESCRIPTION=Suite description' + ||'%AFTER_SUITE:SUITE_PACKAGE='||gc_owner||'.check_context' + ||'%AFTER_SUITE:SUITE_PATH=some.suite.path.check_context' + ||'%AFTER_SUITE:SUITE_START_TIME='||to_char(g_timestamp,'syyyy-mm-dd"T"hh24:mi') + ||'%APPLICATION_INFO:MODULE=utPLSQL' + ||'%APPLICATION_INFO:ACTION=check_context' + ||'%APPLICATION_INFO:CLIENT_INFO=after_suite%' + ); + ut.expect(g_context_test_results).not_to_be_like('%AFTER_SUITE:CONTEXT_%'); + ut.expect(g_context_test_results).not_to_be_like('%AFTER_SUITE:TEST_%'); + end; + + procedure sys_ctx_clear_after_run is + l_actual sys_refcursor; + begin + open l_actual for + select attribute||'='||value + from session_context where namespace = 'UT3_DEVELOP_INFO'; + + ut.expect(l_actual).to_be_empty(); + end; + + procedure app_info_restore_after_run is + l_module varchar2(32767); + l_action varchar2(32767); + l_client_info varchar2(32767); + begin + dbms_application_info.read_module( l_module, l_action ); + dbms_application_info.read_client_info( l_client_info ); + + ut.expect(l_module).to_equal(gc_module); + ut.expect(l_action).to_equal(gc_action); + --Disabled as it can't be tested. + --UT3_LATEST_RELEASE is also setting the client_info on each procedure + -- ut.expect(l_client_info).to_equal(gc_client_info); + end; + +end; +/ diff --git a/test/ut3_user/api/test_ut_run.pks b/test/ut3_user/api/test_ut_run.pks new file mode 100644 index 000000000..c57788bff --- /dev/null +++ b/test/ut3_user/api/test_ut_run.pks @@ -0,0 +1,321 @@ +create or replace package test_ut_run is + --%suite(ut.run) + --%suitepath(utplsql.test_user.api) + + procedure clear_expectations; + + procedure create_ut3_user_tests; + procedure drop_ut3_user_tests; + + --%test(ut.version() returns version of the framework) + procedure ut_version; + + --%test(ut.fail() marks test as failed) + --%beforetest(ut3_tester_helper.main_helper.set_ut_run_context) + --%aftertest(clear_expectations, ut3_tester_helper.main_helper.clear_ut_run_context) + procedure ut_fail; + + --%context(ut_run_procedure) + --%displayname(ut.run() procedure options) + --%beforeall(create_ut3_user_tests) + --%afterall(drop_ut3_user_tests) + + --%test(Runs all tests in current schema with default reporter when no parameters given) + procedure run_proc_no_params; + --%test(Runs all tests in current schema with specified reporter) + procedure run_proc_specific_reporter; + --%test(Runs all tests in current schema with coverage file list) + procedure run_proc_cov_file_list; + + --%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) + procedure run_proc_pkg_name_file_list; + --%test(Runs tests from given paths only with paths list) + procedure run_proc_path_list; + --%test(Runs tests from given paths only with paths list and coverage file list) + procedure run_proc_path_list_file_list; + --%test(Runs all tests in current schema using default reporter when null reporter given) + procedure run_proc_null_reporter; + --%test(Runs all tests in current schema with null path provided) + procedure run_proc_null_path; + --%test(Runs all tests in current schema with null path list given) + procedure run_proc_null_path_list; + --%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; + + procedure create_suite_with_link; + procedure drop_suite_with_link; + + --%test(Savepoints are working properly on distributed transactions - Issue #839) + --%beforetest(create_suite_with_link) + --%aftertest(drop_suite_with_link) + procedure savepoints_on_db_links; + + --%endcontext + + --%context(run_proc_transaction_control) + + --%beforeall + procedure transaction_setup; + --%afterall + procedure transaction_cleanup; + --%test(Leaves transaction open and uncommitted with a_force_manual_rollback) + procedure run_proc_keep_test_data; + --%test(Leaves transaction open and uncommitted with a_force_manual_rollback with exceptions) + procedure run_proc_keep_test_data_raise; + --%test(Does not impact current transaction when ran without a_force_manual_rollback) + procedure run_proc_discard_test_data; + + --%endcontext + + + --%context(ut_run_function) + + --%displayname(ut.run() function options) + --%beforeall(create_ut3_user_tests) + --%afterall(drop_ut3_user_tests) + + --%test(Runs all tests in current schema with default reporter when no parameters given) + procedure run_func_no_params; + --%test(Runs all tests in current schema with specified reporter) + procedure run_func_specific_reporter; + --%test(Runs all tests in current schema with coverage file list) + procedure run_func_cov_file_list; + + --%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) + procedure run_func_pkg_name_file_list; + --%test(Runs tests from given paths with paths list) + procedure run_func_path_list; + --%test(Runs tests from given paths with paths list and coverage file list) + procedure run_func_path_list_file_list; + --%test(Runs all tests in current schema using default reporter when null reporter given) + procedure run_func_null_reporter; + --%test(Runs all tests in current schema with null path provided) + procedure run_func_null_path; + --%test(Runs all tests in current schema with null path list given) + procedure run_func_null_path_list; + --%test(Runs all tests in current schema with empty path list given) + procedure run_func_empty_path_list; + --%test(Runs all tests in current schema with coverage file list and default reporter) + procedure run_func_cov_file_lst_null_rep; + --%test(Executes successfully an empty suite) + procedure run_func_empty_suite; + + --disabled(Makes session wait for lock on 18.1 due to library cache pin wait) + --%test(ut.run - raises after completing all tests if a test fails with ORA-04068 or ORA-04061) + --%beforetest(create_test_suite) + --%aftertest(drop_test_suite) + procedure raise_in_invalid_state; + procedure create_test_suite; + procedure drop_test_suite; + + --%test(ut.run - Does not execute suite when specified package is not valid) + --%beforetest(compile_invalid_package) + --%aftertest(drop_invalid_package) + procedure run_in_invalid_state; + procedure compile_invalid_package; + procedure drop_invalid_package; + + --%test(Invalidate package specs via rebuild but still execute package) + --%beforetest(generate_invalid_spec) + --%aftertest(drop_invalid_spec) + procedure run_and_revalidate_specs; + 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; + + --%test(Can run test package that is named the same as schema name) + --%beforetest(create_schema_name_package) + --%aftertest(drop_schema_name_package) + procedure run_schema_name_test; + procedure create_schema_name_package; + procedure drop_schema_name_package; + + --%test(Runs properly formed suite hierarchy regardless of NLS_SORT settings - Issue #1060) + --%beforetest(create_suites_with_path) + --%aftertest(drop_suites_with_path) + procedure run_suite_with_nls_sort; + procedure create_suites_with_path; + procedure drop_suites_with_path; + + --%endcontext + + --%context(random_order) + + --%displayname(Random test execution order) + --%beforeall(create_ut3_user_tests) + --%afterall(drop_ut3_user_tests) + + --%test(Runs tests in random order) + procedure run_with_random_order; + + --%test(Reports test random_test_order_seed) + procedure run_and_report_random_ord_seed; + + --%test(Runs tests in the same random order with provided seed) + procedure run_with_random_order_seed; + + --%endcontext + + --%context(run with tags) + --%displayname(Call ut.run with #tags) + + --%beforeall(create_ut3_user_tests) + --%afterall(drop_ut3_user_tests) + + --%test(Execute test by tag ut_run) + procedure test_run_by_one_tag; + + --%test( Execute suite by one tag) + procedure suite_run_by_one_tag; + + --%test(Execute two tests by one tag) + procedure two_test_run_by_one_tag; + + --%test(Execute all suites tests with tag) + procedure all_suites_run_by_one_tag; + + --%test(Execute tests by passing two tags) + procedure two_test_run_by_two_tags; + + --%test(Execute tests by passing two tags - Legacy notation) + procedure two_test_run_by_two_tags_leg; + + --%test(Execute suite and all of its children) + procedure suite_with_children_tag; + + --%test(Execute suite and parents) + procedure suite_with_tag_parent; + + --%test(Execute test for non existing tag) + procedure test_nonexists_tag; + + --%test(Execute test for duplicate list tags) + procedure test_duplicate_tag; + + --%test(Execute suite test for duplicate list tags) + procedure suite_duplicate_tag; + + --%test(Runs given package only with package name given as path and filter by tag) + procedure run_proc_pkg_name_tag; + + --%test(Runs all from given package with package name given as path and coverage file list with tag) + procedure run_pkg_name_file_list_tag; + + --%test(Runs tests from given paths with paths list and tag) + procedure run_proc_path_list_tag; + + --%test(Runs all tests in current schema with default reporter when only tag is given) + procedure tag_run_func_no_params; + + --%test(Runs given package only with package name given as path and filter by tag) + procedure tag_run_func_pkg_name; + + --%test(Runs tests from given paths with paths list and a tag) + procedure tag_run_func_path_list; + + --%test(Runs tests from given paths with paths list and a tag - Legacy Notation) + procedure tag_run_func_path_list_leg; + + --%test(Runs tests from given paths with paths list and include/exclude tags) + procedure tag_inc_exc_run_func_path_list; + + --%test(Runs tests from given paths with paths list and include/exclude tags - Legacy Notation) + procedure tag_inc_exc_run_fun_pth_lst_lg; + + --%test(Runs tests from given path and excludes specific tags) + procedure tag_exclude_run_func_path_list; + + --%test(Runs tests from given path and excludes specific tags - Legacy Notation) + procedure tag_exclude_run_fun_pth_lst_lg; + + --%test(Runs tests from given tags and exclude tags) + procedure tag_include_exclude_run_func; + + --%test(Runs tests from given tags and exclude tags - Legacy Notation) + procedure tag_include_exclude_run_fun_lg; + + --%test(Runs tests suing complex expressions) + procedure tag_complex_expressions; + + --%test(Testing invalid tag expression) + --%throws(-20219) + procedure invalid_tag_expression; + + --%endcontext + + --%context(ut3_info context) + + --%beforeall + procedure set_application_info; + --%beforeall + procedure create_context_test_suite; + + --%beforeall + procedure run_context_test_suite; + + --%afterall + procedure drop_context_test_suite; + + --%test(sets context for suite level beforeall) + procedure sys_ctx_on_suite_beforeall; + + --%test(sets context for context level beforeall) + procedure sys_ctx_on_context_beforeall; + + --%test(set for context level beforeeach) + procedure sys_ctx_on_beforeeach; + + --%test(set for context level beforetest) + procedure sys_ctx_on_beforetest; + + --%test(set for context level test) + procedure sys_ctx_on_test; + + --%test(set for context level aftertest) + procedure sys_ctx_on_aftertest; + + --%test(set for context level aftereach) + procedure sys_ctx_on_aftereach; + + --%test(set for context level afterall) + procedure sys_ctx_on_context_afterall; + + --%test(set for suite level afterall) + procedure sys_ctx_on_suite_afterall; + + --%test(is cleared after run) + procedure sys_ctx_clear_after_run; + + --%test(application info is restored after run) + procedure app_info_restore_after_run; + + --%endcontext + +end; +/ + diff --git a/test/ut3_user/api/test_ut_runner.pkb b/test/ut3_user/api/test_ut_runner.pkb new file mode 100644 index 000000000..b6b7c67e7 --- /dev/null +++ b/test/ut3_user/api/test_ut_runner.pkb @@ -0,0 +1,657 @@ +create or replace package body test_ut_runner is + + procedure setup_cache_objects is + begin + ut3_tester_helper.run_helper.setup_cache_objects(); + end; + + procedure setup_cache_objectstag is + begin + ut3_tester_helper.run_helper.setup_cache_objectstag(); + end; + + procedure setup_cache_twotags is + begin + ut3_tester_helper.run_helper.setup_cache_twotags(); + end; + + procedure setup_cache is + begin + ut3_tester_helper.run_helper.setup_cache(); + end; + + procedure cleanup_cache is + begin + ut3_tester_helper.run_helper.cleanup_cache(); + end; + + procedure create_test_spec + as + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package test_cache as + --%suite + + --%test + procedure failing_test; +end; +]'; + end; + + procedure create_test_body(a_number integer) + as + pragma autonomous_transaction; + begin + execute immediate 'create or replace package body test_cache as + procedure failing_test is + begin + ut3_develop.ut.expect('||a_number||').to_be_null; + end; +end;'; + end; + + procedure drop_test_package + as + pragma autonomous_transaction; + begin + execute immediate 'drop package test_cache'; + end; + + + + procedure keep_an_open_transaction is + l_expected varchar2(300); + l_output_data dbms_output.chararr; + l_num_lines integer := 100000; + begin + --Arrange + create_test_spec(); + create_test_body(0); + l_expected := dbms_transaction.local_transaction_id(true); + --Act + ut3_develop.ut.run('test_cache'); + dbms_output.get_lines( l_output_data, l_num_lines); + --Assert + ut.expect(dbms_transaction.local_transaction_id()).to_equal(l_expected); + drop_test_package(); + end; + + procedure close_newly_opened_transaction is + l_output_data dbms_output.chararr; + l_num_lines integer := 100000; + pragma autonomous_transaction; + begin + --Arrange + create_test_spec(); + create_test_body(0); + rollback; + --Act + ut3_develop.ut.run('test_cache'); + dbms_output.get_lines( l_output_data, l_num_lines); + --Assert + ut.expect(dbms_transaction.local_transaction_id()).to_be_null(); + drop_test_package(); + end; + + procedure version_comp_check_compare is + begin + ut.expect( ut3_develop.ut_runner.version_compatibility_check('v3.0.0.0','v3.0.0.0') ).to_equal(1); + ut.expect( ut3_develop.ut_runner.version_compatibility_check('v3.0.0.0','v3.0.123.0') ).to_equal(1); + ut.expect( ut3_develop.ut_runner.version_compatibility_check('v3.0.0.0','v3.123.0.0') ).to_equal(1); + ut.expect( ut3_develop.ut_runner.version_compatibility_check('v3.0.0.0','v3.13.31.0') ).to_equal(1); + ut.expect( ut3_develop.ut_runner.version_compatibility_check('v3.0.1.0','v3.0.0.0') ).to_equal(0); + ut.expect( ut3_develop.ut_runner.version_compatibility_check('v3.1.0.0','v3.0.0.0') ).to_equal(0); + ut.expect( ut3_develop.ut_runner.version_compatibility_check('v3.0.0.0','v2.0.0.0') ).to_equal(0); + ut.expect( ut3_develop.ut_runner.version_compatibility_check('v3.0.0.0','v4.0.0.0') ).to_equal(0); + end; + + procedure version_comp_check_ignore is + begin + ut.expect( ut3_develop.ut_runner.version_compatibility_check('v3.0.0.123','v3.0.0.0') ).to_equal(1); + ut.expect( ut3_develop.ut_runner.version_compatibility_check('v3.0.0.0','v3.0.0.123') ).to_equal(1); + ut.expect( ut3_develop.ut_runner.version_compatibility_check('v3.0.0','v3.0.0.0') ).to_equal(1); + end; + + procedure version_comp_check_short is + begin + ut.expect( ut3_develop.ut_runner.version_compatibility_check('v3.0.0','v3.0.0.0') ).to_equal(1); + ut.expect( ut3_develop.ut_runner.version_compatibility_check('v3.0','v3.0.123.0') ).to_equal(1); + ut.expect( ut3_develop.ut_runner.version_compatibility_check('v3','v3.123.0.0') ).to_equal(1); + end; + + procedure version_comp_check_exception is + procedure throws(a_requested varchar2, a_current varchar2) is + l_compatible integer; + begin + l_compatible := ut3_develop.ut_runner.version_compatibility_check(a_requested,a_current); + ut.fail('Expected exception but nothing was raised'); + exception + when others then + ut.expect(sqlcode).to_equal(-20214); + end; + begin + throws('bad_ver','v3.0.0.0'); + throws('v3.0.0.0','bad_ver'); + end; + + procedure run_reset_package_body_cache is + l_results ut3_develop.ut_varchar2_list; + l_expected clob; + l_actual clob; + begin + --Arrange + create_test_spec(); + create_test_body(0); + select * + bulk collect into l_results + from table(ut3_develop.ut.run('test_cache')); + + --Act + create_test_body(1); + select * + bulk collect into l_results + from table(ut3_develop.ut.run('test_cache')); + --Assert + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + l_expected := '%ut3_develop.ut.expect(1).to_be_null;%'; + ut.expect(l_actual).to_be_like(l_expected); + drop_test_package(); + end; + + procedure run_keep_dbms_output_buffer is + l_expected dbmsoutput_linesarray; + l_actual dbmsoutput_linesarray; + l_results ut3_develop.ut_varchar2_list; + l_lines number := 10000; + begin + --Arrange + create_test_spec(); + create_test_body(0); + + l_expected := dbmsoutput_linesarray( + 'A text placed into DBMS_OUTPUT', + 'Another line', + lpad('A very long line',10000,'a') + ); + for i in 1 .. 300 loop + l_expected.extend; + l_expected(l_expected.last) := 'line '||i; + end loop; + + for i in 1 .. l_expected.count loop + dbms_output.put_line(l_expected(i)); + end loop; + + --Act + select * + bulk collect into l_results + from table(ut3_develop.ut.run('test_cache')); + + --Assert + dbms_output.get_lines(lines => l_actual, numlines => l_lines); + for i in 1 .. l_lines loop + ut.expect(l_actual(i)).to_equal(l_expected(i)); + end loop; + drop_test_package(); + end; + + procedure test_purge_cache_schema_type is + l_actual sys_refcursor; + begin + --Arrange + l_actual := ut3_tester_helper.run_helper.get_annotation_cache_info_cur( + a_owner => sys_context('USERENV', 'CURRENT_USER'), + a_type => 'PROCEDURE' + ); + + ut.expect(l_actual).not_to_be_empty(); + + --Act + ut3_develop.ut_runner.purge_cache(sys_context('USERENV', 'CURRENT_USER'),'PROCEDURE'); + + --Assert + + l_actual := ut3_tester_helper.run_helper.get_annotation_cache_info_cur( + a_owner => sys_context('USERENV', 'CURRENT_USER'), + a_type => 'PROCEDURE' + ); + --Cache purged for object owner/type + ut.expect(l_actual).to_be_empty(); + + l_actual := ut3_tester_helper.run_helper.get_annotation_cache_info_cur( + a_owner => sys_context('USERENV', 'CURRENT_USER'), + a_type => 'PACKAGE' + ); + --Cache not purged for other types + ut.expect(l_actual).not_to_be_empty(); + + l_actual := ut3_tester_helper.run_helper.get_annotation_cache_info_cur( + a_owner => 'UT3_TESTER_HELPER', + a_type => 'PROCEDURE' + ); + --Cache not purged for other owners + ut.expect(l_actual).not_to_be_empty(); + + end; + + procedure test_rebuild_cache_schema_type is + l_actual sys_refcursor; + begin + --Act + ut3_develop.ut_runner.rebuild_annotation_cache( sys_context('USERENV', 'CURRENT_USER'), 'PACKAGE' ); + --Assert + l_actual := ut3_tester_helper.run_helper.get_annotation_cache_cursor( + a_owner => sys_context('USERENV', 'CURRENT_USER'), + a_type => 'PACKAGE', + a_name => 'DUMMY_TEST_PACKAGE' + ); + + --Rebuild cache for sys_context('USERENV', 'CURRENT_USER')/packages + ut.expect(l_actual).to_have_count(4); + + l_actual := ut3_tester_helper.run_helper.get_annotation_cache_cursor( + a_owner => sys_context('USERENV', 'CURRENT_USER'), + a_type => 'PACKAGE' + ); + + --Did not rebuild cache for ut3_develop/procedures + ut.expect(l_actual).to_have_count(0); + end; + + procedure test_get_suites_info_notag is + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + --Arrange + open l_expected for + select + 'UT3_USER' 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, + 'some.path.dummy_test_package' path, 0 disabled_flag, null disabled_reason,null tags + from dual union all + select + 'UT3_USER' object_owner, 'DUMMY_TEST_PACKAGE' object_name, 'SOME_DUMMY_TEST_PROCEDURE' item_name, + 'dummy_test' item_description, 'UT_TEST' item_type, 6 item_line_no, + 'some.path.dummy_test_package.some_dummy_test_procedure' path, 0 disabled_flag, null disabled_reason,null tags + from dual union all + select + 'UT3_USER' object_owner, 'PATH' object_name, 'PATH' item_name, + null item_description, 'UT_LOGICAL_SUITE' item_type, null item_line_no, + 'some.path' path, 0 disabled_flag, null disabled_reason, null tags + from dual union all + select + 'UT3_USER' object_owner, 'SOME' object_name, 'SOME' item_name, + null item_description, 'UT_LOGICAL_SUITE' item_type, null item_line_no, + 'some' path, 0 disabled_flag, null disabled_reason, null tags + from dual; + --Act + open l_actual for select * from table(ut3_develop.ut_runner.get_suites_info('UT3_USER','DUMMY_TEST_PACKAGE')); + --Assert + ut.expect(l_actual).to_equal(l_expected); + end; + + procedure test_get_suites_info_tag is + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + --Arrange + open l_expected for + select + 'UT3_USER' 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, + 'some.path.dummy_test_package' path, 0 disabled_flag, null disabled_reason,'dummy' tags + from dual union all + select + 'UT3_USER' object_owner, 'DUMMY_TEST_PACKAGE' object_name, 'SOME_DUMMY_TEST_PROCEDURE' item_name, + 'dummy_test' item_description, 'UT_TEST' item_type, 7 item_line_no, + 'some.path.dummy_test_package.some_dummy_test_procedure' path, 0 disabled_flag, null disabled_reason,'testtag' tags + from dual union all + select + 'UT3_USER' object_owner, 'PATH' object_name, 'PATH' item_name, + null item_description, 'UT_LOGICAL_SUITE' item_type, null item_line_no, + 'some.path' path, 0 disabled_flag, null disabled_reason, null tags + from dual union all + select + 'UT3_USER' object_owner, 'SOME' object_name, 'SOME' item_name, + null item_description, 'UT_LOGICAL_SUITE' item_type, null item_line_no, + 'some' path, 0 disabled_flag, null disabled_reason, null tags + from dual; + --Act + open l_actual for select * from table(ut3_develop.ut_runner.get_suites_info('UT3_USER','DUMMY_TEST_PACKAGE')); + --Assert + ut.expect(l_actual).to_equal(l_expected); + end; + + procedure test_get_suites_info_twotag is + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + --Arrange + open l_expected for + select + 'UT3_USER' 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, null disabled_reason,'suitetag1,suitetag2' tags + from dual union all + select + 'UT3_USER' object_owner, 'DUMMY_TEST_PACKAGE' object_name, 'SOME_DUMMY_TEST_PROCEDURE' item_name, + 'dummy_test' item_description, 'UT_TEST' item_type, 6 item_line_no, + 'dummy_test_package.some_dummy_test_procedure' path, 0 disabled_flag, null disabled_reason,'testtag1,testtag2' tags + from dual; + --Act + open l_actual for select * from table(ut3_develop.ut_runner.get_suites_info('UT3_USER','DUMMY_TEST_PACKAGE')); + --Assert + ut.expect(l_actual).to_equal(l_expected); + end; + + procedure test_get_suites_info_by_path is + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + --Arrange + open l_expected for + select + 'UT3_USER' 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, + 'some.path.dummy_test_package' path, 0 disabled_flag, null disabled_reason,null tags + from dual union all + select + 'UT3_USER' object_owner, 'DUMMY_TEST_PACKAGE' object_name, 'SOME_DUMMY_TEST_PROCEDURE' item_name, + 'dummy_test' item_description, 'UT_TEST' item_type, 6 item_line_no, + 'some.path.dummy_test_package.some_dummy_test_procedure' path, 0 disabled_flag, null disabled_reason,null tags + from dual union all + select + 'UT3_USER' object_owner, 'PATH' object_name, 'PATH' item_name, + null item_description, 'UT_LOGICAL_SUITE' item_type, null item_line_no, + 'some.path' path, 0 disabled_flag, null disabled_reason, null tags + from dual union all + select + 'UT3_USER' object_owner, 'SOME' object_name, 'SOME' item_name, + null item_description, 'UT_LOGICAL_SUITE' item_type, null item_line_no, + 'some' path, 0 disabled_flag, null disabled_reason, null tags + from dual; + --Act + open l_actual for select * from table(ut3_develop.ut_runner.get_suites_info('ut3_user:some.path.dummy_test_package')); + --Assert + ut.expect(l_actual).to_equal(l_expected); + end; + + procedure test_get_reporters_list is + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + --Arrange + open l_expected for + select 'UT3_DEVELOP.UT_COVERAGE_COBERTURA_REPORTER' reporter_object_name, 'Y' is_output_reporter from dual union all + select 'UT3_DEVELOP.UT_DEBUG_REPORTER', 'Y' from dual union all + select 'UT3_DEVELOP.UT_COVERAGE_HTML_REPORTER', 'Y' from dual union all + select 'UT3_DEVELOP.UT_COVERAGE_SONAR_REPORTER', 'Y' from dual union all + select 'UT3_DEVELOP.UT_COVERALLS_REPORTER', 'Y' from dual union all + select 'UT3_DEVELOP.UT_DOCUMENTATION_REPORTER', 'Y' from dual union all + select 'UT3_DEVELOP.UT_JUNIT_REPORTER', 'Y' from dual union all + select 'UT3_DEVELOP.UT_REALTIME_REPORTER', 'Y' from dual union all + select 'UT3_DEVELOP.UT_SONAR_TEST_REPORTER', 'Y' from dual union all + select 'UT3_DEVELOP.UT_TEAMCITY_REPORTER', 'Y' from dual union all + select 'UT3_DEVELOP.UT_TFS_JUNIT_REPORTER', 'Y' from dual union all + select 'UT3_DEVELOP.UT_XUNIT_REPORTER', 'Y' from dual + order by 1; + --Act + open l_actual for select * from table(ut3_develop.ut_runner.GET_REPORTERS_LIST()) order by 1; + --Assert + ut.expect(l_actual).to_equal(l_expected); + end; + + procedure db_link_cleanup is + pragma autonomous_transaction; + begin + ut3_tester_helper.run_helper.db_link_cleanup(); + end; + + procedure db_link_setup is + pragma autonomous_transaction; + begin + ut3_tester_helper.run_helper.db_link_setup(); + end; + + procedure raises_20213_on_fail_link is + l_reporter ut3_develop.ut_documentation_reporter := ut3_develop.ut_documentation_reporter(); + l_lines ut3_develop.ut_varchar2_list; + pragma autonomous_transaction; + begin + --Arrange + --Act + ut3_develop.ut_runner.run(ut3_develop.ut_varchar2_list('test_db_link'), ut3_develop.ut_reporters(l_reporter), a_fail_on_errors=> true); + ut.fail('Expected exception but nothing was raised'); + exception + when others then + --Assert + ut.expect(sqlcode).to_equal(-20213); + ut.expect(dbms_utility.format_error_stack||dbms_utility.format_error_backtrace).not_to_be_like('%ORA-02055%'); + end; + + procedure create_test_csl_packages is + pragma autonomous_transaction; + begin + execute immediate q'[ + create or replace package test_csl_names1 as + --%suite + --%suitepath(test_csl_names) + + --%test + procedure one_is_one; + + --%test + procedure two_is_two; + + end; + ]'; + + execute immediate q'{ + create or replace package body test_csl_names1 as + + procedure one_is_one is + begin + ut3_develop.ut.expect(1).to_equal(1); + end; + + procedure two_is_two is + begin + ut3_develop.ut.expect(2).to_equal(2); + end; + + end; + }'; + + execute immediate q'[ + create or replace package test_csl_names2 as + --%suite + --%suitepath(test_csl_names) + + --%test + procedure one_is_one; + + --%test + procedure two_is_two; + + end; + ]'; + + execute immediate q'{ + create or replace package body test_csl_names2 as + + procedure one_is_one is + begin + ut3_develop.ut.expect(1).to_equal(1); + end; + + procedure two_is_two is + begin + ut3_develop.ut.expect(2).to_equal(2); + end; + + end; + }'; + + end; + + procedure drop_test_csl_packages is + pragma autonomous_transaction; + begin + execute immediate 'drop package test_csl_names1'; + execute immediate 'drop package test_csl_names2'; + end; + + procedure pass_varchar2_name_list is + l_results ut3_develop.ut_varchar2_list; + l_actual clob; + begin + select * + bulk collect into l_results + from table(ut3_develop.ut.run(ut3_develop.ut_varchar2_list('test_csl_names1','test_csl_names2'))); + + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + ut.expect(l_actual).to_be_like('%Finished in % seconds +%4 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'); + end; + + procedure pass_varchar2_name is + l_results ut3_develop.ut_varchar2_list; + l_actual clob; + begin + select * + bulk collect into l_results + from table(ut3_develop.ut.run('test_csl_names1')); + + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + ut.expect(l_actual).to_be_like('%Finished in % seconds +%2 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'); + end; + + procedure pass_varchar2_suite_csl is + l_results ut3_develop.ut_varchar2_list; + l_actual clob; + begin + select * + bulk collect into l_results + from table(ut3_develop.ut.run('test_csl_names1,test_csl_names2')); + + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + ut.expect(l_actual).to_be_like('%Finished in % seconds +%4 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'); + end; + + procedure pass_varchar2_test_csl is + l_results ut3_develop.ut_varchar2_list; + l_actual clob; + begin + select * + bulk collect into l_results + from table(ut3_develop.ut.run('test_csl_names1.one_is_one,test_csl_names2.one_is_one')); + + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + ut.expect(l_actual).to_be_like('%Finished in % seconds +%2 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'); + end; + + procedure pass_varch_test_csl_spc is + l_results ut3_develop.ut_varchar2_list; + l_actual clob; + begin + select * + bulk collect into l_results + from table(ut3_develop.ut.run('test_csl_names1.one_is_one, test_csl_names2.one_is_one')); + + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + ut.expect(l_actual).to_be_like('%Finished in % seconds +%2 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'); + end; + + procedure pass_csl_with_srcfile is + l_results ut3_develop.ut_varchar2_list; + l_actual clob; + begin + + select * + bulk collect into l_results + from table( + ut3_develop.ut.run( + a_path => 'test_csl_names1.one_is_one,test_csl_names2.one_is_one', + a_source_files => ut3_develop.ut_varchar2_list('ut3_develop.ut'), + a_test_files => ut3_develop.ut_varchar2_list('ut3_tester.test_csl_names2') + ) + ); + + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + ut.expect(l_actual).to_be_like('%Finished in % seconds +%2 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'); + end; + + procedure pass_csl_within_var2list is + l_results ut3_develop.ut_varchar2_list; + l_actual clob; + begin + select * + bulk collect into l_results + from table(ut3_develop.ut.run(ut3_develop.ut_varchar2_list('test_csl_names1.one_is_one,test_csl_names2.one_is_one'))); + + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + 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_develop.ut_runner.is_test( + a_owner => 'UT3_USER', + a_package_name => 'DUMMY_TEST_PACKAGE', + a_procedure_name => 'SOME_DUMMY_TEST_PROCEDURE' + ) + ).to_be_true(); + ut.expect( ut3_develop.ut_runner.is_test( 'ut3_user','dummy_test_package','some_dummy_test_procedure' ) ).to_be_true(); + end; + + procedure is_test_false is + begin + ut.expect( ut3_develop.ut_runner.is_test( 'UT3_USER','DUMMY_TEST_PACKAGE', 'BAD' ) ).to_be_false(); + ut.expect( ut3_develop.ut_runner.is_test( 'UT3_USER','BAD_TEST_PACKAGE', 'some_dummy_test_procedure' ) ).to_be_false(); + ut.expect( ut3_develop.ut_runner.is_test( 'UT3_USER','DUMMY_TEST_PACKAGE', null ) ).to_be_false(); + ut.expect( ut3_develop.ut_runner.is_test( 'UT3_USER',null,'some_dummy_test_procedure' ) ).to_be_false(); + ut.expect( ut3_develop.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_develop.ut_runner.is_suite( + a_owner => 'UT3_USER', + a_package_name => 'DUMMY_TEST_PACKAGE' + ) + ).to_be_true(); + + ut.expect( ut3_develop.ut_runner.is_suite( 'ut3_user','dummy_test_package' ) ).to_be_true(); + end; + + procedure is_suite_false is + begin + ut.expect( ut3_develop.ut_runner.is_suite( 'UT3_USER','BAD' ) ).to_be_false(); + ut.expect( ut3_develop.ut_runner.is_suite( 'UT3_USER', null ) ).to_be_false(); + ut.expect( ut3_develop.ut_runner.is_suite( null,'DUMMY_TEST_PACKAGE' ) ).to_be_false(); + ut.expect( ut3_develop.ut_runner.is_suite( 'UT3_USER','bad_test_package' ) ).to_be_false(); + end; + + procedure has_suites_true is + begin + ut.expect( ut3_develop.ut_runner.has_suites( a_owner => 'UT3_USER' ) ).to_be_true(); + ut.expect( ut3_develop.ut_runner.has_suites( 'ut3_user' ) ).to_be_true(); + end; + + procedure has_suites_false is + begin + ut.expect( ut3_develop.ut_runner.has_suites( 'UT3' ) ).to_be_false(); + ut.expect( ut3_develop.ut_runner.has_suites( 'BAD' ) ).to_be_false(); + ut.expect( ut3_develop.ut_runner.has_suites( null ) ).to_be_false(); + end; + +end; +/ diff --git a/test/api/test_ut_runner.pks b/test/ut3_user/api/test_ut_runner.pks similarity index 55% rename from test/api/test_ut_runner.pks rename to test/ut3_user/api/test_ut_runner.pks index 74c93dbae..e003ba852 100644 --- a/test/api/test_ut_runner.pks +++ b/test/ut3_user/api/test_ut_runner.pks @@ -1,7 +1,7 @@ create or replace package test_ut_runner is --%suite(ut_runner) - --%suitepath(utplsql.api) + --%suitepath(utplsql.test_user.api) --%rollback(manual) --%test(transaction stays open after the run if it was opened before the run) @@ -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; @@ -37,16 +41,34 @@ create or replace package test_ut_runner is procedure test_purge_cache_schema_type; procedure setup_cache_objects; + procedure setup_cache_objectstag; + procedure setup_cache_twotags; --%test(Rebuilds cache for a given schema and object type) --%beforetest(setup_cache_objects) --%aftertest(cleanup_cache) + --%DISABLED(TODO -disable trigger for this test to pass) 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_notag; + + --%test(get_suites_info returns a cursor containing records for a newly created test with tag) + --%beforetest(setup_cache_objectstag) + --%aftertest(cleanup_cache) + procedure test_get_suites_info_tag; + + --%test(get_suites_info returns a cursor containing records for a newly created test with two tags) + --%beforetest(setup_cache_twotags) + --%aftertest(cleanup_cache) + procedure test_get_suites_info_twotag; + + --%test(get_suites_info returns a cursor containing records for a newly created test with passed path) + --%beforetest(setup_cache_objects) + --%aftertest(cleanup_cache) + procedure test_get_suites_info_by_path; --%test(get_reporters_list returns a cursor containing all built-in reporters and information about output-reporter) --%beforetest(setup_cache_objects) @@ -91,5 +113,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/ut3_user/expectations.pkb b/test/ut3_user/expectations.pkb new file mode 100644 index 000000000..be8627712 --- /dev/null +++ b/test/ut3_user/expectations.pkb @@ -0,0 +1,60 @@ +create or replace package body expectations as + + procedure inline_expectation_to_dbms_out is + l_expected clob; + l_actual clob; + pragma autonomous_transaction; + begin + --Arrange + --Act + execute immediate 'begin some_pkg.some_procedure; end;'; + ut3_develop.ut.expect(1).to_equal(0); + ut3_develop.ut.expect(0).to_equal(0); + + --Assert + l_actual := ut3_tester_helper.main_helper.get_dbms_output_as_clob(); + + l_expected := q'[FAILURE + Actual: 1 (number) was expected to equal: 0 (number) + at "UT3_USER.SOME_PKG%", line 4 ut3_develop.ut.expect(1).to_equal(0); + at "anonymous block", line 1 + at "UT3_USER.EXPECTATIONS%", line 10 +SUCCESS + Actual: 0 (number) was expected to equal: 0 (number) +FAILURE + Actual: 1 (number) was expected to equal: 0 (number) + at "UT3_USER.EXPECTATIONS%", line 11 ut3_develop.ut.expect(1).to_equal(0); +SUCCESS + Actual: 0 (number) was expected to equal: 0 (number) +]'; + + ut.expect(l_actual).to_be_like(l_expected); + rollback; + end; + + procedure create_some_pkg is + pragma autonomous_transaction; + begin + execute immediate q'[ + create or replace package some_pkg is + procedure some_procedure; + end;]'; + + execute immediate q'[ + create or replace package body some_pkg is + procedure some_procedure is + begin + ut3_develop.ut.expect(1).to_equal(0); + ut3_develop.ut.expect(0).to_equal(0); + end; + end;]'; + end; + + procedure drop_some_pkg is + pragma autonomous_transaction; + begin + execute immediate 'drop package some_pkg'; + end; + +end; +/ \ No newline at end of file diff --git a/test/ut3_user/expectations.pks b/test/ut3_user/expectations.pks new file mode 100644 index 000000000..0324f9ac0 --- /dev/null +++ b/test/ut3_user/expectations.pks @@ -0,0 +1,18 @@ +create or replace package expectations as + --%suite + --%suitepath(utplsql.test_user) + + --%beforeall(ut3_tester_helper.main_helper.set_ut_run_context) + + --%afterall(ut3_tester_helper.main_helper.clear_ut_run_context) + + --%test(Expectations return data to screen when called standalone) + --%beforetest( create_some_pkg, ut3_tester_helper.main_helper.clear_ut_run_context ) + --%aftertest( drop_some_pkg, ut3_tester_helper.main_helper.set_ut_run_context ) + procedure inline_expectation_to_dbms_out; + + procedure create_some_pkg; + procedure drop_some_pkg; + +end; +/ \ No newline at end of file diff --git a/test/core/expectations/binary/test_be_greater_or_equal.pkb b/test/ut3_user/expectations/binary/test_be_greater_or_equal.pkb similarity index 68% rename from test/core/expectations/binary/test_be_greater_or_equal.pkb rename to test/ut3_user/expectations/binary/test_be_greater_or_equal.pkb index f41878643..3f92c84c7 100644 --- a/test/core/expectations/binary/test_be_greater_or_equal.pkb +++ b/test/ut3_user/expectations/binary/test_be_greater_or_equal.pkb @@ -2,7 +2,7 @@ create or replace package body test_be_greater_or_equal is procedure cleanup_expectations is begin - expectations.cleanup_expectations( ); + ut3_tester_helper.main_helper.clear_expectations( ); end; function to_greater_equal_block( @@ -11,7 +11,7 @@ create or replace package body test_be_greater_or_equal is a_expected varchar2 ) return varchar2 is begin - return expectations.binary_expectation_block( + return ut3_tester_helper.expectations_helper.binary_expectation_block( 'to_be_greater_or_equal', a_data_type, a_actual, a_data_type, a_expected ); end; @@ -22,7 +22,7 @@ create or replace package body test_be_greater_or_equal is a_expected varchar2 ) return varchar2 is begin - return expectations.binary_expectation_block( + return ut3_tester_helper.expectations_helper.binary_expectation_block( 'not_to_be_greater_or_equal', a_data_type, a_actual, a_data_type, a_expected ); end; @@ -32,7 +32,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate to_greater_equal_block('date', 'sysdate', 'sysdate-1'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_number_greater is @@ -40,7 +40,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate to_greater_equal_block('number', '2.0', '1.99'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_interval_ym_greater is @@ -48,7 +48,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate to_greater_equal_block('interval year to month', '''2-1''', '''2-0'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_interval_ds_greater is @@ -56,7 +56,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate to_greater_equal_block('interval day to second', '''2 01:00:00''', '''2 00:59:59'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_timestamp_greater is @@ -64,7 +64,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate to_greater_equal_block('timestamp', 'to_timestamp(''1997 13'',''YYYY FF'')', 'to_timestamp(''1997 12'',''YYYY FF'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_timestamp_tz_greater is @@ -72,7 +72,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate to_greater_equal_block('timestamp with time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_timestamp_ltz_greater is @@ -80,7 +80,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate to_greater_equal_block('timestamp with local time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_date_equal is @@ -88,7 +88,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate to_greater_equal_block('date', 'sysdate', 'sysdate'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_number_equal is @@ -96,7 +96,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate to_greater_equal_block('number', '2.0', '2.00'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_interval_ym_equal is @@ -104,7 +104,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate to_greater_equal_block('interval year to month', '''2-1''', '''2-1'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_interval_ds_equal is @@ -112,7 +112,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate to_greater_equal_block('interval day to second', '''2 01:00:00''', '''2 01:00:00'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_timestamp_equal is @@ -120,7 +120,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate to_greater_equal_block('timestamp', 'to_timestamp(''1997 13'',''YYYY FF'')', 'to_timestamp(''1997 13'',''YYYY FF'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_timestamp_tz_equal is @@ -128,7 +128,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate to_greater_equal_block('timestamp with time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_timestamp_ltz_equal is @@ -136,7 +136,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate to_greater_equal_block('timestamp with local time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_date_less is @@ -144,7 +144,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate to_greater_equal_block('date', 'sysdate-1', 'sysdate'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_number_less is @@ -152,7 +152,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate to_greater_equal_block('number', '1.0', '1.01'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_interval_ym_less is @@ -160,7 +160,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate to_greater_equal_block('interval year to month', '''2-1''', '''2-2'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_interval_ds_less is @@ -168,7 +168,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate to_greater_equal_block('interval day to second', '''2 00:59:58''', '''2 00:59:59'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_timestamp_less is @@ -176,7 +176,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate to_greater_equal_block('timestamp', 'to_timestamp(''1997 12'',''YYYY FF'')', 'to_timestamp(''1997 13'',''YYYY FF'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_timestamp_tz_less is @@ -184,7 +184,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate to_greater_equal_block('timestamp with time zone', 'to_timestamp_tz(''1997 12 +03:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_timestamp_ltz_less is @@ -192,7 +192,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate to_greater_equal_block('timestamp with local time zone', 'to_timestamp_tz(''1997 12 +03:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure not_actual_date_greater is @@ -200,7 +200,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate not_to_greater_equal_block('date', 'sysdate', 'sysdate-1'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure not_actual_number_greater is @@ -208,7 +208,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate not_to_greater_equal_block('number', '2.0', '1.99'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure not_actual_interval_ym_greater is @@ -216,7 +216,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate not_to_greater_equal_block('interval year to month', '''2-1''', '''2-0'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure not_actual_interval_ds_greater is @@ -224,7 +224,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate not_to_greater_equal_block('interval day to second', '''2 01:00:00''', '''2 00:59:59'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure not_actual_timestamp_greater is @@ -232,7 +232,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate not_to_greater_equal_block('timestamp', 'to_timestamp(''1997 13'',''YYYY FF'')', 'to_timestamp(''1997 12'',''YYYY FF'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure not_actual_timestamp_tz_gretr is @@ -240,7 +240,7 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate not_to_greater_equal_block('timestamp with time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure not_actual_timestamp_ltz_gretr is @@ -248,15 +248,15 @@ create or replace package body test_be_greater_or_equal is --Act execute immediate not_to_greater_equal_block('timestamp with local time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_clob is begin --Act - ut3.ut.expect(to_clob('3')).to_( ut3.be_greater_or_equal(3) ); + ut3_develop.ut.expect(to_clob('3')).to_( ut3_develop.be_greater_or_equal(3) ); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; end; diff --git a/test/core/expectations/binary/test_be_greater_or_equal.pks b/test/ut3_user/expectations/binary/test_be_greater_or_equal.pks similarity index 98% rename from test/core/expectations/binary/test_be_greater_or_equal.pks rename to test/ut3_user/expectations/binary/test_be_greater_or_equal.pks index 077dff59c..3f51e8e3f 100644 --- a/test/core/expectations/binary/test_be_greater_or_equal.pks +++ b/test/ut3_user/expectations/binary/test_be_greater_or_equal.pks @@ -1,7 +1,7 @@ create or replace package test_be_greater_or_equal is --%suite((not)to_be_greater_or_equal) - --%suitepath(utplsql.core.expectations.binary) + --%suitepath(utplsql.test_user.expectations.binary) --%aftereach procedure cleanup_expectations; diff --git a/test/core/expectations/binary/test_be_greater_than.pkb b/test/ut3_user/expectations/binary/test_be_greater_than.pkb similarity index 67% rename from test/core/expectations/binary/test_be_greater_than.pkb rename to test/ut3_user/expectations/binary/test_be_greater_than.pkb index 5863b11b1..6724b5c41 100644 --- a/test/core/expectations/binary/test_be_greater_than.pkb +++ b/test/ut3_user/expectations/binary/test_be_greater_than.pkb @@ -2,7 +2,7 @@ create or replace package body test_be_greater_than is procedure cleanup_expectations is begin - expectations.cleanup_expectations( ); + ut3_tester_helper.main_helper.clear_expectations( ); end; function to_greater_than_block( @@ -11,7 +11,7 @@ create or replace package body test_be_greater_than is a_expected varchar2 ) return varchar2 is begin - return expectations.binary_expectation_block( + return ut3_tester_helper.expectations_helper.binary_expectation_block( 'to_be_greater_than', a_data_type, a_actual, a_data_type, a_expected ); end; @@ -22,7 +22,7 @@ create or replace package body test_be_greater_than is a_expected varchar2 ) return varchar2 is begin - return expectations.binary_expectation_block( + return ut3_tester_helper.expectations_helper.binary_expectation_block( 'not_to_be_greater_than', a_data_type, a_actual, a_data_type, a_expected ); end; @@ -32,7 +32,7 @@ create or replace package body test_be_greater_than is --Act execute immediate to_greater_than_block('date', 'sysdate', 'sysdate-1'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_number_greater is @@ -40,7 +40,7 @@ create or replace package body test_be_greater_than is --Act execute immediate to_greater_than_block('number', '2.0', '1.99'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_interval_ym_greater is @@ -48,7 +48,7 @@ create or replace package body test_be_greater_than is --Act execute immediate to_greater_than_block('interval year to month', '''2-1''', '''2-0'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_interval_ds_greater is @@ -56,7 +56,7 @@ create or replace package body test_be_greater_than is --Act execute immediate to_greater_than_block('interval day to second', '''2 01:00:00''', '''2 00:59:59'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_timestamp_greater is @@ -64,7 +64,7 @@ create or replace package body test_be_greater_than is --Act execute immediate to_greater_than_block('timestamp', 'to_timestamp(''1997 13'',''YYYY FF'')', 'to_timestamp(''1997 12'',''YYYY FF'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_timestamp_tz_greater is @@ -72,7 +72,7 @@ create or replace package body test_be_greater_than is --Act execute immediate to_greater_than_block('timestamp with time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_timestamp_ltz_greater is @@ -80,7 +80,7 @@ create or replace package body test_be_greater_than is --Act execute immediate to_greater_than_block('timestamp with local time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_date_equal is @@ -88,7 +88,7 @@ create or replace package body test_be_greater_than is --Act execute immediate to_greater_than_block('date', 'sysdate', 'sysdate'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_number_equal is @@ -96,7 +96,7 @@ create or replace package body test_be_greater_than is --Act execute immediate to_greater_than_block('number', '2.0', '2.00'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_interval_ym_equal is @@ -104,7 +104,7 @@ create or replace package body test_be_greater_than is --Act execute immediate to_greater_than_block('interval year to month', '''2-1''', '''2-1'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_interval_ds_equal is @@ -112,7 +112,7 @@ create or replace package body test_be_greater_than is --Act execute immediate to_greater_than_block('interval day to second', '''2 01:00:00''', '''2 01:00:00'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_timestamp_equal is @@ -120,7 +120,7 @@ create or replace package body test_be_greater_than is --Act execute immediate to_greater_than_block('timestamp', 'to_timestamp(''1997 13'',''YYYY FF'')', 'to_timestamp(''1997 13'',''YYYY FF'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_timestamp_tz_equal is @@ -128,7 +128,7 @@ create or replace package body test_be_greater_than is --Act execute immediate to_greater_than_block('timestamp with time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_timestamp_ltz_equal is @@ -136,7 +136,7 @@ create or replace package body test_be_greater_than is --Act execute immediate to_greater_than_block('timestamp with local time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_date_less is @@ -144,7 +144,7 @@ create or replace package body test_be_greater_than is --Act execute immediate to_greater_than_block('date', 'sysdate-1', 'sysdate'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_number_less is @@ -152,7 +152,7 @@ create or replace package body test_be_greater_than is --Act execute immediate to_greater_than_block('number', '1.0', '1.01'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_interval_ym_less is @@ -160,7 +160,7 @@ create or replace package body test_be_greater_than is --Act execute immediate to_greater_than_block('interval year to month', '''2-1''', '''2-2'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_interval_ds_less is @@ -168,7 +168,7 @@ create or replace package body test_be_greater_than is --Act execute immediate to_greater_than_block('interval day to second', '''2 00:59:58''', '''2 00:59:59'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_timestamp_less is @@ -176,7 +176,7 @@ create or replace package body test_be_greater_than is --Act execute immediate to_greater_than_block('timestamp', 'to_timestamp(''1997 12'',''YYYY FF'')', 'to_timestamp(''1997 13'',''YYYY FF'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_timestamp_tz_less is @@ -184,7 +184,7 @@ create or replace package body test_be_greater_than is --Act execute immediate to_greater_than_block('timestamp with time zone', 'to_timestamp_tz(''1997 12 +03:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_timestamp_ltz_less is @@ -192,7 +192,7 @@ create or replace package body test_be_greater_than is --Act execute immediate to_greater_than_block('timestamp with local time zone', 'to_timestamp_tz(''1997 12 +03:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure not_actual_date_greater is @@ -200,7 +200,7 @@ create or replace package body test_be_greater_than is --Act execute immediate not_to_greater_than_block('date', 'sysdate', 'sysdate-1'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure not_actual_number_greater is @@ -208,7 +208,7 @@ create or replace package body test_be_greater_than is --Act execute immediate not_to_greater_than_block('number', '2.0', '1.99'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure not_actual_interval_ym_greater is @@ -216,7 +216,7 @@ create or replace package body test_be_greater_than is --Act execute immediate not_to_greater_than_block('interval year to month', '''2-1''', '''2-0'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure not_actual_interval_ds_greater is @@ -224,7 +224,7 @@ create or replace package body test_be_greater_than is --Act execute immediate not_to_greater_than_block('interval day to second', '''2 01:00:00''', '''2 00:59:59'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure not_actual_timestamp_greater is @@ -232,7 +232,7 @@ create or replace package body test_be_greater_than is --Act execute immediate not_to_greater_than_block('timestamp', 'to_timestamp(''1997 13'',''YYYY FF'')', 'to_timestamp(''1997 12'',''YYYY FF'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure not_actual_timestamp_tz_gretr is @@ -240,7 +240,7 @@ create or replace package body test_be_greater_than is --Act execute immediate not_to_greater_than_block('timestamp with time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure not_actual_timestamp_ltz_gretr is @@ -248,15 +248,15 @@ create or replace package body test_be_greater_than is --Act execute immediate not_to_greater_than_block('timestamp with local time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_clob is begin --Act - ut3.ut.expect(to_clob('3')).to_( ut3.be_greater_than(2) ); + ut3_develop.ut.expect(to_clob('3')).to_( ut3_develop.be_greater_than(2) ); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; end; diff --git a/test/core/expectations/binary/test_be_greater_than.pks b/test/ut3_user/expectations/binary/test_be_greater_than.pks similarity index 98% rename from test/core/expectations/binary/test_be_greater_than.pks rename to test/ut3_user/expectations/binary/test_be_greater_than.pks index 6a1dfcc3e..fb158dddb 100644 --- a/test/core/expectations/binary/test_be_greater_than.pks +++ b/test/ut3_user/expectations/binary/test_be_greater_than.pks @@ -1,7 +1,7 @@ create or replace package test_be_greater_than is --%suite((not)to_be_greater_than) - --%suitepath(utplsql.core.expectations.binary) + --%suitepath(utplsql.test_user.expectations.binary) --%aftereach procedure cleanup_expectations; diff --git a/test/core/expectations/binary/test_be_less_or_equal.pkb b/test/ut3_user/expectations/binary/test_be_less_or_equal.pkb similarity index 68% rename from test/core/expectations/binary/test_be_less_or_equal.pkb rename to test/ut3_user/expectations/binary/test_be_less_or_equal.pkb index c72e0039b..aefb58849 100644 --- a/test/core/expectations/binary/test_be_less_or_equal.pkb +++ b/test/ut3_user/expectations/binary/test_be_less_or_equal.pkb @@ -2,7 +2,7 @@ create or replace package body test_be_less_or_equal is procedure cleanup_expectations is begin - expectations.cleanup_expectations( ); + ut3_tester_helper.main_helper.clear_expectations( ); end; function to_less_or_equal_block( @@ -11,7 +11,7 @@ create or replace package body test_be_less_or_equal is a_expected varchar2 ) return varchar2 is begin - return expectations.binary_expectation_block( + return ut3_tester_helper.expectations_helper.binary_expectation_block( 'to_be_less_or_equal', a_data_type, a_actual, a_data_type, a_expected ); end; @@ -22,7 +22,7 @@ create or replace package body test_be_less_or_equal is a_expected varchar2 ) return varchar2 is begin - return expectations.binary_expectation_block( + return ut3_tester_helper.expectations_helper.binary_expectation_block( 'not_to_be_less_or_equal', a_data_type, a_actual, a_data_type, a_expected ); end; @@ -32,7 +32,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate to_less_or_equal_block('date', 'sysdate', 'sysdate-1'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_number_greater is @@ -40,7 +40,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate to_less_or_equal_block('number', '2.0', '1.99'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_interval_ym_greater is @@ -48,7 +48,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate to_less_or_equal_block('interval year to month', '''2-1''', '''2-0'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_interval_ds_greater is @@ -56,7 +56,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate to_less_or_equal_block('interval day to second', '''2 01:00:00''', '''2 00:59:59'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_timestamp_greater is @@ -64,7 +64,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate to_less_or_equal_block('timestamp', 'to_timestamp(''1997 13'',''YYYY FF'')', 'to_timestamp(''1997 12'',''YYYY FF'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_timestamp_tz_greater is @@ -72,7 +72,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate to_less_or_equal_block('timestamp with time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_timestamp_ltz_greater is @@ -80,7 +80,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate to_less_or_equal_block('timestamp with local time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_date_equal is @@ -88,7 +88,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate to_less_or_equal_block('date', 'sysdate', 'sysdate'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_number_equal is @@ -96,7 +96,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate to_less_or_equal_block('number', '2.0', '2.00'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_interval_ym_equal is @@ -104,7 +104,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate to_less_or_equal_block('interval year to month', '''2-1''', '''2-1'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_interval_ds_equal is @@ -112,7 +112,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate to_less_or_equal_block('interval day to second', '''2 01:00:00''', '''2 01:00:00'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_timestamp_equal is @@ -120,7 +120,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate to_less_or_equal_block('timestamp', 'to_timestamp(''1997 13'',''YYYY FF'')', 'to_timestamp(''1997 13'',''YYYY FF'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_timestamp_tz_equal is @@ -128,7 +128,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate to_less_or_equal_block('timestamp with time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_timestamp_ltz_equal is @@ -136,7 +136,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate to_less_or_equal_block('timestamp with local time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_date_less is @@ -144,7 +144,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate to_less_or_equal_block('date', 'sysdate-1', 'sysdate'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_number_less is @@ -152,7 +152,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate to_less_or_equal_block('number', '1.0', '1.01'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_interval_ym_less is @@ -160,7 +160,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate to_less_or_equal_block('interval year to month', '''2-1''', '''2-2'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_interval_ds_less is @@ -168,7 +168,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate to_less_or_equal_block('interval day to second', '''2 00:59:58''', '''2 00:59:59'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_timestamp_less is @@ -176,7 +176,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate to_less_or_equal_block('timestamp', 'to_timestamp(''1997 12'',''YYYY FF'')', 'to_timestamp(''1997 13'',''YYYY FF'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_timestamp_tz_less is @@ -184,7 +184,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate to_less_or_equal_block('timestamp with time zone', 'to_timestamp_tz(''1997 12 +03:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_timestamp_ltz_less is @@ -192,7 +192,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate to_less_or_equal_block('timestamp with local time zone', 'to_timestamp_tz(''1997 12 +03:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure not_actual_date_greater is @@ -200,7 +200,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate not_to_less_or_equal_block('date', 'sysdate', 'sysdate-1'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure not_actual_number_greater is @@ -208,7 +208,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate not_to_less_or_equal_block('number', '2.0', '1.99'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure not_actual_interval_ym_greater is @@ -216,7 +216,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate not_to_less_or_equal_block('interval year to month', '''2-1''', '''2-0'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure not_actual_interval_ds_greater is @@ -224,7 +224,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate not_to_less_or_equal_block('interval day to second', '''2 01:00:00''', '''2 00:59:59'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure not_actual_timestamp_greater is @@ -232,7 +232,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate not_to_less_or_equal_block('timestamp', 'to_timestamp(''1997 13'',''YYYY FF'')', 'to_timestamp(''1997 12'',''YYYY FF'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure not_actual_timestamp_tz_gretr is @@ -240,7 +240,7 @@ create or replace package body test_be_less_or_equal is --Act execute immediate not_to_less_or_equal_block('timestamp with time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure not_actual_timestamp_ltz_gretr is @@ -248,15 +248,15 @@ create or replace package body test_be_less_or_equal is --Act execute immediate not_to_less_or_equal_block('timestamp with local time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_clob is begin --Act - ut3.ut.expect(to_clob('3')).to_( ut3.be_less_or_equal(3) ); + ut3_develop.ut.expect(to_clob('3')).to_( ut3_develop.be_less_or_equal(3) ); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; end; diff --git a/test/core/expectations/binary/test_be_less_or_equal.pks b/test/ut3_user/expectations/binary/test_be_less_or_equal.pks similarity index 98% rename from test/core/expectations/binary/test_be_less_or_equal.pks rename to test/ut3_user/expectations/binary/test_be_less_or_equal.pks index a6ab01664..d6baf037e 100644 --- a/test/core/expectations/binary/test_be_less_or_equal.pks +++ b/test/ut3_user/expectations/binary/test_be_less_or_equal.pks @@ -1,7 +1,7 @@ create or replace package test_be_less_or_equal is --%suite((not)to_be_less_or_equal) - --%suitepath(utplsql.core.expectations.binary) + --%suitepath(utplsql.test_user.expectations.binary) --%aftereach procedure cleanup_expectations; diff --git a/test/core/expectations/binary/test_equal.pkb b/test/ut3_user/expectations/binary/test_equal.pkb similarity index 94% rename from test/core/expectations/binary/test_equal.pkb rename to test/ut3_user/expectations/binary/test_equal.pkb index dd7dd7a82..735915348 100644 --- a/test/core/expectations/binary/test_equal.pkb +++ b/test/ut3_user/expectations/binary/test_equal.pkb @@ -2,12 +2,12 @@ create or replace package body test_equal is procedure reset_nulls_equal is begin - ut3.ut_expectation_processor.nulls_Are_equal(ut3.ut_expectation_processor.gc_default_nulls_are_equal); + ut3_tester_helper.main_helper.reset_nulls_equal; end; procedure cleanup_expectations is begin - expectations.cleanup_expectations( ); + ut3_tester_helper.main_helper.clear_expectations( ); end; function to_equal_block( @@ -26,7 +26,7 @@ create or replace package body test_equal is l_actual '||a_actual_type||' := '||a_actual||'; l_expected '||a_expected_type||' := '||a_expected||'; begin - ut3.ut.expect( l_actual ).'||a_matcher_name||'(l_expected, a_nulls_are_equal=>'||l_nulls_equal||'); + ut3_develop.ut.expect( l_actual ).'||a_matcher_name||'(l_expected, a_nulls_are_equal=>'||l_nulls_equal||'); end;'; end; @@ -40,7 +40,7 @@ create or replace package body test_equal is begin execute immediate to_equal_block( 'to_equal', a_actual_type, a_expected_type, a_actual, a_expected, a_nulls_equal ); - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); cleanup_expectations; end; @@ -65,7 +65,7 @@ create or replace package body test_equal is begin execute immediate to_equal_block( 'to_equal', a_actual_type, a_expected_type, a_actual, a_expected, a_nulls_equal ); - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); cleanup_expectations; end; @@ -79,7 +79,7 @@ create or replace package body test_equal is begin execute immediate to_equal_block( 'not_to_equal', a_actual_type, a_expected_type, a_actual, a_expected, a_nulls_equal ); - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); cleanup_expectations; end; @@ -200,7 +200,7 @@ create or replace package body test_equal is procedure failure_on_both_null_with_conf is begin - ut3.ut_expectation_processor.nulls_Are_equal(false); + ut3_tester_helper.main_helper.nulls_are_equal(false); test_to_equal_fail('blob', 'NULL', 'NULL'); test_to_equal_fail('boolean', 'NULL', 'NULL'); test_to_equal_fail('clob', 'NULL', 'NULL'); @@ -246,7 +246,7 @@ create or replace package body test_equal is procedure success_on_both_null_with_parm is begin - ut3.ut_expectation_processor.nulls_Are_equal(false); + ut3_tester_helper.main_helper.nulls_are_equal(false); test_to_equal_success('blob', 'NULL', 'NULL', true); test_to_equal_success('boolean', 'NULL', 'NULL', true); test_to_equal_success('clob', 'NULL', 'NULL', true); diff --git a/test/core/expectations/binary/test_equal.pks b/test/ut3_user/expectations/binary/test_equal.pks similarity index 95% rename from test/core/expectations/binary/test_equal.pks rename to test/ut3_user/expectations/binary/test_equal.pks index c0280c288..923d43a31 100644 --- a/test/core/expectations/binary/test_equal.pks +++ b/test/ut3_user/expectations/binary/test_equal.pks @@ -1,7 +1,7 @@ create or replace package test_equal is --%suite((not)to_be_equal) - --%suitepath(utplsql.core.expectations.binary) + --%suitepath(utplsql.test_user.expectations.binary) procedure reset_nulls_equal; diff --git a/test/core/expectations/binary/test_expect_to_be_less_than.pkb b/test/ut3_user/expectations/binary/test_expect_to_be_less_than.pkb similarity index 68% rename from test/core/expectations/binary/test_expect_to_be_less_than.pkb rename to test/ut3_user/expectations/binary/test_expect_to_be_less_than.pkb index 8f1278db4..dbf6e30a4 100644 --- a/test/core/expectations/binary/test_expect_to_be_less_than.pkb +++ b/test/ut3_user/expectations/binary/test_expect_to_be_less_than.pkb @@ -2,7 +2,7 @@ create or replace package body test_expect_to_be_less_than is procedure cleanup_expectations is begin - expectations.cleanup_expectations( ); + ut3_tester_helper.main_helper.clear_expectations( ); end; function to_be_less_than_block( @@ -11,7 +11,7 @@ create or replace package body test_expect_to_be_less_than is a_expected varchar2 ) return varchar2 is begin - return expectations.binary_expectation_block( + return ut3_tester_helper.expectations_helper.binary_expectation_block( 'to_be_less_than', a_data_type, a_actual, a_data_type, a_expected ); end; @@ -22,7 +22,7 @@ create or replace package body test_expect_to_be_less_than is a_expected varchar2 ) return varchar2 is begin - return expectations.binary_expectation_block( + return ut3_tester_helper.expectations_helper.binary_expectation_block( 'not_to_be_less_than', a_data_type, a_actual, a_data_type, a_expected ); end; @@ -32,7 +32,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate to_be_less_than_block('date', 'sysdate', 'sysdate-1'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_number_greater is @@ -40,7 +40,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate to_be_less_than_block('number', '2.0', '1.99'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_interval_ym_greater is @@ -48,7 +48,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate to_be_less_than_block('interval year to month', '''2-1''', '''2-0'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_interval_ds_greater is @@ -56,7 +56,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate to_be_less_than_block('interval day to second', '''2 01:00:00''', '''2 00:59:59'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_timestamp_greater is @@ -64,7 +64,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate to_be_less_than_block('timestamp', 'to_timestamp(''1997 13'',''YYYY FF'')', 'to_timestamp(''1997 12'',''YYYY FF'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_timestamp_tz_greater is @@ -72,7 +72,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate to_be_less_than_block('timestamp with time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_timestamp_ltz_greater is @@ -80,7 +80,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate to_be_less_than_block('timestamp with local time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_date_equal is @@ -88,7 +88,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate to_be_less_than_block('date', 'sysdate', 'sysdate'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_number_equal is @@ -96,7 +96,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate to_be_less_than_block('number', '2.0', '2.00'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_interval_ym_equal is @@ -104,7 +104,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate to_be_less_than_block('interval year to month', '''2-1''', '''2-1'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_interval_ds_equal is @@ -112,7 +112,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate to_be_less_than_block('interval day to second', '''2 01:00:00''', '''2 01:00:00'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_timestamp_equal is @@ -120,7 +120,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate to_be_less_than_block('timestamp', 'to_timestamp(''1997 13'',''YYYY FF'')', 'to_timestamp(''1997 13'',''YYYY FF'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_timestamp_tz_equal is @@ -128,7 +128,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate to_be_less_than_block('timestamp with time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_timestamp_ltz_equal is @@ -136,7 +136,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate to_be_less_than_block('timestamp with local time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; procedure actual_date_less is @@ -144,7 +144,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate to_be_less_than_block('date', 'sysdate-1', 'sysdate'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_number_less is @@ -152,7 +152,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate to_be_less_than_block('number', '1.0', '1.01'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_interval_ym_less is @@ -160,7 +160,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate to_be_less_than_block('interval year to month', '''2-1''', '''2-2'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_interval_ds_less is @@ -168,7 +168,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate to_be_less_than_block('interval day to second', '''2 00:59:58''', '''2 00:59:59'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_timestamp_less is @@ -176,7 +176,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate to_be_less_than_block('timestamp', 'to_timestamp(''1997 12'',''YYYY FF'')', 'to_timestamp(''1997 13'',''YYYY FF'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_timestamp_tz_less is @@ -184,7 +184,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate to_be_less_than_block('timestamp with time zone', 'to_timestamp_tz(''1997 12 +03:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_timestamp_ltz_less is @@ -192,7 +192,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate to_be_less_than_block('timestamp with local time zone', 'to_timestamp_tz(''1997 12 +03:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure not_actual_date_greater is @@ -200,7 +200,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate not_to_be_less_than_block('date', 'sysdate', 'sysdate-1'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure not_actual_number_greater is @@ -208,7 +208,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate not_to_be_less_than_block('number', '2.0', '1.99'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure not_actual_interval_ym_greater is @@ -216,7 +216,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate not_to_be_less_than_block('interval year to month', '''2-1''', '''2-0'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure not_actual_interval_ds_greater is @@ -224,7 +224,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate not_to_be_less_than_block('interval day to second', '''2 01:00:00''', '''2 00:59:59'''); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure not_actual_timestamp_greater is @@ -232,7 +232,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate not_to_be_less_than_block('timestamp', 'to_timestamp(''1997 13'',''YYYY FF'')', 'to_timestamp(''1997 12'',''YYYY FF'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure not_actual_timestamp_tz_gretr is @@ -240,7 +240,7 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate not_to_be_less_than_block('timestamp with time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure not_actual_timestamp_ltz_gretr is @@ -248,15 +248,15 @@ create or replace package body test_expect_to_be_less_than is --Act execute immediate not_to_be_less_than_block('timestamp with local time zone', 'to_timestamp_tz(''1997 12 +01:00'',''YYYY FF TZR'')', 'to_timestamp_tz(''1997 12 +02:00'',''YYYY FF TZR'')'); --Assert - ut.expect( expectations.failed_expectations_data( ) ).to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; procedure actual_clob is begin --Act - ut3.ut.expect(to_clob('3')).to_( ut3.be_less_than(4) ); + ut3_develop.ut.expect(to_clob('3')).to_( ut3_develop.be_less_than(4) ); --Assert - ut.expect( expectations.failed_expectations_data( ) ).not_to_be_empty( ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); end; end; diff --git a/test/core/expectations/binary/test_expect_to_be_less_than.pks b/test/ut3_user/expectations/binary/test_expect_to_be_less_than.pks similarity index 98% rename from test/core/expectations/binary/test_expect_to_be_less_than.pks rename to test/ut3_user/expectations/binary/test_expect_to_be_less_than.pks index 67e6b8776..c03f0d28e 100644 --- a/test/core/expectations/binary/test_expect_to_be_less_than.pks +++ b/test/ut3_user/expectations/binary/test_expect_to_be_less_than.pks @@ -1,7 +1,7 @@ create or replace package test_expect_to_be_less_than is --%suite((not)to_be_less_than) - --%suitepath(utplsql.core.expectations.binary) + --%suitepath(utplsql.test_user.expectations.binary) --%aftereach procedure cleanup_expectations; diff --git a/test/ut3_user/expectations/binary/test_to_be_within.pkb b/test/ut3_user/expectations/binary/test_to_be_within.pkb new file mode 100644 index 000000000..032b684a5 --- /dev/null +++ b/test/ut3_user/expectations/binary/test_to_be_within.pkb @@ -0,0 +1,360 @@ +create or replace package body test_to_be_within is + + procedure cleanup_expectations is + begin + ut3_tester_helper.main_helper.clear_expectations( ); + end; + + function be_within_expectation_block( + a_matcher_name varchar2, + a_actual_data_type varchar2, + a_actual_data varchar2, + a_expected_data_type varchar2, + a_expected_data varchar2, + a_distance varchar2, + a_distance_data_type varchar2, + a_matcher_end varchar2 + ) return varchar2 + is + l_execute varchar2(32000); + begin + l_execute := ' + declare + l_actual '||a_actual_data_type||' := '||a_actual_data||'; + l_expected '||a_expected_data_type||' := '||a_expected_data||'; + l_distance '||a_distance_data_type||' := '||a_distance||'; + begin + --act - execute the expectation + ut3_develop.ut.expect( l_actual ).'||a_matcher_name||'(l_distance).of_(l_expected)'||a_matcher_end||'; + end;'; + return l_execute; + end; + + procedure test_to_be_within_fail( + a_matcher_name varchar2, + a_data_type varchar2, + a_actual varchar2, + a_expected varchar2, + a_distance varchar2, + a_distance_data_type varchar2, + a_matcher_end varchar2 := null + ) is + begin + execute immediate be_within_expectation_block( + a_matcher_name,a_data_type, a_actual, a_data_type, a_expected, + a_distance,a_distance_data_type, a_matcher_end + ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).not_to_equal(0); + cleanup_expectations; + end; + + procedure test_to_be_within_success( + a_matcher_name varchar2, + a_data_type varchar2, + a_actual varchar2, + a_expected varchar2, + a_distance varchar2, + a_distance_data_type varchar2, + a_matcher_end varchar2 := null + ) is + begin + execute immediate be_within_expectation_block( + a_matcher_name,a_data_type, a_actual, a_data_type, a_expected, + a_distance,a_distance_data_type, a_matcher_end + ); + ut.expect + (ut3_tester_helper.main_helper.get_failed_expectations_num + ,be_within_expectation_block( + a_matcher_name,a_data_type, a_actual, a_data_type, a_expected, + a_distance,a_distance_data_type, a_matcher_end + ) + ).to_equal(0); + cleanup_expectations; + end; + + procedure success_tests is + begin + test_to_be_within_success('to_be_within','number', '2', '4','2','number'); + test_to_be_within_success('to_be_within','number', '4', '2','2','number'); + test_to_be_within_success('to_be_within','date', 'sysdate+1', 'sysdate','''1 0:00:11.333''','interval day to second'); + test_to_be_within_success('to_be_within','date', 'sysdate', 'sysdate+1','''1 0:00:11.333''','interval day to second'); + test_to_be_within_success('to_be_within','date', 'sysdate', 'sysdate+200','''1-0''','interval year to month'); + test_to_be_within_success('to_be_within','date', 'sysdate+200', 'sysdate','''1-0''','interval year to month'); + + test_to_be_within_success('to_be_within','timestamp', q'[TIMESTAMP '2017-08-09 07:00:00']', q'[TIMESTAMP '2017-08-08 06:59:48.667']','''1 0:00:11.333''','interval day to second'); + test_to_be_within_success('to_be_within','timestamp', q'[TIMESTAMP '2017-08-08 06:59:48.667']', q'[TIMESTAMP '2017-08-09 07:00:00']','''1 0:00:11.333''','interval day to second'); + test_to_be_within_success('to_be_within','timestamp', q'[TIMESTAMP '2017-08-09 07:00:00']', q'[TIMESTAMP '2018-08-09 07:00:00']','''1-0''','interval year to month'); + test_to_be_within_success('to_be_within','timestamp', q'[TIMESTAMP '2018-08-09 07:00:00']', q'[TIMESTAMP '2017-08-09 07:00:00']','''1-0''','interval year to month'); + test_to_be_within_success('to_be_within','timestamp_tz_unconstrained', q'[TIMESTAMP '2017-08-09 07:00:00 -7:00']', q'[TIMESTAMP '2017-08-08 05:59:48.668 -8:00']','''1 0:00:11.333''','interval day to second'); + test_to_be_within_success('to_be_within','timestamp_tz_unconstrained', q'[TIMESTAMP '2017-08-08 05:59:48.668 -8:00']', q'[TIMESTAMP '2017-08-09 07:00:00 -7:00']','''1 0:00:11.333''','interval day to second'); + test_to_be_within_success('to_be_within','timestamp_tz_unconstrained', q'[TIMESTAMP '2017-08-09 07:00:00 -7:00']', q'[TIMESTAMP '2018-08-09 07:00:00 -7:00']','''1-0''','interval year to month'); + test_to_be_within_success('to_be_within','timestamp_tz_unconstrained', q'[TIMESTAMP '2018-08-09 07:00:00 -7:00']', q'[TIMESTAMP '2017-08-09 07:00:00 -7:00']','''1-0''','interval year to month'); + test_to_be_within_success('to_be_within','timestamp_ltz_unconstrained', q'[TIMESTAMP '2017-08-09 07:00:00 -7:00']', q'[TIMESTAMP '2017-08-08 05:59:48.668 -8:00']','''1 0:00:11.333''','interval day to second'); + test_to_be_within_success('to_be_within','timestamp_ltz_unconstrained', q'[TIMESTAMP '2017-08-08 05:59:48.668 -8:00']', q'[TIMESTAMP '2017-08-09 07:00:00 -7:00']','''1 0:00:11.333''','interval day to second'); + test_to_be_within_success('to_be_within','timestamp_ltz_unconstrained', q'[TIMESTAMP '2017-08-09 07:00:00 -7:00']', q'[TIMESTAMP '2018-08-09 07:00:00 -7:00']','''1-0''','interval year to month'); + test_to_be_within_success('to_be_within','timestamp_ltz_unconstrained', q'[TIMESTAMP '2018-08-09 07:00:00 -7:00']', q'[TIMESTAMP '2017-08-09 07:00:00 -7:00']','''1-0''','interval year to month'); + + test_to_be_within_success('to_( ut3_develop.be_within','number', '2', '4','2','number', ')'); + test_to_be_within_success('to_( ut3_develop.be_within','number', '4', '2','2','number', ')'); + test_to_be_within_success('to_( ut3_develop.be_within','date', 'sysdate+1', 'sysdate','''1 0:00:11.333''','interval day to second', ')'); + test_to_be_within_success('to_( ut3_develop.be_within','date', 'sysdate', 'sysdate+1','''1 0:00:11.333''','interval day to second', ')'); + test_to_be_within_success('to_( ut3_develop.be_within','date', 'sysdate', 'sysdate+200','''1-0''','interval year to month', ')'); + test_to_be_within_success('to_( ut3_develop.be_within','date', 'sysdate+200', 'sysdate','''1-0''','interval year to month', ')'); + test_to_be_within_success('to_( ut3_develop.be_within','timestamp', q'[TIMESTAMP '2018-08-09 07:00:00']', q'[TIMESTAMP '2017-08-09 07:00:00']','''1-0''','interval year to month', ')'); + test_to_be_within_success('to_( ut3_develop.be_within','timestamp_tz_unconstrained', q'[TIMESTAMP '2017-08-09 07:00:00 -7:00']', q'[TIMESTAMP '2017-08-08 05:59:48.668 -8:00']','''1 0:00:11.333''','interval day to second', ')'); + test_to_be_within_success('to_( ut3_develop.be_within','timestamp_ltz_unconstrained', q'[TIMESTAMP '2017-08-09 07:00:00 -7:00']', q'[TIMESTAMP '2017-08-08 05:59:48.668 -8:00']','''1 0:00:11.333''','interval day to second', ')'); + test_to_be_within_fail('not_to_be_within','number', '2', '4','2','number'); + test_to_be_within_fail('not_to_be_within','number', '4', '2','2','number'); + test_to_be_within_fail('not_to_be_within','date', 'sysdate+1', 'sysdate','''1 0:00:11.333''','interval day to second'); + test_to_be_within_fail('not_to_be_within','date', 'sysdate', 'sysdate+1','''1 0:00:11.333''','interval day to second'); + test_to_be_within_fail('not_to_be_within','date', 'sysdate', 'sysdate+200','''1-0''','interval year to month'); + test_to_be_within_fail('not_to_be_within','date', 'sysdate+200', 'sysdate','''1-0''','interval year to month'); + test_to_be_within_fail('not_to( ut3_develop.be_within','number', '2', '4','2','number',')'); + test_to_be_within_fail('not_to( ut3_develop.be_within','number', '4', '2','2','number',')'); + test_to_be_within_fail('not_to( ut3_develop.be_within','date', 'sysdate+1', 'sysdate','''1 0:00:11.333''','interval day to second',')'); + test_to_be_within_fail('not_to( ut3_develop.be_within','date', 'sysdate', 'sysdate+1','''1 0:00:11.333''','interval day to second',')'); + test_to_be_within_fail('not_to( ut3_develop.be_within','date', 'sysdate', 'sysdate+200','''1-0''','interval year to month',')'); + test_to_be_within_fail('not_to( ut3_develop.be_within','date', 'sysdate+200', 'sysdate','''1-0''','interval year to month',')'); + test_to_be_within_fail('not_to( ut3_develop.be_within','timestamp', q'[TIMESTAMP '2018-08-09 07:00:00']', q'[TIMESTAMP '2017-08-09 07:00:00']','''1-0''','interval year to month', ')'); + test_to_be_within_fail('not_to( ut3_develop.be_within','timestamp_tz_unconstrained', q'[TIMESTAMP '2017-08-09 07:00:00 -7:00']', q'[TIMESTAMP '2017-08-08 05:59:48.668 -8:00']','''1 0:00:11.333''','interval day to second', ')'); + test_to_be_within_fail('not_to( ut3_develop.be_within','timestamp_ltz_unconstrained', q'[TIMESTAMP '2017-08-09 07:00:00 -7:00']', q'[TIMESTAMP '2017-08-08 05:59:48.668 -8:00']','''1 0:00:11.333''','interval day to second', ')'); + test_to_be_within_fail('not_to_be_within','timestamp', q'[TIMESTAMP '2018-08-09 07:00:00']', q'[TIMESTAMP '2017-08-09 07:00:00']','''1-0''','interval year to month'); + test_to_be_within_fail('not_to_be_within','timestamp_tz_unconstrained', q'[TIMESTAMP '2017-08-09 07:00:00 -7:00']', q'[TIMESTAMP '2017-08-08 05:59:48.668 -8:00']','''1 0:00:11.333''','interval day to second'); + test_to_be_within_fail('not_to_be_within','timestamp_ltz_unconstrained', q'[TIMESTAMP '2017-08-09 07:00:00 -7:00']', q'[TIMESTAMP '2017-08-08 05:59:48.668 -8:00']','''1 0:00:11.333''','interval day to second'); + end; + + procedure failed_tests is + begin + test_to_be_within_fail('to_be_within','number', '2', '4','1','number'); + test_to_be_within_fail('to_be_within','number', '4', '2','1','number'); + test_to_be_within_fail('to_be_within','date', 'sysdate', 'sysdate+1','''0 0:00:11.333''','interval day to second'); + test_to_be_within_fail('to_be_within','date', 'sysdate+1', 'sysdate','''0 0:00:11.333''','interval day to second'); + test_to_be_within_fail('to_be_within','date', 'sysdate', 'sysdate+750','''1-0''','interval year to month'); + test_to_be_within_fail('to_be_within','date', 'sysdate+750', 'sysdate','''1-0''','interval year to month'); + test_to_be_within_fail('to_( ut3_develop.be_within','number', '2', '4','1','number',')'); + test_to_be_within_fail('to_( ut3_develop.be_within','number', '4', '2','1','number',')'); + test_to_be_within_fail('to_( ut3_develop.be_within','date', 'sysdate', 'sysdate+1','''0 0:00:11.333''','interval day to second',')'); + test_to_be_within_fail('to_( ut3_develop.be_within','date', 'sysdate+1', 'sysdate','''0 0:00:11.333''','interval day to second',')'); + test_to_be_within_fail('to_( ut3_develop.be_within','date', 'sysdate', 'sysdate+750','''1-0''','interval year to month',')'); + test_to_be_within_fail('to_( ut3_develop.be_within','date', 'sysdate+750', 'sysdate','''1-0''','interval year to month',')'); + test_to_be_within_success('not_to_be_within','number', '2', '4','1','number'); + test_to_be_within_success('not_to_be_within','number', '4', '2','1','number'); + test_to_be_within_success('not_to_be_within','date', 'sysdate', 'sysdate+1','''0 0:00:11.333''','interval day to second'); + test_to_be_within_success('not_to_be_within','date', 'sysdate+1', 'sysdate','''0 0:00:11.333''','interval day to second'); + test_to_be_within_success('not_to_be_within','date', 'sysdate', 'sysdate+750','''1-0''','interval year to month'); + test_to_be_within_success('not_to_be_within','date', 'sysdate+750', 'sysdate','''1-0''','interval year to month'); + test_to_be_within_success('not_to( ut3_develop.be_within','number', '2', '4','1','number',')'); + test_to_be_within_success('not_to( ut3_develop.be_within','number', '4', '2','1','number',')'); + test_to_be_within_success('not_to( ut3_develop.be_within','date', 'sysdate', 'sysdate+1','''0 0:00:11.333''','interval day to second',')'); + test_to_be_within_success('not_to( ut3_develop.be_within','date', 'sysdate+1', 'sysdate','''0 0:00:11.333''','interval day to second',')'); + test_to_be_within_success('not_to( ut3_develop.be_within','date', 'sysdate', 'sysdate+750','''1-0''','interval year to month',')'); + test_to_be_within_success('not_to( ut3_develop.be_within','date', 'sysdate+750', 'sysdate','''1-0''','interval year to month',')'); + end; + + procedure fail_for_number_not_within is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + --Act + ut3_develop.ut.expect(4).to_be_within(1).of_(7); + --Assert + l_expected_message := q'[Actual: 4 (number) was expected to be within 1 of 7 (number)]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure fail_for_ds_int_not_within is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + --Act + ut3_develop.ut.expect(sysdate).to_be_within(interval '1' second).of_(sysdate+1); + --Assert + l_expected_message := q'[Actual: % (date) was expected to be within 1 second of % (date)]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure fail_for_custom_ds_int is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + --Act + ut3_develop.ut.expect(sysdate).to_be_within(INTERVAL '2 3:04:11.333' DAY TO SECOND).of_(sysdate+100); + --Assert + l_expected_message := q'[Actual: % (date) was expected to be within 2 days 3 hours 4 minutes 11.333 seconds of % (date)]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure fail_for_ym_int_not_within is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + --Act + ut3_develop.ut.expect(sysdate).to_be_within(INTERVAL '1' MONTH).of_(sysdate+ 46); + --Assert + l_expected_message := q'[Actual: % (date) was expected to be within 1 month of % (date)]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure fail_for_custom_ym_int is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + --Act + ut3_develop.ut.expect(sysdate).to_be_within(INTERVAL '1-3' YEAR TO MONTH).of_(sysdate+720); + --Assert + l_expected_message := q'[Actual: % (date) was expected to be within 1 year 3 months % (date)]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure fail_msg_when_not_within is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + --Act + ut3_develop.ut.expect(1).to_be_within(3).of_(12); + --Assert + l_expected_message := q'[Actual: 1 (number) was expected to be within 3 of 12 (number)]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure fail_msg_wrong_types is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Act + ut3_develop.ut.expect(sysdate).to_be_within(interval '1' second).of_(systimestamp); + --Assert + l_expected_message := q'[Matcher 'be within' cannot be used to compare Actual (date) with Expected (timestamp with time zone) using distance (interval day to second).]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure null_expected is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Act + ut3_develop.ut.expect(sysdate).to_be_within(interval '1' second).of_(to_date(null)); + --Assert + l_expected_message := q'[Actual: % (date) was expected to be within 1 second of NULL (date)]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure null_actual_and_expected is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Act + ut3_develop.ut.expect(to_date(null)).to_be_within(interval '1' second).of_(to_date(null)); + --Assert + l_expected_message := q'[Actual: NULL (date) was expected to be within 1 second of NULL (date)]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure null_actual is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Act + ut3_develop.ut.expect(to_date(null)).to_be_within(interval '1' second).of_(sysdate); + --Assert + l_expected_message := q'[Actual: NULL (date) was expected to be within 1 second of % (date)]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + + procedure null_distance is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Act + ut3_develop.ut.expect(sysdate).to_be_within(cast(null as interval day to second)).of_(sysdate); + --Assert + l_expected_message := q'[Actual: % (date) was expected to be within NULL of % (date)]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + + procedure invalid_distance_for_number is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Act + ut3_develop.ut.expect(2).to_be_within(interval '1' second).of_(1); + --Assert + l_expected_message := q'[Matcher 'be within' cannot be used to compare Actual (number) with Expected (number) using distance (interval day to second).]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + + procedure invalid_distance_for_timestamp is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Act + ut3_develop.ut.expect(sysdate).to_be_within(1).of_(sysdate); + --Assert + l_expected_message := q'[Matcher 'be within' cannot be used to compare Actual (date) with Expected (date) using distance (number).]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure failure_on_tiny_time_diff is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Act + ut3_develop.ut.expect(timestamp'2022-01-29 23:23:23.000000009').to_be_within(interval '0.000000001' second).of_(timestamp'2022-01-29 23:23:23.000000001'); + --Assert + l_expected_message := q'[Actual: 2022-01-29T23:23:23.000000009 (timestamp) was expected to be within .000000001 seconds of 2022-01-29T23:23:23.000000001 (timestamp)]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + + procedure failure_on_large_years_compare is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Act + ut3_develop.ut.expect(to_date('-4000-01-01','syyyy-mm-dd')).to_be_within(interval '9990' year).of_(date '9999-12-31'); + --Assert + l_expected_message := q'[Actual: -4000-01-01T00:00:00 (date) was expected to be within 9990 years of 9999-12-31T00:00:00 (date)]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + +end; +/ diff --git a/test/ut3_user/expectations/binary/test_to_be_within.pks b/test/ut3_user/expectations/binary/test_to_be_within.pks new file mode 100644 index 000000000..966e9baaf --- /dev/null +++ b/test/ut3_user/expectations/binary/test_to_be_within.pks @@ -0,0 +1,61 @@ +create or replace package test_to_be_within is + + --%suite((not)to_be_within) + --%suitepath(utplsql.test_user.expectations.binary) + + --%aftereach + procedure cleanup_expectations; + + --%test(gives success for values within a distance) + procedure success_tests; + + --%test(gives failure when value is not within distance) + procedure failed_tests; + + --%test(returns well formatted failure message when expectation fails) + procedure fail_for_number_not_within; + + --%test(returns well formatted failure message for inteval of 1 sec not within) + procedure fail_for_ds_int_not_within; + + --%test(returns well formatted failure message for custom ds interval not within) + procedure fail_for_custom_ds_int; + + --%test(returns well formatted failure message for inteval of 1 month not within) + procedure fail_for_ym_int_not_within; + + --%test(returns well formatted failure message for custom ym interval not within) + procedure fail_for_custom_ym_int; + + --%test(returns well formatted failure message for simple within) + procedure fail_msg_when_not_within; + + --%test(returns well formatted failure message when comparing different datatypes) + procedure fail_msg_wrong_types; + + --%test(failure on null expected value) + procedure null_expected; + + --%test(failure on null actual value) + procedure null_actual; + + --%test(failure on null expected and actual value) + procedure null_actual_and_expected; + + --%test(failure on null distance value) + procedure null_distance; + + --%test(failure on invalid distance datatype for number expected) + procedure invalid_distance_for_number; + + --%test(failure on invalid distance datatype for timestamp expected) + procedure invalid_distance_for_timestamp; + + --%test(failure on exceeding difference in day second time by nanosecond) + procedure failure_on_tiny_time_diff; + + --%test(failure when comparing very large year difference) + procedure failure_on_large_years_compare; + +end; +/ diff --git a/test/ut3_user/expectations/binary/test_to_be_within_pct.pkb b/test/ut3_user/expectations/binary/test_to_be_within_pct.pkb new file mode 100644 index 000000000..da634d90e --- /dev/null +++ b/test/ut3_user/expectations/binary/test_to_be_within_pct.pkb @@ -0,0 +1,221 @@ +create or replace package body test_to_be_within_pct is + + procedure cleanup_expectations is + begin + ut3_tester_helper.main_helper.clear_expectations( ); + end; + + function be_within_expectation_block( + a_matcher varchar2, + a_actual_type varchar2, + a_actual varchar2, + a_expected_type varchar2, + a_expected varchar2, + a_distance varchar2, + a_distance_type varchar2, + a_matcher_end varchar2 + ) return varchar2 + is + l_execute varchar2(32000); + begin + l_execute := ' + declare + l_actual '||a_actual_type||' := '||a_actual||'; + l_expected '||a_expected_type||' := '||a_expected||'; + l_distance '||a_distance_type||' := '||a_distance||'; + begin + --act - execute the expectation + ut3_develop.ut.expect( l_actual ).'||a_matcher||'( l_distance ).of_( l_expected )'||a_matcher_end||'; + end;'; + return l_execute; + end; + + procedure test_to_be_within_fail( + a_matcher varchar2, + a_actual_type varchar2, + a_actual varchar2, + a_expected_type varchar2, + a_expected varchar2, + a_distance varchar2, + a_distance_type varchar2, + a_failure_message varchar2 := null, + a_matcher_end varchar2 := null + ) is + l_failure_text varchar2(4000); + begin + execute immediate be_within_expectation_block( + a_matcher,a_actual_type, a_actual, a_expected_type, a_expected, + a_distance,a_distance_type, a_matcher_end + ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(1); + if a_failure_message is not null then + l_failure_text := ut3_tester_helper.main_helper.get_failed_expectations(1); + ut.expect( l_failure_text ).to_be_like('%'||a_failure_message||'%' ); + end if; + cleanup_expectations; + end; + + procedure test_to_be_within_success( + a_matcher varchar2, + a_actual_type varchar2, + a_actual varchar2, + a_expected_type varchar2, + a_expected varchar2, + a_distance varchar2, + a_distance_type varchar2, + a_matcher_end varchar2 := null + ) is + begin + execute immediate be_within_expectation_block( + a_matcher,a_actual_type, a_actual, a_expected_type, a_expected, + a_distance,a_distance_type, a_matcher_end + ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + cleanup_expectations; + end; + + + procedure test_to_be_within_error( + a_matcher varchar2, + a_actual_type varchar2, + a_actual varchar2, + a_expected_type varchar2, + a_expected varchar2, + a_distance varchar2, + a_distance_type varchar2, + a_error_message varchar2, + a_matcher_end varchar2 := null + ) is + begin + execute immediate be_within_expectation_block( + a_matcher,a_actual_type, a_actual, a_expected_type, a_expected, + a_distance,a_distance_type, a_matcher_end + ); + cleanup_expectations; + ut.fail('Expected exception but nothing was raised'); + exception + when others then + ut.expect(sqlerrm).to_be_like('%'||a_error_message||'%'); + cleanup_expectations; + end; + + + procedure expect_success is + begin + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + cleanup_expectations; + end; + + procedure expect_failure is + begin + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(1); + cleanup_expectations; + end; + + procedure success_tests is + begin + ut3_develop.ut.expect( 1 ).to_be_within_pct( 0.01 ).of_(1.0001); + expect_success; + + ut3_develop.ut.expect( 1.0001 ).to_( ut3_develop.be_within_pct( 0.01 ).of_(1) ); + expect_success; + + ut3_develop.ut.expect( 1.0002 ).not_to_be_within_pct( 0.01 ).of_(1); + expect_success; + + ut3_develop.ut.expect( 1 ).not_to( ut3_develop.be_within_pct( 0.01 ).of_(1.0002) ); + expect_success; + + ut3_develop.ut.expect( 1.0001 ).to_be_within_pct( -0.01 ).of_(1); + expect_success; + + ut3_develop.ut.expect( 1 ).to_( ut3_develop.be_within_pct( -0.01 ).of_(1.0001) ); + expect_success; + + ut3_develop.ut.expect( 1.00000001 ).not_to_be_within_pct( 0 ).of_(1); + expect_success; + + ut3_develop.ut.expect( 0 ).not_to( ut3_develop.be_within_pct( 0.01 ).of_(0.000001) ); + expect_success; + + ut3_develop.ut.expect( 0 ).to_be_within_pct( 0 ).of_( 0 ); + expect_success; + + ut3_develop.ut.expect( 0 ).to_be_within_pct( 100 ).of_( 1 ); + expect_success; + + ut3_develop.ut.expect( -1 ).to_be_within_pct( 200 ).of_( 1 ); + expect_success; + end; + + procedure failed_tests is + begin + ut3_develop.ut.expect( 1 ).not_to_be_within_pct( 0.01 ).of_(1.0001); + expect_failure; + + ut3_develop.ut.expect( 1.0001 ).not_to( ut3_develop.be_within_pct( 0.01 ).of_(1) ); + expect_failure; + + ut3_develop.ut.expect( 1.0002 ).to_be_within_pct( 0.01 ).of_(1); + expect_failure; + + ut3_develop.ut.expect( 1 ).to_( ut3_develop.be_within_pct( 0.01 ).of_(1.0002) ); + expect_failure; + + ut3_develop.ut.expect( 1.0001 ).not_to_be_within_pct( -0.01 ).of_(1); + expect_failure; + + ut3_develop.ut.expect( 1 ).not_to( ut3_develop.be_within_pct( -0.01 ).of_(1.0001) ); + expect_failure; + + ut3_develop.ut.expect( 1.00000001 ).to_be_within_pct( 0 ).of_(1); + expect_failure; + + ut3_develop.ut.expect( 0 ).to_( ut3_develop.be_within_pct( 0.01 ).of_(0.000001) ); + expect_failure; + + ut3_develop.ut.expect( 0 ).not_to_be_within_pct( 0 ).of_( 0 ); + expect_failure; + + ut3_develop.ut.expect( 0 ).not_to_be_within_pct( 100 ).of_( 1 ); + expect_failure; + + ut3_develop.ut.expect( -1 ).not_to_be_within_pct( 200 ).of_( 1 ); + expect_failure; + end; + + procedure fail_for_number_not_within is + begin + test_to_be_within_fail( + 'to_be_within_pct','number', '4', 'number','7', + '1','number', + q'[Actual: 4 (number) was expected to be within 1 % of 7 (number)]' + ); + end; + + procedure fail_at_invalid_argument_types is + begin + test_to_be_within_error( + 'to_be_within_pct','date', 'sysdate', 'date','sysdate', + '''0 0:00:11.333''','interval day to second', + 'wrong number or types of arguments in call to ''TO_BE_WITHIN_PCT''' + ); + test_to_be_within_error( + 'to_be_within_pct','number','1', 'date', 'sysdate', + '1','number', + ' wrong number or types of arguments in call to ''OF_''' + ); + test_to_be_within_error( + 'to_be_within_pct','number','1','number','1', + 'sysdate', 'date', + ' wrong number or types of arguments in call to ''TO_BE_WITHIN_PCT''' + ); + test_to_be_within_fail( + 'to_be_within_pct','date', 'sysdate', 'number','1', + '1','number', + 'Matcher ''be within pct'' cannot be used to compare Actual (date) with Expected (number) using distance (number).' + ); + end; + +end; +/ diff --git a/test/ut3_user/expectations/binary/test_to_be_within_pct.pks b/test/ut3_user/expectations/binary/test_to_be_within_pct.pks new file mode 100644 index 000000000..4b8f0cb4c --- /dev/null +++ b/test/ut3_user/expectations/binary/test_to_be_within_pct.pks @@ -0,0 +1,22 @@ +create or replace package test_to_be_within_pct is + + --%suite((not)to_be_within_pct) + --%suitepath(utplsql.test_user.expectations.binary) + + --%aftereach + procedure cleanup_expectations; + + --%test(gives success for values within a distance) + procedure success_tests; + + --%test(gives failure when number is not within distance) + procedure failed_tests; + + --%test(returns well formatted failure message when expectation fails) + procedure fail_for_number_not_within; + + --%test(fails at compile or run time for unsupported data-types ) + procedure fail_at_invalid_argument_types; + +end; +/ diff --git a/test/ut3_user/expectations/test_expectation_anydata.pkb b/test/ut3_user/expectations/test_expectation_anydata.pkb new file mode 100644 index 000000000..c70d41f9e --- /dev/null +++ b/test/ut3_user/expectations/test_expectation_anydata.pkb @@ -0,0 +1,1259 @@ +create or replace package body test_expectation_anydata is + + g_test_expected anydata; + g_test_actual anydata; + + procedure cleanup_expectations is + begin + ut3_tester_helper.main_helper.clear_expectations( ); + end; + + procedure cleanup is + begin + g_test_expected := null; + g_test_actual := null; + cleanup_expectations(); + end; + + procedure fail_on_different_type_null is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + g_test_expected := anydata.convertObject( cast(null as ut3_tester_helper.test_dummy_object) ); + g_test_actual := anydata.convertObject( cast(null as ut3_tester_helper.other_dummy_object) ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + --Assert + l_expected_message := q'[%Actual (ut3_tester_helper.other_dummy_object) cannot be compared to Expected (ut3_tester_helper.test_dummy_object) using matcher 'equal'.]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure fail_on_different_type is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(1, 'A', '0') ); + g_test_actual := anydata.convertObject( ut3_tester_helper.other_dummy_object(1, 'A', '0') ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + --Assert + l_expected_message := q'[%Actual (ut3_tester_helper.other_dummy_object) cannot be compared to Expected (ut3_tester_helper.test_dummy_object) using matcher 'equal'.]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure fail_on_different_object_data is + begin + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(1, 'A', '0') ); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(1, null, '0') ); + --Act + ut3_develop.ut.expect( g_test_actual ).not_to_equal( g_test_expected ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure fail_on_one_object_null is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(1, 'A', '0') ); + g_test_actual := anydata.convertObject( cast(null as ut3_tester_helper.test_dummy_object) ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + --Assert + l_expected_message := q'[%Actual: ut3_tester_helper.test_dummy_object was expected to equal: ut3_tester_helper.test_dummy_object +%Diff: +%Rows: [ 1 differences ] +%Row No. 1 - Missing: 1A0]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + + end; + + procedure fail_on_collection_vs_object is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(1, 'A', '0') ); + g_test_actual := anydata.convertCollection( ut3_tester_helper.test_dummy_object_list(ut3_tester_helper.test_dummy_object(1, 'A', '0')) ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + --Assert + l_expected_message := q'[%Actual (ut3_tester_helper.test_dummy_object_list) cannot be compared to Expected (ut3_tester_helper.test_dummy_object) using matcher 'equal'.]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure fail_on_null_vs_empty_coll is + l_null_list ut3_tester_helper.test_dummy_object_list; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + g_test_expected := anydata.convertCollection( ut3_tester_helper.test_dummy_object_list() ); + g_test_actual := anydata.convertCollection( l_null_list ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + --Assert + l_expected_message := q'[%Actual: ut3_tester_helper.test_dummy_object_list [ null ] was expected to equal: ut3_tester_helper.test_dummy_object_list [ count = 0 ]]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + + end; + + procedure fail_on_one_collection_null is + l_null_list ut3_tester_helper.test_dummy_object_list; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + g_test_expected := anydata.convertCollection( ut3_tester_helper.test_dummy_object_list(ut3_tester_helper.test_dummy_object(1, 'A', '0')) ); + g_test_actual := anydata.convertCollection( l_null_list ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + --Assert + l_expected_message := q'[%Actual: ut3_tester_helper.test_dummy_object_list [ null ] was expected to equal: ut3_tester_helper.test_dummy_object_list [ count = 1 ] +%Diff: +%Rows: [ 1 differences ] +%Row No. 1 - Missing: 1A0]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure fail_on_one_collection_empty is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + g_test_expected := anydata.convertCollection( ut3_tester_helper.test_dummy_object_list(ut3_tester_helper.test_dummy_object(1, 'A', '0')) ); + g_test_actual := anydata.convertCollection( ut3_tester_helper.test_dummy_object_list() ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + --Assert + l_expected_message := q'[%Actual: ut3_tester_helper.test_dummy_object_list [ count = 0 ] was expected to equal: ut3_tester_helper.test_dummy_object_list [ count = 1 ] +%Diff: +%Rows: [ 1 differences ] +%Row No. 1 - Missing: 1A0]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + + end; + + procedure fail_on_different_coll_data is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + l_obj ut3_tester_helper.test_dummy_object := ut3_tester_helper.test_dummy_object(1, 'A', '0'); + begin + --Arrange + g_test_expected := anydata.convertCollection( ut3_tester_helper.test_dummy_object_list(l_obj) ); + g_test_actual := anydata.convertCollection( ut3_tester_helper.test_dummy_object_list(l_obj, l_obj) ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + --Assert + l_expected_message := q'[%Actual: ut3_tester_helper.test_dummy_object_list [ count = 2 ] was expected to equal: ut3_tester_helper.test_dummy_object_list [ count = 1 ] +%Diff: +%Rows: [ 1 differences ] +%Row No. 2 - Extra: 1A0]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + --%test(Gives success when both anydata are NULL) + procedure success_on_both_anydata_null is + --Arrange + l_null_anydata anydata; + begin + --Act + ut3_develop.ut.expect( l_null_anydata ).to_equal( l_null_anydata ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure success_on_both_object_null is + --Arrange + l_null_object ut3_tester_helper.test_dummy_object; + l_anydata anydata := anydata.convertObject(l_null_object); + begin + --Act + ut3_develop.ut.expect( l_anydata ).to_equal( l_anydata ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure success_on_both_coll_null is + --Arrange + l_null_collection ut3_tester_helper.test_dummy_object_list; + l_anydata anydata := anydata.convertCollection(l_null_collection); + begin + --Act + ut3_develop.ut.expect( l_anydata ).to_equal( l_anydata ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure success_on_same_coll_data is + begin + --Arrange + g_test_expected := anydata.convertCollection( ut3_tester_helper.test_dummy_object_list(ut3_tester_helper.test_dummy_object(1, 'A', '0')) ); + g_test_actual := anydata.convertCollection( ut3_tester_helper.test_dummy_object_list(ut3_tester_helper.test_dummy_object(1, 'A', '0')) ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure fail_on_coll_different_order is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + l_first_obj ut3_tester_helper.test_dummy_object := ut3_tester_helper.test_dummy_object(1, 'A', '0'); + l_second_obj ut3_tester_helper.test_dummy_object := ut3_tester_helper.test_dummy_object(2, 'b', '1'); + begin + --Arrange + g_test_expected := anydata.convertCollection( ut3_tester_helper.test_dummy_object_list(l_first_obj, l_second_obj) ); + g_test_actual := anydata.convertCollection( ut3_tester_helper.test_dummy_object_list(l_second_obj, l_first_obj) ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure success_on_same_object_data is + begin + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(1, 'A', '0') ); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(1, 'A', '0') ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure exclude_attributes_as_list is + l_list ut3_develop.ut_varchar2_list; + begin + --Arrange + l_list := ut3_develop.ut_varchar2_list('Value','/ID'); + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>3, "name"=>'A',"Value"=>'1') ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected, a_exclude=> l_list ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure exclude_attributes_as_csv is + l_list varchar2(100); + begin + --Arrange + l_list := 'Value,ID'; + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>2, "name"=>'A',"Value"=>'1') ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected, a_exclude=> l_list ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure exclude_attributes_xpath is + l_xpath varchar2(100); + begin + --Arrange + l_xpath := '//Value|//ID'; + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>2, "name"=>'A',"Value"=>'1') ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected, a_exclude=> l_xpath ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure exclude_ignores_invalid_attrib is + l_exclude varchar2(100); + begin + --Arrange + l_exclude := 'BadAttributeName'; + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected, a_exclude=> l_exclude ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure include_attributes_as_list is + l_list ut3_develop.ut_varchar2_list; + begin + --Arrange + l_list := ut3_develop.ut_varchar2_list('Value','ID'); + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'b',"Value"=>'0') ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ).include( l_list ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure include_attributes_as_csv is + l_xpath varchar2(100); + begin + --Arrange + l_xpath := 'key,ID'; + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'1') ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ).include( l_xpath ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure include_attributes_xpath is + l_xpath varchar2(100); + begin + --Arrange + l_xpath := '//key|//ID'; + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'0') ); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'1') ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ).include( l_xpath ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure include_ignores_invalid_attrib is + l_include varchar2(100); + begin + --Arrange + l_include := ' BadAttributeName, ID '; + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'B',"Value"=>'0') ); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'1') ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ).include( l_include ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure include_exclude_attributes_csv is + l_exclude varchar2(100); + l_include varchar2(100); + begin + --Arrange + l_include := 'key,ID,Value'; + l_exclude := '//key|//Value'; + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'B',"Value"=>'0') ); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'1') ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ).exclude( l_exclude ).include( l_include ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure include_exclude_attrib_list is + l_exclude ut3_develop.ut_varchar2_list; + l_include ut3_develop.ut_varchar2_list; + l_expected varchar2(32767); + l_actual varchar2(32767); + begin + --Arrange + l_include := ut3_develop.ut_varchar2_list('key','ID','Value'); + l_exclude := ut3_develop.ut_varchar2_list('key','Value'); + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'B',"Value"=>'0') ); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(id=>1, "name"=>'A',"Value"=>'1') ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ).exclude( l_exclude ).include( l_include ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure reports_diff_attribute is + l_expected varchar2(32767); + l_actual varchar2(32767); + begin + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(1, 'A', '0') ); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(1, NULL, '0') ); + l_expected := q'[Actual: ut3_tester_helper.test_dummy_object was expected to equal: ut3_tester_helper.test_dummy_object +Diff: +Rows: [ 1 differences ] + Row No. 1 - Actual: + Row No. 1 - Expected: A]'; + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + --Assert + l_actual := ut3_tester_helper.main_helper.get_failed_expectations(1); + ut.expect(l_actual).to_be_like(l_expected); + end; + + + procedure reports_diff_structure is + l_obj ut3_tester_helper.test_dummy_object := ut3_tester_helper.test_dummy_object(1, 'A', '0'); + l_expected varchar2(32767); + l_actual varchar2(32767); + begin + --Arrange + g_test_expected := anydata.convertCollection( ut3_tester_helper.test_dummy_object_list(l_obj) ); + g_test_actual := anydata.convertCollection( ut3_tester_helper.test_dummy_object_list(l_obj, l_obj) ); + l_expected := q'[Actual: ut3_tester_helper.test_dummy_object_list [ count = 2 ] was expected to equal: ut3_tester_helper.test_dummy_object_list [ count = 1 ] +Diff: +Rows: [ 1 differences ] + Row No. 2 - Extra: 1A0]'; + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + --Assert + l_actual := ut3_tester_helper.main_helper.get_failed_expectations(1); + ut.expect(l_actual).to_be_like(l_expected); + end; + + function get_anydata return anydata is + begin + return anydata.convertObject( ut3_tester_helper.test_dummy_object(1, 'B', '0') ); + end; + + procedure deprec_to_equal_excl_varch is + begin + --Act + ut3_develop.ut.expect(get_anydata()).to_equal(get_anydata(), a_exclude => 'A_COLUMN,Some_Col'); + --Assert + ut.expect(cardinality(ut3_tester_helper.main_helper.get_warnings())).to_equal(1); + ut.expect(ut3_tester_helper.main_helper.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); + end; + + procedure deprec_to_equal_excl_list is + begin + --Act + ut3_develop.ut.expect(get_anydata()).to_equal(get_anydata(), a_exclude => ut3_develop.ut_varchar2_list('A_COLUMN','Some_Col')); + --Assert + ut.expect(cardinality(ut3_tester_helper.main_helper.get_warnings())).to_equal(1); + ut.expect(ut3_tester_helper.main_helper.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); + end; + + procedure deprec_not_to_equal_excl_varch is + begin + --Act + ut3_develop.ut.expect(get_anydata()).not_to_equal(get_anydata(), a_exclude => 'A_COLUMN,Some_Col'); + --Assert + ut.expect(cardinality(ut3_tester_helper.main_helper.get_warnings())).to_equal(1); + ut.expect(ut3_tester_helper.main_helper.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); + end; + + procedure deprec_not_to_equal_excl_list is + begin + --Act + ut3_develop.ut.expect(get_anydata()).not_to_equal(get_anydata(), a_exclude => ut3_develop.ut_varchar2_list('A_COLUMN','Some_Col')); + --Assert + ut.expect(cardinality(ut3_tester_helper.main_helper.get_warnings())).to_equal(1); + ut.expect(ut3_tester_helper.main_helper.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); + end; + + procedure deprec_equal_excl_varch is + begin + --Act + ut3_develop.ut.expect(get_anydata()).to_(ut3_develop.equal(get_anydata(), a_exclude => 'A_COLUMN,Some_Col')); + --Assert + ut.expect(cardinality(ut3_tester_helper.main_helper.get_warnings())).to_equal(1); + ut.expect(ut3_tester_helper.main_helper.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); + end; + + procedure deprec_equal_excl_list is + begin + --Act + ut3_develop.ut.expect(get_anydata()).to_(ut3_develop.equal(get_anydata(), a_exclude => ut3_develop.ut_varchar2_list('A_COLUMN','Some_Col'))); + --Assert + ut.expect(cardinality(ut3_tester_helper.main_helper.get_warnings())).to_equal(1); + ut.expect(ut3_tester_helper.main_helper.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); + end; + + procedure data_diff_on_atr_data_mismatch is + l_actual ut3_tester_helper.test_dummy_object_list; + l_expected ut3_tester_helper.test_dummy_object_list; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) + bulk collect into l_actual + from dual connect by level <=2; + select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) + bulk collect into l_expected + from dual connect by level <=2 + order by rownum desc; + --Act + ut3_develop.ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); + + l_expected_message := q'[Actual: ut3_tester_helper.test_dummy_object_list [ count = 2 ] was expected to equal: ut3_tester_helper.test_dummy_object_list [ count = 2 ] +Diff: +Rows: [ 2 differences ] + Row No. 1 - Actual: 1Something 11 + Row No. 1 - Expected: 2Something 22 + Row No. 2 - Actual: 2Something 22 + Row No. 2 - Expected: 1Something 11]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure data_diff_on_20_rows_only is + l_actual ut3_tester_helper.test_dummy_object_list; + l_expected ut3_tester_helper.test_dummy_object_list; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + select ut3_tester_helper.test_dummy_object( rn, 'Something '||rn, rn1) + bulk collect into l_actual + from (select rownum * case when mod(rownum,2) = 0 then -1 else 1 end rn, + rownum * case when mod(rownum,4) = 0 then -1 else 1 end rn1 + from dual connect by level <=100); + select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) + bulk collect into l_expected + from dual connect by level <=110; + --Act + ut3_develop.ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); + + l_expected_message := q'[Actual: ut3_tester_helper.test_dummy_object_list [ count = 100 ] was expected to equal: ut3_tester_helper.test_dummy_object_list [ count = 110 ] +Diff: +Rows: [ 60 differences, showing first 20 ] + Row No. 2 - Actual: -2Something -2 + Row No. 2 - Expected: 2Something 2 + Row No. 4 - Actual: -4Something -4-4 + Row No. 4 - Expected: 4Something 44 + % + Row No. 38 - Actual: -38Something -38 + Row No. 38 - Expected: 38Something 38 + Row No. 40 - Actual: -40Something -40-40 + Row No. 40 - Expected: 40Something 4040]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure collection_include_list is + l_actual ut3_tester_helper.test_dummy_object_list; + l_expected ut3_tester_helper.test_dummy_object_list; + l_list ut3_develop.ut_varchar2_list; + begin + l_list := ut3_develop.ut_varchar2_list('Value','ID'); + --Arrange + select ut3_tester_helper.test_dummy_object( rownum, 'SomethingsDifferent '||rownum, rownum) + bulk collect into l_actual + from dual connect by level <=2; + select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) + bulk collect into l_expected + from dual connect by level <=2; + --Act + ut3_develop.ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)).include( l_list ); + + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure collection_exclude_list is + l_actual ut3_tester_helper.test_dummy_object_list; + l_expected ut3_tester_helper.test_dummy_object_list; + l_list ut3_develop.ut_varchar2_list; + begin + l_list := ut3_develop.ut_varchar2_list('Value','ID'); + --Arrange + select ut3_tester_helper.test_dummy_object( rownum*2, 'Something '||rownum, rownum*2) + bulk collect into l_actual + from dual connect by level <=2; + select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) + bulk collect into l_expected + from dual connect by level <=2; + --Act + ut3_develop.ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)).exclude( l_list ); + + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure collection_include_list_fail is + l_actual ut3_tester_helper.test_dummy_object_list; + l_expected ut3_tester_helper.test_dummy_object_list; + l_list ut3_develop.ut_varchar2_list; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + l_list := ut3_develop.ut_varchar2_list('name'); + --Arrange + select ut3_tester_helper.test_dummy_object( rownum, 'SomethingsDifferent '||rownum, rownum) + bulk collect into l_actual + from dual connect by level <=2; + select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) + bulk collect into l_expected + from dual connect by level <=2; + --Act + ut3_develop.ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)).include( l_list ); + + l_expected_message := q'[%Actual: ut3_tester_helper.test_dummy_object_list [ count = 2 ] was expected to equal: ut3_tester_helper.test_dummy_object_list [ count = 2 ] +%Diff: +%Rows: [ 2 differences ] +%Row No. 1 - Actual: SomethingsDifferent 1 +%Row No. 1 - Expected: Something 1 +%Row No. 2 - Actual: SomethingsDifferent 2 +%Row No. 2 - Expected: Something 2]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure array_same_data is + begin + --Arrange + g_test_expected := anydata.convertCollection( ut3_tester_helper.t_tab_varchar('A') ); + g_test_actual := anydata.convertCollection( ut3_tester_helper.t_tab_varchar('A') ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure array_diff_data is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + g_test_expected := anydata.convertCollection( ut3_tester_helper.t_tab_varchar('A') ); + g_test_actual := anydata.convertCollection( ut3_tester_helper.t_tab_varchar('B') ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + l_expected_message := q'[%Actual: ut3_tester_helper.t_tab_varchar [ count = 1 ] was expected to equal: ut3_tester_helper.t_tab_varchar [ count = 1 ] +%Diff: +%Rows: [ 1 differences ] +%Row No. 1 - Actual: B +%Row No. 1 - Expected: A]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure array_is_null is + l_is_null ut3_tester_helper.t_tab_varchar ; + begin + ut3_develop.ut.expect( anydata.convertCollection( l_is_null ) ).to_be_null; + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure array_null_equal_array_null is + l_is_null ut3_tester_helper.t_tab_varchar ; + l_is_null_bis ut3_tester_helper.t_tab_varchar ; + begin + ut3_develop.ut.expect( anydata.convertCollection( l_is_null ) ).to_equal(anydata.convertCollection( l_is_null_bis )); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure array_null_equal_array_notnull is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + l_is_null ut3_tester_helper.t_tab_varchar ; + begin + --Arrange + g_test_expected := anydata.convertCollection( l_is_null ); + g_test_actual := anydata.convertCollection( ut3_tester_helper.t_tab_varchar('A') ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + l_expected_message := q'[%Actual: ut3_tester_helper.t_tab_varchar [ count = 1 ] was expected to equal: ut3_tester_helper.t_tab_varchar [ null ] +%Diff: +%Rows: [ 1 differences ] +%Row No. 1 - Extra: A]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure empty_array_have_zero_elem is + begin + ut3_develop.ut.expect( anydata.convertCollection(ut3_tester_helper.t_tab_varchar())).to_have_count(0); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure array_empty_equal_array_empty is + begin + --Arrange + g_test_expected := anydata.convertCollection(ut3_tester_helper.t_tab_varchar()); + g_test_actual := anydata.convertCollection(ut3_tester_helper.t_tab_varchar()); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure arr_empty_equal_arr_notempty is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + l_is_null ut3_tester_helper.t_tab_varchar ; + begin + --Arrange + g_test_expected := anydata.convertCollection( ut3_tester_helper.t_tab_varchar() ); + g_test_actual := anydata.convertCollection( ut3_tester_helper.t_tab_varchar('A') ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + l_expected_message := q'[%Actual: ut3_tester_helper.t_tab_varchar [ count = 1 ] was expected to equal: ut3_tester_helper.t_tab_varchar [ count = 0 ] +%Diff: +%Rows: [ 1 differences ] +%Row No. 1 - Extra: A]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure collection_is_null is + l_null_list ut3_tester_helper.test_dummy_object_list; + begin + --Arrange + g_test_actual := anydata.convertCollection( l_null_list ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_be_null; + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure collection_is_empty is + begin + --Arrange + g_test_actual := anydata.convertCollection( ut3_tester_helper.test_dummy_object_list() ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_have_count(0); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + + end; + + procedure varray_same_data is + begin + --Arrange + g_test_expected := anydata.convertCollection( ut3_tester_helper.t_varray(1) ); + g_test_actual := anydata.convertCollection( ut3_tester_helper.t_varray(1) ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure varray_diff_data is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + g_test_expected := anydata.convertCollection( ut3_tester_helper.t_varray(1) ); + g_test_actual := anydata.convertCollection( ut3_tester_helper.t_varray(2) ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + l_expected_message := q'[%Actual: ut3_tester_helper.t_varray [ count = 1 ] was expected to equal: ut3_tester_helper.t_varray [ count = 1 ] +%Diff: +%Rows: [ 1 differences ] +%Row No. 1 - Actual: 2 +%Row No. 1 - Expected: 1]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure varray_is_null is + l_is_null ut3_tester_helper.t_varray ; + begin + ut3_develop.ut.expect( anydata.convertCollection( l_is_null ) ).to_be_null; + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure varray_null_equal_varray_null is + l_is_null ut3_tester_helper.t_varray ; + l_is_null_bis ut3_tester_helper.t_varray ; + begin + ut3_develop.ut.expect( anydata.convertCollection( l_is_null ) ).to_equal(anydata.convertCollection( l_is_null_bis )); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure varr_null_equal_varr_notnull is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + l_is_null ut3_tester_helper.t_varray ; + begin + --Arrange + g_test_expected := anydata.convertCollection( l_is_null ); + g_test_actual := anydata.convertCollection( ut3_tester_helper.t_varray(1) ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + l_expected_message := q'[%Actual: ut3_tester_helper.t_varray [ count = 1 ] was expected to equal: ut3_tester_helper.t_varray [ null ] +%Diff: +%Rows: [ 1 differences ] +%Row No. 1 - Extra: 1]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure empty_varray_have_zero_elem is + begin + ut3_develop.ut.expect( anydata.convertCollection(ut3_tester_helper.t_varray())).to_have_count(0); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure varr_empty_equal_varr_empty is + begin + --Arrange + g_test_expected := anydata.convertCollection(ut3_tester_helper.t_varray()); + g_test_actual := anydata.convertCollection(ut3_tester_helper.t_varray()); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure varr_empty_equal_varr_notempty is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + l_is_null ut3_tester_helper.t_varray ; + begin + --Arrange + g_test_expected := anydata.convertCollection( ut3_tester_helper.t_varray() ); + g_test_actual := anydata.convertCollection( ut3_tester_helper.t_varray(1) ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + l_expected_message := q'[%Actual: ut3_tester_helper.t_varray [ count = 1 ] was expected to equal: ut3_tester_helper.t_varray [ count = 0 ] +%Diff: +%Rows: [ 1 differences ] +%Row No. 1 - Extra: 1]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure collection_join_by is + l_actual ut3_tester_helper.test_dummy_object_list; + l_expected ut3_tester_helper.test_dummy_object_list; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) + bulk collect into l_actual + from dual connect by level <=2; + select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) + bulk collect into l_expected + from dual connect by level <=2 + order by rownum desc; + --Act + ut3_develop.ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)).join_by('ID'); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure collection_join_by_fail is + l_actual ut3_tester_helper.test_dummy_object_list; + l_expected ut3_tester_helper.test_dummy_object_list; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) + bulk collect into l_actual + from dual connect by level <=2; + select ut3_tester_helper.test_dummy_object( rownum * 2, 'Something '||rownum, rownum) + bulk collect into l_expected + from dual connect by level <=2 + order by rownum desc; + --Act + ut3_develop.ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)).join_by('ID'); + l_expected_message := q'[%Actual: ut3_tester_helper.test_dummy_object_list [ count = 2 ] was expected to equal: ut3_tester_helper.test_dummy_object_list [ count = 2 ] +%Diff: +%Rows: [ 3 differences ] +%PK 2 - Actual: Something 22 +%PK 2 - Expected: Something 11 +%PK 1 - Extra: 1Something 11 +%PK 4 - Missing: 4Something 22]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure collection_unordered is + l_actual ut3_tester_helper.test_dummy_object_list; + l_expected ut3_tester_helper.test_dummy_object_list; + begin + --Arrange + select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) + bulk collect into l_actual + from dual connect by level <=3; + select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) + bulk collect into l_expected + from dual connect by level <=3 + order by rownum desc; + --Act + ut3_develop.ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)).unordered; + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure collection_unordered_fail is + l_actual ut3_tester_helper.test_dummy_object_list; + l_expected ut3_tester_helper.test_dummy_object_list; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) + bulk collect into l_actual + from dual connect by level <=2; + select ut3_tester_helper.test_dummy_object( rownum * 2, 'Something '||rownum, rownum) + bulk collect into l_expected + from dual connect by level <=2 + order by rownum desc; + + l_expected_message := q'[%Actual: ut3_tester_helper.test_dummy_object_list [ count = 2 ] was expected to equal: ut3_tester_helper.test_dummy_object_list [ count = 2 ] +%Diff: +%Rows: [ 4 differences ] +%Extra: 1Something 11 +%Extra: 2Something 22 +%Missing: 4Something 22 +%Missing: 2Something 11]'; + + ut3_develop.ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)).unordered; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure object_join_by is + begin + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(1, 'A', '0') ); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(1, 'A', '0') ); + + --Act + ut3_develop.ut.expect(g_test_actual).to_equal(g_test_expected).join_by('ID'); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure object_unordered is + begin + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(1, 'A', '0') ); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(1, 'A', '0') ); + + --Act + ut3_develop.ut.expect(g_test_actual).to_equal(g_test_expected).unordered; + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure collection_to_contain is + l_actual ut3_tester_helper.test_dummy_object_list; + l_expected ut3_tester_helper.test_dummy_object_list; + begin + --Arrange + select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) + bulk collect into l_actual + from dual connect by level <=4; + select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) + bulk collect into l_expected + from dual connect by level <=2 + order by rownum desc; + --Act + ut3_develop.ut.expect(anydata.convertCollection(l_actual)).to_contain(anydata.convertCollection(l_expected)); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure collection_not_to_contain is + l_actual ut3_tester_helper.test_dummy_object_list; + l_expected ut3_tester_helper.test_dummy_object_list; + begin + --Arrange + select ut3_tester_helper.test_dummy_object( rownum, 'Something2 '||rownum, rownum+100) + bulk collect into l_actual + from dual connect by level <=4; + select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) + bulk collect into l_expected + from dual connect by level <=2 + order by rownum desc; + --Act + ut3_develop.ut.expect(anydata.convertCollection(l_actual)).not_to_contain(anydata.convertCollection(l_expected)); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure object_to_contain is + begin + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_object(1, 'A', '0') ); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_object(1, 'A', '0') ); + + --Act + ut3_develop.ut.expect(g_test_actual).to_contain(g_test_expected); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure arr_empty_eq_arr_empty_unord is + begin + --Arrange + g_test_expected := anydata.convertCollection(ut3_tester_helper.t_tab_varchar(null)); + g_test_actual := anydata.convertCollection(ut3_tester_helper.t_tab_varchar(null)); + + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ).unordered(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + + end; + + procedure arr_empty_nqua_arr_e_unord is + begin + --Arrange + g_test_expected := anydata.convertCollection(ut3_tester_helper.t_tab_varchar('t')); + g_test_actual := anydata.convertCollection(ut3_tester_helper.t_tab_varchar(' ')); + + --Act + ut3_develop.ut.expect( g_test_actual ).not_to_equal( g_test_expected ).unordered(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + + end; + + procedure failure_nesting_objects is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_nested_object(ut3_tester_helper.test_dummy_object(1, 'A', '0'),ut3_tester_helper.test_dummy_object(1, 'B', '0') )); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_nested_object(ut3_tester_helper.test_dummy_object(1, 'A', '0'),ut3_tester_helper.test_dummy_object(1, 'C', '0') )); + --Act + l_expected_message := q'[%Actual: ut3_tester_helper.test_dummy_nested_object was expected to equal: ut3_tester_helper.test_dummy_nested_object +%Diff: +%Rows: [ 1 differences ] +%Row No. 1 - Actual: 1C0 +%Row No. 1 - Expected: 1B0]'; + ut3_develop.ut.expect(g_test_actual).to_equal(g_test_expected); + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure failure_double_nested_objects is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_double_nested_obj(ut3_tester_helper.test_dummy_nested_object(ut3_tester_helper.test_dummy_object(1, 'A', '0'),ut3_tester_helper.test_dummy_object(1, 'B', '0') ),'Test')); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_double_nested_obj(ut3_tester_helper.test_dummy_nested_object(ut3_tester_helper.test_dummy_object(1, 'A', '0'),ut3_tester_helper.test_dummy_object(1, 'C', '0') ),'Test')); + --Act + l_expected_message := q'[%Actual: ut3_tester_helper.test_dummy_double_nested_obj was expected to equal: ut3_tester_helper.test_dummy_double_nested_obj +%Diff: +%Rows: [ 1 differences ] +%Row No. 1 - Actual: 1A01C0 +%Row No. 1 - Expected: 1A01B0]'; + ut3_develop.ut.expect(g_test_actual).to_equal(g_test_expected); + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure success_nesting_objects is + begin + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_nested_object(ut3_tester_helper.test_dummy_object(1, 'A', '0'),ut3_tester_helper.test_dummy_object(1, 'B', '0') )); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_nested_object(ut3_tester_helper.test_dummy_object(1, 'A', '0'),ut3_tester_helper.test_dummy_object(1, 'B', '0') )); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure success_double_nested_objects is + begin + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_double_nested_obj(ut3_tester_helper.test_dummy_nested_object(ut3_tester_helper.test_dummy_object(1, 'A', '0'),ut3_tester_helper.test_dummy_object(1, 'B', '0') ),'Test')); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_double_nested_obj(ut3_tester_helper.test_dummy_nested_object(ut3_tester_helper.test_dummy_object(1, 'A', '0'),ut3_tester_helper.test_dummy_object(1, 'B', '0') ),'Test')); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure failure_nested_object_list is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + l_actual ut3_tester_helper.test_dummy_object_list; + l_expected ut3_tester_helper.test_dummy_object_list; + begin + --Arrange + select ut3_tester_helper.test_dummy_object( rownum + 1, 'Something '||rownum, rownum) + bulk collect into l_actual + from dual connect by level <=2 + order by rownum desc; + select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) + bulk collect into l_expected + from dual connect by level <=2 + order by rownum desc; + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_nested_object_list(l_actual,'Test')); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_nested_object_list(l_expected,'Test')); + --Act + l_expected_message := q'[%Actual: ut3_tester_helper.test_dummy_nested_object_list was expected to equal: ut3_tester_helper.test_dummy_nested_object_list +%Diff: +%Rows: [ 1 differences ] +%Row No. 1 - Actual: 2Something 221Something 11 +%Row No. 1 - Expected: 3Something 222Something 11]'; + ut3_develop.ut.expect(g_test_actual).to_equal(g_test_expected); + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure success_nested_object_list is + l_actual ut3_tester_helper.test_dummy_object_list; + l_expected ut3_tester_helper.test_dummy_object_list; + begin + --Arrange + select ut3_tester_helper.test_dummy_object( rownum , 'Something '||rownum, rownum) + bulk collect into l_actual + from dual connect by level <=2 + order by rownum desc; + select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) + bulk collect into l_expected + from dual connect by level <=2 + order by rownum desc; + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_nested_object_list(l_actual,'Test')); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_nested_object_list(l_expected,'Test')); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure nested_varray_same_data is + begin + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_nested_tab_varray(ut3_tester_helper.t_varray(1)) ); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_nested_tab_varray(ut3_tester_helper.t_varray(1)) ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure nested_varray_diff_data is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_nested_tab_varray(ut3_tester_helper.t_varray(1)) ); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_nested_tab_varray(ut3_tester_helper.t_varray(2)) ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + l_expected_message := q'[%Actual: ut3_tester_helper.test_nested_tab_varray was expected to equal: ut3_tester_helper.test_nested_tab_varray +%Diff: +%Rows: [ 1 differences ] +%Row No. 1 - Actual: 2 +%Row No. 1 - Expected: 1]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure user_def_type_null_issue_1098 is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + l_actual ut3_tester_helper.test_dummy_dble_nest_lst_obj; + l_expected ut3_tester_helper.test_dummy_dble_nest_lst_obj; + begin + l_actual:= ut3_tester_helper.test_dummy_dble_nest_lst_obj( + 1, 'North America', + ut3_tester_helper.test_dummy_double_nested_list ( + ut3_tester_helper.test_dummy_nested_object_list( + ut3_tester_helper.test_dummy_object_list( + ut3_tester_helper.test_dummy_object(1, '100 Broadway', 02474), + ut3_tester_helper.test_dummy_object(2, '200 Indian School Rd', 85016) + ),'USA' + ), + ut3_tester_helper.test_dummy_nested_object_list( + ut3_tester_helper.test_dummy_object_list(),'USA' + ) + ) + ); + + l_expected := ut3_tester_helper.test_dummy_dble_nest_lst_obj( + 1, + 'North America', + ut3_tester_helper.test_dummy_double_nested_list(ut3_tester_helper.test_dummy_nested_object_list(ut3_tester_helper.test_dummy_object_list( + ut3_tester_helper.test_dummy_object(1, '100 Broadway', 02474), + ut3_tester_helper.test_dummy_object(2, '200 Indian School Rd', 85016) + ), 'USA')) + ); + ut3_develop.ut.expect(anydata.convertObject(l_actual)).to_equal(anydata.convertObject(l_expected)).unordered; + + l_expected_message := q'[%Actual: ut3_tester_helper.test_dummy_dble_nest_lst_obj was expected to equal: ut3_tester_helper.test_dummy_dble_nest_lst_obj +%Diff: +%Rows: [ 2 differences ] +%Extra: 1North America1100 Broadway24742200 Indian School Rd85016USAUSA +%Missing: 1North America1100 Broadway24742200 Indian School Rd85016USA]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + + end; + + procedure complex_nested_object_success is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + l_actual ut3_tester_helper.test_dummy_dble_nest_lst_obj; + l_expected ut3_tester_helper.test_dummy_dble_nest_lst_obj; + begin + l_actual:= ut3_tester_helper.test_dummy_dble_nest_lst_obj( + 1, 'North America', + ut3_tester_helper.test_dummy_double_nested_list ( + ut3_tester_helper.test_dummy_nested_object_list( + ut3_tester_helper.test_dummy_object_list( + ut3_tester_helper.test_dummy_object(1, '100 Broadway', 02474), + ut3_tester_helper.test_dummy_object(2, '200 Indian School Rd', 85016) + ),'USA' + ), + ut3_tester_helper.test_dummy_nested_object_list( + ut3_tester_helper.test_dummy_object_list(),'USA' + ) + ) + ); + + l_expected := ut3_tester_helper.test_dummy_dble_nest_lst_obj( + 1, 'North America', + ut3_tester_helper.test_dummy_double_nested_list ( + ut3_tester_helper.test_dummy_nested_object_list( + ut3_tester_helper.test_dummy_object_list( + ut3_tester_helper.test_dummy_object(1, '100 Broadway', 02474), + ut3_tester_helper.test_dummy_object(2, '200 Indian School Rd', 85016) + ),'USA' + ), + ut3_tester_helper.test_dummy_nested_object_list( + ut3_tester_helper.test_dummy_object_list(),'USA' + ) + ) + ); + ut3_develop.ut.expect(anydata.convertObject(l_actual)).to_equal(anydata.convertObject(l_expected)).unordered; + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + + end; + + $if dbms_db_version.version = 12 and dbms_db_version.release >= 2 or dbms_db_version.version > 12 $then + procedure long_names_object_types is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace type + very_long_type_name_valid_for_oracle_12_so_utPLSQL_should_allow_it_definitely_well_still_not_reached_128_but_wait_we_did_it + is object ( + code number(18) + )]'; + execute immediate q'[ + begin + ut3_develop.ut.expect(anydata.convertObject( + very_long_type_name_valid_for_oracle_12_so_utPLSQL_should_allow_it_definitely_well_still_not_reached_128_but_wait_we_did_it(1) + )).to_equal(anydata.convertObject( + very_long_type_name_valid_for_oracle_12_so_utPLSQL_should_allow_it_definitely_well_still_not_reached_128_but_wait_we_did_it(1) + )); + end;]'; + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + execute immediate 'drop type very_long_type_name_valid_for_oracle_12_so_utPLSQL_should_allow_it_definitely_well_still_not_reached_128_but_wait_we_did_it'; + exception + when others then + execute immediate 'drop type very_long_type_name_valid_for_oracle_12_so_utPLSQL_should_allow_it_definitely_well_still_not_reached_128_but_wait_we_did_it'; + raise; + end; + $end + +end; +/ \ No newline at end of file diff --git a/test/core/expectations/test_expectation_anydata.pks b/test/ut3_user/expectations/test_expectation_anydata.pks similarity index 50% rename from test/core/expectations/test_expectation_anydata.pks rename to test/ut3_user/expectations/test_expectation_anydata.pks index fedec586c..54c246bd3 100644 --- a/test/core/expectations/test_expectation_anydata.pks +++ b/test/ut3_user/expectations/test_expectation_anydata.pks @@ -1,7 +1,7 @@ create or replace package test_expectation_anydata is --%suite(equal on anydata) - --%suitepath(utplsql.core.expectations) + --%suitepath(utplsql.test_user.expectations) --%aftereach procedure cleanup; @@ -57,9 +57,6 @@ create or replace package test_expectation_anydata is --%test(Comma separated list of attributes to exclude is case sensitive) procedure exclude_attributes_as_csv; - --%test(Exclude attributes fails on invalid XPath) - procedure exclude_attrib_xpath_invalid; - --%test(Exclude attributes by XPath is case sensitive) procedure exclude_attributes_xpath; @@ -72,9 +69,6 @@ create or replace package test_expectation_anydata is --%test(Comma separated list of attributes to include is case sensitive) procedure include_attributes_as_csv; - --%test(Include attributes fails on invalid XPath) - procedure include_attrib_xpath_invalid; - --%test(Include attributes by XPath is case sensitive) procedure include_attributes_xpath; @@ -117,5 +111,136 @@ create or replace package test_expectation_anydata is --%test(Reports only first 20 rows of diff and gives a full diff count) procedure data_diff_on_20_rows_only; + --%test(Validate include list on collections of objects) + procedure collection_include_list; + + --%test(Validate exclude list on collections of objects) + procedure collection_exclude_list; + + --%test(Validate include list on collections of objects fail) + procedure collection_include_list_fail; + + --%test(Two ARRAYS with same data) + procedure array_same_data; + + --%test(Two ARRAYS with different data) + procedure array_diff_data; + + --%test(ARRAY is atomically null) + procedure array_is_null; + + --%test(Compare two null ARRAYs) + procedure array_null_equal_array_null; + + --%test(Compare null ARRAY to ARRAY with data) + procedure array_null_equal_array_notnull; + + --%test(Empty ARRAY have count of 0) + procedure empty_array_have_zero_elem; + + --%test(Compare two empty ARRAYs) + procedure array_empty_equal_array_empty; + + --%test(Compare empty ARRAY to ARRAY with data) + procedure arr_empty_equal_arr_notempty; + + --%test(Collection is atomically NULL) + procedure collection_is_null; + + --%test(Collection is empty) + procedure collection_is_empty; + + --%test(Two VARRAYS with same data) + procedure varray_same_data; + + --%test(Two VARRAYS with different data) + procedure varray_diff_data; + + --%test(VARRAY is atomically null) + procedure varray_is_null; + + --%test(Compare two null VARRAYs) + procedure varray_null_equal_varray_null; + + --%test(Compare null VARRAY to VARRAY with data) + procedure varr_null_equal_varr_notnull; + + --%test(Empty VARRAY have count of 0) + procedure empty_varray_have_zero_elem; + + --%test(Compare two empty VARRAYs) + procedure varr_empty_equal_varr_empty; + + --%test(Compare empty VARRAY to VARRAY with data) + procedure varr_empty_equal_varr_notempty; + + --%test( Anydata collection using joinby ) + procedure collection_join_by; + + --%test( Anydata collection using joinby fail) + procedure collection_join_by_fail; + + --%test( Anydata collection unordered ) + procedure collection_unordered; + + --%test( Anydata collection unordered fail ) + procedure collection_unordered_fail; + + --%test( Anydata object using joinby ) + procedure object_join_by; + + --%test( Anydata object unordered ) + procedure object_unordered; + + --%test( Success when anydata collection contains data from another anydata collection) + procedure collection_to_contain; + + --%test( Success when anydata collection not contains data from another anydata collection) + procedure collection_not_to_contain; + + --%test( Success when anydata object contains data from another anydata) + procedure object_to_contain; + + --%test ( Empty Array equal empty array ) + procedure arr_empty_eq_arr_empty_unord; + + --%test ( Empty Array not equal array with space ) + procedure arr_empty_nqua_arr_e_unord; + + --%test ( Reports diff between not equal nested objects ) + procedure failure_nesting_objects; + + --%test ( Reports diff between not equal double nested objects ) + procedure failure_double_nested_objects; + + --%test (Reports success when comparing identical nested object ) + procedure success_nesting_objects; + + --%test ( Reports success when comparing identical double nested object ) + procedure success_double_nested_objects; + + --%test ( Reports diff between two not equal nested object list ) + procedure failure_nested_object_list; + + --%test ( Reports success when comparing identical nested object list ) + procedure success_nested_object_list; + + --%test ( Reports success when comparing identical nested VARRAYS ) + procedure nested_varray_same_data; + + --%test ( Reports diff between two not equal nested VARRAYS ) + procedure nested_varray_diff_data; + + --%test ( Comparision won't fail on user_defined type that is null as per issue 1098 ) + procedure user_def_type_null_issue_1098; + + --%test ( Reports success when comparing complex nested objects ) + procedure complex_nested_object_success; + + $if dbms_db_version.version = 12 and dbms_db_version.release >= 2 or dbms_db_version.version > 12 $then + --%test ( Compares object types with long names - Issue #1235 ) + procedure long_names_object_types; + $end + end; / diff --git a/test/ut3_user/expectations/test_expectations_cursor.pkb b/test/ut3_user/expectations/test_expectations_cursor.pkb new file mode 100644 index 000000000..a4ef4e8f2 --- /dev/null +++ b/test/ut3_user/expectations/test_expectations_cursor.pkb @@ -0,0 +1,2996 @@ +create or replace package body test_expectations_cursor is + + gc_blob blob := to_blob('123'); + gc_clob clob := to_clob('abc'); + gc_date date := sysdate; + gc_ds_int interval day(9) to second(9) := numtodsinterval(1.12345678912, 'day'); + gc_num number := 123456789.1234567890123456789; + gc_ts timestamp(9) := to_timestamp_tz('2017-03-30 00:21:12.123456789 cet','yyyy-mm-dd hh24:mi:ss.ff9 tzr'); + gc_ts_tz timestamp(9) with time zone := to_timestamp_tz('2017-03-30 00:21:12.123456789 cet','yyyy-mm-dd hh24:mi:ss.ff9 tzr'); + gc_ts_ltz timestamp(9) with local time zone := to_timestamp_tz('2017-03-30 00:21:12.123456789 cet','yyyy-mm-dd hh24:mi:ss.ff9 tzr'); + gc_varchar varchar2(4000) := 'a varchar2'; + gc_ym_int interval year(9) to month := numtoyminterval(1.1, 'year'); + + procedure cleanup_expectations is + begin + ut3_tester_helper.main_helper.clear_expectations( ); + end; + + procedure setup_temp_table_test + as + pragma autonomous_transaction; + begin + execute immediate 'create global temporary table gtt_test_table ( + value varchar2(250) + ) on commit delete rows'; + + end; + + procedure cleanup_temp_table_test + as + pragma autonomous_transaction; + begin + execute immediate 'drop table gtt_test_table'; + end; + + procedure with_temp_table + as + pragma autonomous_transaction; + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + -- Arrange + execute immediate 'insert into gtt_test_table ( value ) ' || + 'select ''Test-entry'' from dual union all ' || + 'select ''Other test entry'' from dual'; + open l_expected for + select 'Test-entry' as value from dual union all + select 'Other test entry' as value from dual; + open l_actual for 'select * from gtt_test_table'; + --Act - execute the expectation on cursor opened on GTT + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + --Cleanup + rollback; + end; + + + procedure success_on_same_data + as + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + -- Arrange + ut3_develop.ut.set_nls; + open l_expected for + select 1 as my_num, + 'This is my test string' as my_string, + to_clob('This is an even longer test clob') as my_clob, + to_date('1984-09-05', 'YYYY-MM-DD') as my_date + from dual; + open l_actual for + select 1 as my_num, + 'This is my test string' as my_string, + to_clob('This is an even longer test clob') as my_clob, + to_date('1984-09-05', 'YYYY-MM-DD') as my_date + from dual; + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + ut3_develop.ut.reset_nls; + end; + + procedure success_on_same_data_float + as + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + -- Arrange + ut3_develop.ut.set_nls; + open l_expected for + select cast(3.14 as binary_double) as pi_double, + cast(3.14 as binary_float) as pi_float + from dual; + open l_actual for + select cast(3.14 as binary_double) as pi_double, + cast(3.14 as binary_float) as pi_float + from dual; + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + ut3_develop.ut.reset_nls; + end; + + procedure success_on_empty + as + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + -- Arrange + open l_expected for select * from dual where 1=0; + open l_actual for select * from dual where 1=0; + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure success_on_both_null + as + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure success_to_be_null + as + l_actual sys_refcursor; + begin + --Act + ut3_develop.ut.expect( l_actual ).to_be_null(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure success_not_to_be_not_null + as + l_actual sys_refcursor; + begin + --Act + ut3_develop.ut.expect( l_actual ).not_to_be_not_null(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure success_not_to_be_null + as + l_actual sys_refcursor; + begin + --Arrange + open l_actual for select * from dual; + --Act + ut3_develop.ut.expect( l_actual ).to_be_not_null(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure success_to_be_not_null + as + l_actual sys_refcursor; + begin + --Arrange + open l_actual for select * from dual; + --Act + ut3_develop.ut.expect( l_actual ).to_be_not_null(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure success_is_empty + as + l_actual sys_refcursor; + begin + --Arrange + open l_actual for select * from dual where 0=1; + --Act + ut3_develop.ut.expect( l_actual ).to_be_empty(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure success_is_not_empty + as + l_actual sys_refcursor; + begin + --Arrange + open l_actual for select * from dual; + --Act + ut3_develop.ut.expect( l_actual ).not_to_be_empty(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure failure_is_null + as + l_actual sys_refcursor; + begin + --Arrange + open l_actual for select * from dual; + --Act + ut3_develop.ut.expect( l_actual ).to_be_null(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure failure_is_not_null + as + l_actual sys_refcursor; + begin + --Act + ut3_develop.ut.expect( l_actual ).not_to_be_null(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure failure_is_empty + as + l_actual sys_refcursor; + begin + --Arrange + open l_actual for select * from dual; + --Act + ut3_develop.ut.expect( l_actual ).to_be_empty(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure failure_is_not_empty + as + l_actual sys_refcursor; + begin + --Arrange + open l_actual for select * from dual where 0=1; + --Act + ut3_develop.ut.expect( l_actual ).not_to_be_empty(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure fail_null_vs_empty + as + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + --Arrange + open l_expected for select * from dual where 1=0; + --Act + ut3_develop.ut.expect( l_actual ).not_to_equal( l_expected ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure fail_on_difference + as + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + --Arrange + open l_expected for select to_clob('This is an even longer test clob') as my_clob from dual; + open l_actual for select to_clob('Another totally different story') as my_clob from dual; + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure fail_on_expected_missing + as + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + --Arrange + open l_expected for select 1 as my_num from dual; + open l_actual for select 1 as my_num from dual union all select 1 as my_num from dual; + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure fail_on_actual_missing + as + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + --Arrange + open l_expected for select 1 as my_num from dual union all select 1 as my_num from dual; + open l_actual for select 1 as my_num from dual; + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure fail_on_different_column_name + as + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + --Arrange + open l_expected for select 1 as col_1 from dual; + open l_actual for select 1 as col_2 from dual; + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + + procedure fail_on_different_column_order + as + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + --Arrange + open l_expected for select 1 as col_1, 2 as col_2 from dual; + open l_actual for select 2 as col_2, 1 as col_1 from dual; + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure pass_on_different_column_order + as + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + --Arrange + open l_expected for select 1 as col_1, 2 as col_2 from dual; + open l_actual for select 2 as col_2, 1 as col_1 from dual; + --Act + ut3_develop.ut.expect( l_actual ).to_( ut3_develop.equal( l_expected ).unordered_columns() ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure pass_on_diff_column_ord_uc + as + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + --Arrange + open l_expected for select 1 as col_1, 2 as col_2 from dual; + open l_actual for select 2 as col_2, 1 as col_1 from dual; + --Act + ut3_develop.ut.expect( l_actual ).to_( ut3_develop.equal( l_expected ).uc() ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure fail_on_multi_diff_col_order + as + l_expected sys_refcursor; + l_actual sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_expected for select 1 as col_1, 2 as col_2,3 as col_3, 4 as col_4,5 col_5 from dual; + open l_actual for select 2 as col_2, 1 as col_1,40 as col_4, 5 as col_5, 30 col_3 from dual; + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ).unordered_columns; + --Assert + l_expected_message := q'[Actual: refcursor [ count = 1 ] was expected to equal: refcursor [ count = 1 ] +%Diff: +%Rows: [ 1 differences ] +%Row No. 1 - Actual: 3040 +%Row No. 1 - Expected: 34]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure fail_on_multi_diff_col_ord_uc + as + l_expected sys_refcursor; + l_actual sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_expected for select 1 as col_1, 2 as col_2,3 as col_3, 4 as col_4,5 col_5 from dual; + open l_actual for select 2 as col_2, 1 as col_1,40 as col_4, 5 as col_5, 30 col_3 from dual; + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ).uc; + --Assert + l_expected_message := q'[Actual: refcursor [ count = 1 ] was expected to equal: refcursor [ count = 1 ] +%Diff: +%Rows: [ 1 differences ] +%Row No. 1 - Actual: 3040 +%Row No. 1 - Expected: 34]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure fail_on_different_row_order + as + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + --Arrange + open l_expected for select 1 as my_num from dual union all select 2 as my_num from dual; + open l_actual for select 2 as my_num from dual union all select 1 as my_num from dual; + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure include_time_in_date_with_nls + as + l_expected sys_refcursor; + l_actual sys_refcursor; + c_second constant number := 1/24/60/60; + begin + --Arrange + ut3_develop.ut.set_nls; + open l_actual for select gc_date as some_date from dual; + open l_expected for select gc_date - c_second some_date from dual; + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + ut3_develop.ut.reset_nls; + end; + + procedure uses_default_nls_for_date + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select gc_date as some_date from dual; + open l_expected for select to_date(to_char(gc_date)) as some_date from dual; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure exclude_columns_as_list + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; + open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected, a_exclude=>ut3_develop.ut_varchar2_list('A_COLUMN','Some_Col')); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure exclude_columns_as_csv + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; + open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected, a_exclude=>'A_COLUMN,Some_Col'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure exclude_columns_as_mixed_list is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; + open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected, a_exclude=>ut3_develop.ut_varchar2_list('A_COLUMN','/ROW/Some_Col')); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure exclude_columns_as_mix_csv_lst is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; + open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected, a_exclude=>'A_COLUMN,/ROW/Some_Col'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure exclude_columns_xpath_invalid + as + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; + open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected, a_exclude=>'/ROW/A_COLUMN,\\//Some_Col'); + --Assert + l_expected_message := q'[Actual: refcursor [ count = 3 ] was expected to equal: refcursor [ count = 3 ] +%Diff: +%Rows: [ 3 differences ] +%Row No. 1 - Actual: d +%Row No. 1 - Expected: c +%Row No. 2 - Actual: d +%Row No. 2 - Expected: c +%Row No. 3 - Actual: d +%Row No. 3 - Expected: c]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure exclude_columns_xpath + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual; + open l_expected for select 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected, a_exclude=>'/ROW/A_COLUMN|/ROW/Some_Col'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure exclude_ignores_invalid_column + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'c' as A_COLUMN from dual a connect by level < 4; + open l_expected for select rownum as rn, 'd' as A_COLUMN from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected, a_exclude=>ut3_develop.ut_varchar2_list('A_COLUMN','non_existing_column')); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure include_columns_as_list + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; + open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).include(ut3_develop.ut_varchar2_list('RN','//A_Column','SOME_COL')); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure include_columns_as_csv + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; + open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).include('RN,//A_Column, SOME_COL'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure include_columns_xpath + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual connect by level < 4; + open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_( ut3_develop.equal(l_expected).include('/ROW/RN|//A_Column|//SOME_COL') ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure include_ignores_invalid_column + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'c' as A_COLUMN from dual a connect by level < 4; + open l_expected for select rownum as rn, 'd' as A_COLUMN from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).include(ut3_develop.ut_varchar2_list(' RN ',' non_existing_column ')); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure include_exclude_col_csv_xpath + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual connect by level < 4; + open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).exclude('Some_Col').include('/ROW/RN|//Some_Col'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure include_exclude_columns_list + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual connect by level < 4; + open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).exclude(ut3_develop.ut_varchar2_list('A_COLUMN')).include(ut3_develop.ut_varchar2_list('RN','A_Column','A_COLUMN')); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure data_diff_on_rows_mismatch + as + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_actual for select 1 rn from dual union all select 6 rn from dual; + open l_expected for select rownum rn from dual connect by level <=3; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected); + + l_expected_message := q'[Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 3 ] +Diff: +Rows: [ 2 differences ] + Row No. 2 - Actual: 6 + Row No. 2 - Expected: 2 + Row No. 3 - Missing: 3]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure char_and_varchar2_col_is_equal is + l_expected sys_refcursor; + l_actual sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_actual for select cast('a' as char(1)) a_column, 1 as id from dual; + open l_expected for select cast('a' as varchar2(10)) a_column from dual; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected); + l_expected_message := q'[Actual: refcursor [ count = 1 ] was expected to equal: refcursor [ count = 1 ] +Diff: +Columns: + Column [position: 2, data-type: NUMBER] is not expected in results. +Rows: [ 1 differences ] + All rows are different as the columns are not matching.]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure column_diff_on_data_type_diff is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_actual for select to_char(rownum) rn, rownum another_rn from dual connect by level <=2; + open l_expected for select rownum rn, rownum another_rn from dual connect by level <=2; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected); + + l_expected_message := q'[Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ] +Diff: +Columns: + Column data-type is invalid. Expected: NUMBER, actual: VARCHAR2. +Rows: [ all different ] + All rows are different as the columns position is not matching.]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure column_diff_on_col_name_diff is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_actual for select rownum rn, rownum bad_column_name from dual connect by level <=2; + open l_expected for select rownum rn, rownum expected_column_name from dual connect by level <=2; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected); + + l_expected_message := q'[Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ] +Diff: +Columns:% + Column [data-type: NUMBER] is missing. Expected column position: 2.% + Column [position: 2, data-type: NUMBER] is not expected in results.%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure column_diff_on_col_position is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_actual for select rownum+1 col_1, rownum+2 col_2, rownum+3 col_3, rownum+4 col_4 from dual connect by level <=2; + open l_expected for select rownum+1 col_1, rownum+4 col_4, rownum+2 col_2, rownum+3 col_3 from dual connect by level <=2; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected); + + l_expected_message := q'[Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ] +Diff: +Columns: + Column is misplaced. Expected position: 2, actual position: 4. + Column is misplaced. Expected position: 3, actual position: 2. + Column is misplaced. Expected position: 4, actual position: 3. +Rows: [ all different ] + All rows are different as the columns position is not matching.]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure column_diff_on_col_pos_unord is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_actual for select rownum+1 col_1, rownum+2 col_2, rownum+3 col_3, rownum+4 col_4 from dual connect by level <=2; + open l_expected for select rownum+1 col_1, rownum+4 col_4, rownum+2 col_2, rownum+3 col_3 from dual connect by level <=2; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).unordered_columns; + + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + --%test(Reports only mismatched columns on column data mismatch) + procedure data_diff_on_col_data_mismatch is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_actual for select rownum good_col, -rownum bad_col from dual connect by level <=2; + open l_expected for select rownum good_col, rownum bad_col from dual connect by level <=2; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected); + + l_expected_message := q'[Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ] +Diff: +Rows: [ 2 differences ] + Row No. 1 - Actual: -1 + Row No. 1 - Expected: 1 + Row No. 2 - Actual: -2 + Row No. 2 - Expected: 2]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure data_diff_on_20_rows_only is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_actual for + select rownum + * case when mod(rownum,2) = 0 then -1 else 1 end bad_col, + rownum good_col + from dual connect by level <=100; + open l_expected for select rownum bad_col, rownum good_col from dual connect by level <=110; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected); + + l_expected_message := q'[Actual: refcursor [ count = 100 ] was expected to equal: refcursor [ count = 110 ] +Diff: +Rows: [ 60 differences, showing first 20 ] + Row No. 2 - Actual: -2 + Row No. 2 - Expected: 2 + Row No. 4 - Actual: -4 + Row No. 4 - Expected: 4 + Row No. 6 - Actual: -6 + Row No. 6 - Expected: 6 + Row No. 8 - Actual: -8 + Row No. 8 - Expected: 8 + % + Row No. 38 - Actual: -38 + Row No. 38 - Expected: 38 + Row No. 40 - Actual: -40 + Row No. 40 - Expected: 40]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure column_and_data_diff is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_expected for + select 1 as ID, 'JACK' as FIRST_NAME, 'SPARROW' AS LAST_NAME, 10000 AS SALARY from dual union all + select 2 as ID, 'LUKE' as FIRST_NAME, 'SKYWALKER' AS LAST_NAME, 1000 AS SALARY from dual union all + select 3 as ID, 'TONY' as FIRST_NAME, 'STARK' AS LAST_NAME, 100000 AS SALARY from dual; + open l_actual for + select 'M' AS GENDER, 'JACK' as FIRST_NAME, 'SPARROW' AS LAST_NAME, 1 as ID, '25000' AS SALARY from dual union all + select 'M' AS GENDER, 'TONY' as FIRST_NAME, 'STARK' AS LAST_NAME, 3 as ID, '100000' AS SALARY from dual union all + select 'F' AS GENDER, 'JESSICA' as FIRST_NAME, 'JONES' AS LAST_NAME, 4 as ID, '2345' AS SALARY from dual union all + select 'M' AS GENDER, 'LUKE' as FIRST_NAME, 'SKYWALKER' AS LAST_NAME, 2 as ID, '1000' AS SALARY from dual; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected); + l_expected_message := q'[Actual: refcursor [ count = 4 ] was expected to equal: refcursor [ count = 3 ] +Diff: +Columns: + Column is misplaced. Expected position: 1, actual position: 4. + Column data-type is invalid. Expected: NUMBER, actual: VARCHAR2. + Column [position: 1, data-type: CHAR] is not expected in results. +Rows: [ 4 differences ] + Row No. 1 - Actual: 25000 + Row No. 1 - Expected: 10000 + Row No. 2 - Actual: 3TONYSTARK100000 + Row No. 2 - Expected: 2LUKESKYWALKER1000 + Row No. 3 - Actual: 4JESSICAJONES2345 + Row No. 3 - Expected: 3TONYSTARK100000 + Row No. 4 - Extra: MLUKESKYWALKER21000]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure col_and_data_diff_not_ordered is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_expected for + select 1 as ID, 'JACK' as FIRST_NAME, 'SPARROW' AS LAST_NAME, 10000 AS SALARY from dual union all + select 2 as ID, 'LUKE' as FIRST_NAME, 'SKYWALKER' AS LAST_NAME, 1000 AS SALARY from dual union all + select 3 as ID, 'TONY' as FIRST_NAME, 'STARK' AS LAST_NAME, 100000 AS SALARY from dual; + open l_actual for + select 'M' AS GENDER, 'JACK' as FIRST_NAME, 'SPARROW' AS LAST_NAME, 1 as ID, '25000' AS SALARY from dual union all + select 'M' AS GENDER, 'TONY' as FIRST_NAME, 'STARK' AS LAST_NAME, 3 as ID, '100000' AS SALARY from dual union all + select 'F' AS GENDER, 'JESSICA' as FIRST_NAME, 'JONES' AS LAST_NAME, 4 as ID, '2345' AS SALARY from dual union all + select 'M' AS GENDER, 'LUKE' as FIRST_NAME, 'SKYWALKER' AS LAST_NAME, 2 as ID, '1000' AS SALARY from dual; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).unordered_columns; + l_expected_message := q'[Actual: refcursor [ count = 4 ] was expected to equal: refcursor [ count = 3 ] +Diff: +Columns: + Column data-type is invalid. Expected: NUMBER, actual: VARCHAR2. + Column [position: 1, data-type: CHAR] is not expected in results. +Rows: [ 4 differences ] + Row No. 1 - Actual: 25000 + Row No. 1 - Expected: 10000 + Row No. 2 - Actual: 3TONYSTARK100000 + Row No. 2 - Expected: 2LUKESKYWALKER1000 + Row No. 3 - Actual: 4JESSICAJONES2345 + Row No. 3 - Expected: 3TONYSTARK100000 + Row No. 4 - Extra: MLUKESKYWALKER21000]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure prepare_table + as + pragma autonomous_transaction; + begin + execute immediate + 'create table test_table_for_cursors ( + some_blob blob, + some_clob clob, + some_date date, + some_ds_interval interval day(9) to second(9), + some_nummber number, + some_timestamp timestamp(9), + some_timestamp_tz timestamp(9) with time zone, + some_timestamp_ltz timestamp(9) with local time zone, + some_varchar2 varchar2(4000), + some_ym_interval interval year(9) to month + )'; + execute immediate q'[ + insert into test_table_for_cursors + values( :gc_blob, :gc_clob, :gc_date, :gc_ds_int, :gc_num, :gc_ts, :gc_ts_tz, :gc_ts_ltz, :gc_varchar, :gc_ym_int + ) +]' using gc_blob, gc_clob, gc_date, gc_ds_int, gc_num, gc_ts, gc_ts_tz, gc_ts_ltz, gc_varchar, gc_ym_int; + commit; + end; + + procedure cleanup_table + as + pragma autonomous_transaction; + begin + execute immediate 'drop table test_table_for_cursors'; + end; + + procedure compares_sql_and_plsql_types is + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + --Arrange + open l_expected for + select gc_blob some_blob, + gc_clob some_clob, + gc_date some_date, + gc_ds_int some_ds_interval, + gc_num some_nummber, + gc_ts some_timestamp, + gc_ts_tz some_timestamp_tz, + gc_ts_ltz some_timestamp_ltz , + gc_varchar some_varchar2, + gc_ym_int some_ym_interval + from dual; + open l_actual for q'[select * from test_table_for_cursors]'; + --Act + ut3_develop.ut.expect(l_expected).to_equal(l_actual); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure closes_cursor_after_use + as + l_actual sys_refcursor; + begin + --Arrange + open l_actual for select 1 as value from dual; + --Act + ut3_develop.ut.expect(l_actual).to_be_empty(); + --Assert + ut.expect(l_actual%isopen).to_be_false(); + end; + + procedure closes_cursor_after_use_on_err + as + l_actual sys_refcursor; + begin + --Arrange + open l_actual for select 1/0 as value from dual; + --Act + begin + ut3_develop.ut.expect(l_actual).to_be_empty(); + exception + when others then + null; + end; + --Assert + ut.expect(l_actual%isopen).to_be_false(); + end; + + procedure reports_on_exception_in_cursor + as + l_actual sys_refcursor; + begin + --Act + open l_actual for select 1/0 as error_column from dual connect by level < 10; + ut3_develop.ut.expect(l_actual).to_be_empty(); + + ut.fail('Expected exception on cursor fetch'); + exception + when others then + ut.expect(sqlerrm).to_be_like('%ORA-20218: SQL exception thrown when fetching data from cursor:% +%ORA-01476: divisor is equal to zero%Check the query and data for errors%'); + end; + + procedure exception_when_closed_cursor + is + l_actual sys_refcursor; + l_error_code constant integer := -20155; + begin + --Arrange + open l_actual for select * from dual; + close l_actual; + --Act + ut3_develop.ut.expect( l_actual ).not_to_be_null; + exception + when others then + --Assert + ut.expect(sqlcode).to_equal(l_error_code); + end; + + procedure compares_over_1000_rows + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum object_name from dual connect by level <=1100; + open l_expected for select rownum object_name from dual connect by level <=1100; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected); + + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + function get_cursor return sys_refcursor is + l_cursor sys_refcursor; + begin + open l_cursor for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; + return l_cursor; + end; + + procedure deprec_to_equal_excl_varch is + begin + --Act + ut3_develop.ut.expect(get_cursor()).to_equal(get_cursor(), a_exclude => 'A_COLUMN,Some_Col'); + --Assert + ut.expect(cardinality(ut3_tester_helper.main_helper.get_warnings())).to_equal(1); + ut.expect(ut3_tester_helper.main_helper.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); + end; + + procedure deprec_to_equal_excl_list is + begin + --Act + ut3_develop.ut.expect(get_cursor()).to_equal(get_cursor(), a_exclude => ut3_develop.ut_varchar2_list('A_COLUMN','Some_Col')); + --Assert + ut.expect(cardinality(ut3_tester_helper.main_helper.get_warnings())).to_equal(1); + ut.expect(ut3_tester_helper.main_helper.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); + end; + + procedure deprec_not_to_equal_excl_varch is + begin + --Act + ut3_develop.ut.expect(get_cursor()).not_to_equal(get_cursor(), a_exclude => 'A_COLUMN,Some_Col'); + --Assert + ut.expect(cardinality(ut3_tester_helper.main_helper.get_warnings())).to_equal(1); + ut.expect(ut3_tester_helper.main_helper.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); + end; + + procedure deprec_not_to_equal_excl_list is + begin + --Act + ut3_develop.ut.expect(get_cursor()).not_to_equal(get_cursor(), a_exclude => ut3_develop.ut_varchar2_list('A_COLUMN','Some_Col')); + --Assert + ut.expect(cardinality(ut3_tester_helper.main_helper.get_warnings())).to_equal(1); + ut.expect(ut3_tester_helper.main_helper.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); + end; + + procedure deprec_equal_excl_varch is + begin + --Act + ut3_develop.ut.expect(get_cursor()).to_(ut3_develop.equal(get_cursor(), a_exclude => 'A_COLUMN,Some_Col')); + --Assert + ut.expect(cardinality(ut3_tester_helper.main_helper.get_warnings())).to_equal(1); + ut.expect(ut3_tester_helper.main_helper.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); + end; + + procedure deprec_equal_excl_list is + begin + --Act + ut3_develop.ut.expect(get_cursor()).to_(ut3_develop.equal(get_cursor(), a_exclude => ut3_develop.ut_varchar2_list('A_COLUMN','Some_Col'))); + --Assert + ut.expect(cardinality(ut3_tester_helper.main_helper.get_warnings())).to_equal(1); + ut.expect(ut3_tester_helper.main_helper.get_warnings()(1)).to_be_like('The syntax: "%" is deprecated.%'); + end; + + procedure col_diff_on_col_name_implicit is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_actual for select '1' , '2' from dual connect by level <=2; + open l_expected for select rownum , rownum expected_column_name from dual connect by level <=2; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected); + + l_expected_message := q'[%Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ] +%Diff: +%Columns: +%Column [data-type: NUMBER] is missing. Expected column position: 1. +%Column [data-type: NUMBER] is missing. Expected column position: 2. +%Column <1> [position: 1, data-type: CHAR] is not expected in results. +%Column <2> [position: 2, data-type: CHAR] is not expected in results. +%Rows: [ all different ] +%All rows are different as the columns position is not matching.]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure col_mtch_on_col_name_implicit is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_actual for select '1' , rownum from dual connect by level <=2; + open l_expected for select '1' , rownum from dual connect by level <=2; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure cursor_unorderd_compr_success is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select username , user_id from all_users order by username asc; + open l_expected for select username , user_id from all_users order by username desc; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).unordered; + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure cursor_unord_compr_success_uc is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select user_id, username from all_users order by username asc; + open l_expected for select username , user_id from all_users order by username desc; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).unordered().uc(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure cursor_unordered_compare_fail is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_actual for select 'test1' username,-100 user_id from dual + union all + select 'test' username,-666 user_id from dual + order by 1 asc; + + open l_expected for select 'test1' username,-100 user_id from dual + union all + select 'test' username,-667 user_id from dual + order by 1 desc; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).unordered; + l_expected_message := q'[%Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ]% +%Diff:% +%Rows: [ 2 differences ]% +%Extra: test-666% +%Missing: test-667%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure cursor_joinby_compare_uc is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select owner, object_id, object_name,object_type from all_objects where owner = user; + open l_expected for select object_id, owner, object_name,object_type from all_objects where owner = user; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by('OBJECT_ID').uc(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure cursor_joinby_compare is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select object_id, owner, object_name,object_type from all_objects where owner = user; + open l_expected for select object_id, owner, object_name,object_type from all_objects where owner = user; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by('OBJECT_ID'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure cursor_joinby_col_not_ord + as + l_expected sys_refcursor; + l_actual sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_expected for select 1 as col_1, 2 as col_2,3 as col_3, 4 as col_4,5 col_5 from dual; + open l_actual for select 2 as col_2, 1 as col_1,40 as col_4, 5 as col_5, 30 col_3 from dual; + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ).join_by('COL_1').unordered_columns; + --Assert + l_expected_message := q'[Actual: refcursor [ count = 1 ] was expected to equal: refcursor [ count = 1 ] +%Diff: +%Rows: [ 1 differences ] +%PK 1 - Actual: 3040 +%PK 1 - Expected: 34]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure cursor_joinby_compare_twocols is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select object_id, owner, object_name,object_type from all_objects where owner = user; + open l_expected for select object_id, owner, object_name,object_type from all_objects where owner = user; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by(ut3_develop.ut_varchar2_list('OBJECT_ID,OBJECT_NAME')); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure cursor_joinby_compare_nokey is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_actual for select rownum as rn, 'x' SOME_COL from dual a connect by level < 4; + open l_expected for select rownum as rn, 'x' SOME_COL from dual a connect by level < 4; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by('OWNER'); + --Assert + l_expected_message := q'[%Actual: refcursor [ count = 3 ] was expected to equal: refcursor [ count = 3 ]% +Diff:% +%Unable to join sets:% +%Join key OWNER does not exists in expected% +%Join key OWNER does not exists in actual%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure cur_joinby_comp_twocols_nokey is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_actual for select rownum as rn, 'x' SOME_COL from dual a connect by level < 4; + open l_expected for select rownum as rn, 'x' SOME_COL from dual a connect by level < 4; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by(ut3_develop.ut_varchar2_list('OWNER,USER_ID')); + --Assert + l_expected_message := q'[%Actual: refcursor [ count = 3 ] was expected to equal: refcursor [ count = 3 ]% +Diff:% +%Unable to join sets:% +%Join key OWNER does not exists in expected% +%Join key USER_ID does not exists in expected% +%Join key OWNER does not exists in actual% +%Join key USER_ID does not exists in actual%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure cursor_joinby_compare_exkey is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_actual for select rownum as rn, 'x' SOME_COL from dual a connect by level < 4; + open l_expected for select rownum as rn, 'x' SOME_COL from dual a connect by level < 4; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by('SOME_COL').exclude('SOME_COL'); + --Assert + l_expected_message := q'[%Actual: refcursor [ count = 3 ] was expected to equal: refcursor [ count = 3 ]% +Diff:% +%Unable to join sets:% +%Join key SOME_COL does not exists in expected% +%Join key SOME_COL does not exists in actual%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure cur_joinby_comp_twocols_exkey is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_actual for select rownum as rn, 'x' SOME_COL from dual a connect by level < 4; + open l_expected for select rownum as rn, 'x' SOME_COL from dual a connect by level < 4; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by(ut3_develop.ut_varchar2_list('RN,SOME_COL')).exclude('RN'); + --Assert + l_expected_message := q'[%Actual: refcursor [ count = 3 ] was expected to equal: refcursor [ count = 3 ]% +Diff:% +%Unable to join sets:% +%Join key RN does not exists in expected% +%Join key RN does not exists in actual%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure cursor_joinby_comp_nokey_ex is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_actual for select rownum as rni, 'x' SOME_COL from dual a connect by level < 4; + open l_expected for select rownum as rn, 'x' SOME_COL from dual a connect by level < 4; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by('RNI'); + --Assert + l_expected_message := q'[%Actual: refcursor [ count = 3 ] was expected to equal: refcursor [ count = 3 ]% +Diff:% +%Unable to join sets:% +%Join key RNI does not exists in expected%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure cursor_joinby_comp_nokey_ac is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_actual for select rownum as rn, 'x' SOME_COL from dual a connect by level < 4; + open l_expected for select rownum as rni, 'x' SOME_COL from dual a connect by level < 4; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by('RNI'); + --Assert + l_expected_message := q'[%Actual: refcursor [ count = 3 ] was expected to equal: refcursor [ count = 3 ]% +Diff:% +%Unable to join sets:% +%Join key RNI does not exists in actual%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure cursor_joinby_compare_1000 is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select level object_id, level || '_TEST' object_name from dual connect by level <=1100; + open l_expected for select level object_id, level || '_TEST' object_name from dual connect by level <=1100; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by('OBJECT_ID'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure cursor_unorder_compare_1000 is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select level object_id, level || '_TEST' object_name from dual connect by level <=1100; + open l_expected for select level object_id, level || '_TEST' object_name from dual connect by level <=1100; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).unordered; + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure cursor_joinby_compare_fail is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_expected for select username, user_id from all_users union all + select 'TEST' username, -600 user_id from dual order by 1 desc; + + open l_actual for select username, user_id from all_users union all + select 'TEST' username, -610 user_id from dual order by 1 asc; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by('USERNAME'); + --Assert + l_expected_message := q'[%Actual: refcursor [ count = % ] was expected to equal: refcursor [ count = % ] +%Diff:% +%Rows: [ 1 differences ]% +%PK TEST - Actual:%-610% +%PK TEST - Expected:%-600%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure cursor_joinby_cmp_twocol_fail is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_expected for select username, user_id from all_users union all + select 'TEST' username, -600 user_id from dual order by 1 desc; + + open l_actual for select username, user_id from all_users union all + select 'TEST' username, -610 user_id from dual order by 1 asc; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by(ut3_develop.ut_varchar2_list('USERNAME,USER_ID')); + --Assert + l_expected_message := q'[%Actual: refcursor [ count = % ] was expected to equal: refcursor [ count = % ] +%Diff:% +%Rows: [ 2 differences ]% +%PK TEST-610 - Extra: TEST-610% +%PK TEST-600 - Missing: TEST-600%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure cur_joinby_cmp_threcol_fail is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_expected for select username, user_id,'Y' is_valid from all_users union all + select 'TEST' username, -600 user_id,'Y' is_valid from dual order by 1 desc; + + open l_actual for select username, user_id,'Y' is_valid from all_users union all + select 'TEST' username, -610 user_id,'Y' is_valid from dual order by 1 asc; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by(ut3_develop.ut_varchar2_list('USERNAME,IS_VALID')); + --Assert + l_expected_message := q'[%Actual: refcursor [ count = % ] was expected to equal: refcursor [ count = % ] +%Diff:% +%Rows: [ 1 differences ]% +%PK TESTY - Actual:%-610% +%PK TESTY - Expected:%-600%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure unord_incl_cols_as_list + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; + open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).include(ut3_develop.ut_varchar2_list('RN','//A_Column','SOME_COL')).unordered; + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure joinby_incl_cols_as_list + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; + open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).include(ut3_develop.ut_varchar2_list('RN','//A_Column','SOME_COL')).join_by('RN'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure joinby_excl_cols_as_list + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; + open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).exclude(ut3_develop.ut_varchar2_list('//Some_Col','A_COLUMN')).join_by('RN'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure unord_excl_cols_as_list + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 4; + open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).exclude(ut3_develop.ut_varchar2_list('A_COLUMN|//Some_Col')).unordered; + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure excl_dif_cols_as_list + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'TEST' as A_COLUMN from dual a connect by level < 4; + open l_expected for select rownum as rn, 1 as A_COLUMN from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).exclude(ut3_develop.ut_varchar2_list('A_COLUMN')); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure inlc_dif_cols_as_list + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'TEST' as A_COLUMN from dual a connect by level < 4; + open l_expected for select rownum as rn, 1 as A_COLUMN from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).include(ut3_develop.ut_varchar2_list('RN')); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure inlc_exc_dif_cols_as_list + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'TEST' as A_COLUMN from dual a connect by level < 4; + open l_expected for select rownum as rn, 1 as A_COLUMN from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).include(ut3_develop.ut_varchar2_list('RN')).exclude(ut3_develop.ut_varchar2_list('A_COLUMN')); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure compare_obj_typ_col_un is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) as colval + from dual connect by level <=2 order by rownum asc; + + open l_expected for select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) as colval + from dual connect by level <=2 order by rownum desc; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).unordered; + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure compare_obj_typ_col_jb is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) as colval + from dual connect by level <=2 order by rownum asc; + + open l_expected for select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) as colval + from dual connect by level <=2 order by rownum desc; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by('COLVAL/ID'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure comp_obj_typ_col_un_fail is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + --Arrange + open l_actual for select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) as colval + from dual connect by level <=2 order by rownum asc; + + open l_expected for select ut3_tester_helper.test_dummy_object( rownum, 'Somethings '||rownum, rownum) as colval + from dual connect by level <=3 order by rownum desc; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).unordered; + l_expected_message := q'[%Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 3 ]% +Diff:% +Rows: [ 5 differences% +%Extra: 1Something 11% +%Extra: 2Something 22% +%Missing: 3Somethings 33% +%Missing: 2Somethings 22% +%Missing: 1Somethings 11%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure comp_obj_typ_col_jb_fail is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) as colval + from dual connect by level <=2 order by rownum asc; + + open l_expected for select ut3_tester_helper.test_dummy_object( rownum, 'Somethings '||rownum, rownum) as colval + from dual connect by level <=2 order by rownum desc; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by('COLVAL/ID'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure comp_obj_typ_col_jb_multi is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn,ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) as colval + from dual connect by level <=2 order by rownum asc; + + open l_expected for select rownum as rn,ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) as colval + from dual connect by level <=2 order by rownum desc; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by(ut3_develop.ut_varchar2_list('RN,COLVAL/ID')); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure comp_obj_typ_col_jb_nokey is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + --Arrange + open l_actual for select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) as colval + from dual connect by level <=2 order by rownum asc; + + open l_expected for select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) as colval + from dual connect by level <=2 order by rownum desc; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by('COLVAL/IDS'); + + l_expected_message := q'[%Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ]% +Diff:% +%Unable to join sets:% +%Join key COLVAL/IDS does not exists in expected% +%Join key COLVAL/IDS does not exists in actual%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure compare_nest_tab_col_jb is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_tab ut3_develop.ut_key_value_pairs := ut3_develop.ut_key_value_pairs(); + l_expected_tab ut3_develop.ut_key_value_pairs := ut3_develop.ut_key_value_pairs(); + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + select ut3_develop.ut_key_value_pair(rownum,'Something '||rownum) + bulk collect into l_actual_tab + from dual connect by level <=2; + + select ut3_develop.ut_key_value_pair(rownum,'Something '||rownum) + bulk collect into l_expected_tab + from dual connect by level <=2; + + --Arrange + open l_actual for select key,value + from table(l_actual_tab) order by 1 asc; + + open l_expected for select key,value + from table(l_expected_tab) order by 1 desc; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by('KEY'); + + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure compare_nest_tab_col_jb_fail is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_tab ut3_develop.ut_key_value_pairs := ut3_develop.ut_key_value_pairs(); + l_expected_tab ut3_develop.ut_key_value_pairs := ut3_develop.ut_key_value_pairs(); + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + select ut3_develop.ut_key_value_pair(rownum,'Something '||rownum) + bulk collect into l_actual_tab + from dual connect by level <=2; + + select ut3_develop.ut_key_value_pair(rownum,'Somethings '||rownum) + bulk collect into l_expected_tab + from dual connect by level <=2; + + --Arrange + open l_actual for select key,value + from table(l_actual_tab) order by 1 asc; + + open l_expected for select key,value + from table(l_expected_tab) order by 1 desc; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by('KEY'); + l_expected_message := q'[%Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ]% +%Diff:% +%Rows: [ 2 differences ]% +%PK % - Actual: %% +%PK % - Expected: %% +%PK % - Actual: %% +%PK % - Expected: %%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure compare_nest_tab_cols_jb is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_tab ut3_develop.ut_key_value_pairs := ut3_develop.ut_key_value_pairs(); + l_expected_tab ut3_develop.ut_key_value_pairs := ut3_develop.ut_key_value_pairs(); + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + select ut3_develop.ut_key_value_pair(rownum,'Something '||rownum) + bulk collect into l_actual_tab + from dual connect by level <=2; + + select ut3_develop.ut_key_value_pair(rownum,'Something '||rownum) + bulk collect into l_expected_tab + from dual connect by level <=2; + + --Arrange + open l_actual for select key,value + from table(l_actual_tab) order by 1 asc; + + open l_expected for select key,value + from table(l_expected_tab) order by 1 desc; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by(ut3_develop.ut_varchar2_list('KEY,VALUE')); + + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure compare_nest_tab_cols_jb_fail is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_tab ut3_develop.ut_key_value_pairs := ut3_develop.ut_key_value_pairs(); + l_expected_tab ut3_develop.ut_key_value_pairs := ut3_develop.ut_key_value_pairs(); + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + select ut3_develop.ut_key_value_pair(rownum,'Something '||rownum) + bulk collect into l_actual_tab + from dual connect by level <=2; + + select ut3_develop.ut_key_value_pair(rownum,'Somethings '||rownum) + bulk collect into l_expected_tab + from dual connect by level <=2; + + --Arrange + open l_actual for select key,value + from table(l_actual_tab) order by 1 asc; + + open l_expected for select key,value + from table(l_expected_tab) order by 1 desc; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by(ut3_develop.ut_varchar2_list('KEY,VALUE')); + l_expected_message := q'[%Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ]% +%Diff:% +%Rows: [ 4 differences ]% +%PK %% - Extra% +%PK %% - Extra% +%PK %% - Missing% +%PK %% - Missing%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure compare_tabtype_as_cols_jb is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_tab ut3_develop.ut_key_value_pairs := ut3_develop.ut_key_value_pairs(); + l_expected_tab ut3_develop.ut_key_value_pairs := ut3_develop.ut_key_value_pairs(); + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + select ut3_develop.ut_key_value_pair(rownum,'Something '||rownum) + bulk collect into l_actual_tab + from dual connect by level <=2; + + select ut3_develop.ut_key_value_pair(rownum,'Somethings '||rownum) + bulk collect into l_expected_tab + from dual connect by level <=2; + + --Arrange + open l_actual for select rownum rn, l_actual_tab as nested_table + from dual connect by level <=2; + + open l_expected for select rownum rn, l_expected_tab as nested_table + from dual connect by level <=2; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by('NESTED_TABLE'); + + --Assert + l_expected_message := q'[%Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ]% +%Diff:% +%Rows: [ 4 differences ]% +%PK %%%%%%%%%%%%%Extra%%% +%PK %%%%%%%%%%%%%Extra%%% +%PK %%%%%%%%%%%%%Missing%%% +%PK %%%%%%%%%%%%%Missing%%%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + + end; + + procedure compare_tabtype_as_cols is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_tab ut3_develop.ut_key_value_pairs := ut3_develop.ut_key_value_pairs(); + l_expected_tab ut3_develop.ut_key_value_pairs := ut3_develop.ut_key_value_pairs(); + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + select ut3_develop.ut_key_value_pair(rownum,'Something '||rownum) + bulk collect into l_actual_tab + from dual connect by level <=2 order by rownum asc; + + select ut3_develop.ut_key_value_pair(rownum,'Something '||rownum) + bulk collect into l_expected_tab + from dual connect by level <=2 order by rownum asc; + + --Arrange + open l_actual for select rownum rn, l_actual_tab as nested_table + from dual connect by level <=2; + + open l_expected for select rownum rn, l_expected_tab as nested_table + from dual connect by level <=2; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + + end; + + procedure compare_tabtype_as_cols_coll is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_tab ut3_develop.ut_key_value_pairs := ut3_develop.ut_key_value_pairs(); + l_expected_tab ut3_develop.ut_key_value_pairs := ut3_develop.ut_key_value_pairs(); + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + select ut3_develop.ut_key_value_pair(rownum,'Apples '||rownum) + bulk collect into l_actual_tab + from dual connect by level <=2; + + select ut3_develop.ut_key_value_pair(rownum,'Peaches '||rownum) + bulk collect into l_expected_tab + from dual connect by level <=2; + + --Arrange + open l_actual for select rownum rn, l_actual_tab as nested_table + from dual connect by level <=2; + + open l_expected for select rownum rn, l_expected_tab as nested_table + from dual connect by level <=2; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by('NESTED_TABLE/UT_KEY_VALUE_PAIRS'); + + --Assert + l_expected_message := q'[%Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ] +%Diff: +%Rows: [ 4 differences ] +%Extra: 11Apples 12Apples 2 +%Extra: 21Apples 12Apples 2 +%Missing: 11Peaches 12Peaches 2 +%Missing: 21Peaches 12Peaches 2%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + + end; + + procedure compare_rec_colltype_as_cols is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_tab some_object; + l_expected_tab some_object; + begin + select some_object( user,'TEST', gc_date, some_items( some_item(1,'test'), some_item(2,'test') ) ) + into l_actual_tab from dual; + + select some_object( user,'TEST', gc_date, some_items( some_item(1,'test'), some_item(2,'test') ) ) + into l_expected_tab from dual; + + --Arrange + open l_actual for select l_actual_tab as nested_table from dual; + + open l_expected for select l_expected_tab as nested_table from dual; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by('NESTED_TABLE'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + + end; + + procedure compare_rec_colltype_as_attr is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_tab some_object; + l_expected_tab some_object; + begin + select some_object( user,'TEST', gc_date, some_items( some_item(1,'test'), some_item(2,'test') ) ) + into l_actual_tab from dual; + + select some_object( user,'TEST', gc_date, some_items( some_item(1,'test'), some_item(2,'test') ) ) + into l_expected_tab from dual; + + --Arrange + open l_actual for select l_actual_tab as nested_table from dual; + + open l_expected for select l_expected_tab as nested_table from dual; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by('NESTED_TABLE/OBJECT_OWNER'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + + end; + + procedure compare_collection_in_rec is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_tab some_object; + l_expected_tab some_object; + begin + select some_object( user,'TEST', gc_date, some_items( some_item(1,'test'), some_item(2,'test') ) ) + into l_actual_tab from dual; + + select some_object( user,'TEST', gc_date, some_items( some_item(1,'test'), some_item(2,'test') ) ) + into l_expected_tab from dual; + + --Arrange + open l_actual for select l_actual_tab as nested_table from dual; + + open l_expected for select l_expected_tab as nested_table from dual; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by('NESTED_TABLE/ITEMS'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + + end; + + procedure compare_rec_coll_as_cols_fl is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_tab some_object; + l_expected_tab some_object; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + select some_object( 'TEST','TEST', gc_date, some_items( some_item(1,'BAD'), some_item(2,'test') ) ) + into l_actual_tab from dual; + + select some_object( 'TEST','TEST', gc_date, some_items( some_item(1,'TEST'), some_item(2,'test') ) ) + into l_expected_tab from dual; + + --Arrange + open l_actual for select rownum rn, l_actual_tab as nested_table + from dual; + + open l_expected for select rownum rn, l_expected_tab as nested_table + from dual; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by('NESTED_TABLE/OBJECT_OWNER'); + + --Assert + l_expected_message := q'[%Actual: refcursor [ count = 1 ] was expected to equal: refcursor [ count = 1 ] +%Diff: +%Rows: [ 1 differences ] +%PK TEST - Actual: TESTTEST%1BAD2test% +%PK TEST - Expected: TESTTEST%1TEST2test%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure compare_rec_coll_as_join is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_actual_tab some_object; + l_expected_tab some_object; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + select some_object( 'TEST','TEST', gc_date, some_items( some_item(1,'BAD'), some_item(2,'test') ) ) + into l_actual_tab from dual; + + select some_object( 'TEST','TEST', gc_date, some_items( some_item(1,'TEST'), some_item(2,'test') ) ) + into l_expected_tab from dual; + + --Arrange + open l_actual for select l_actual_tab as nested_table from dual; + + open l_expected for select l_expected_tab as nested_table from dual; + + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by('NESTED_TABLE/ITEMS/ID'); + + --Assert + l_expected_message := q'[%Actual: refcursor [ count = 1 ] was expected to equal: refcursor [ count = 1 ]% +%Diff:% +%Unable to join sets:% +%Join key NESTED_TABLE/ITEMS/ID does not exists in expected% +%Join key NESTED_TABLE/ITEMS/ID does not exists in actual% +%Please make sure that your join clause is not refferring to collection element%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + + end; + + procedure unordered_fix_764 is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + open l_expected for + select 'Table' as name from dual + union all + select 'Desk' as name from dual + union all + select 'Table' as name from dual; + + open l_actual for + select 'Desk' as name from dual + union all + select 'Table' as name from dual; + + --Assert + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ).unordered(); + + --Assert + l_expected_message := q'[%Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 3 ] +%Diff: +%Rows: [ 1 differences ] +%Missing: Table%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + + end; + + procedure cursor_to_contain is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select owner, object_name,object_type from all_objects where owner = user + order by 1,2,3 asc; + open l_expected for select owner, object_name,object_type from all_objects where owner = user + and rownum < 20; + + --Act + ut3_develop.ut.expect(l_actual).to_contain(l_expected); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure cursor_to_contain_uc is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select owner, object_name, object_type from all_objects where owner = user + order by 1,2,3 asc; + open l_expected for select object_type, owner, object_name from all_objects where owner = user + and rownum < 20; + + --Act + ut3_develop.ut.expect(l_actual).to_contain(l_expected).uc(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure cursor_to_contain_unordered is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for + select rownum owner, rownum||'name' object_name,'PACKAGE' object_type from dual connect by level < 20 + order by 1,2,3 asc; + open l_expected for + select rownum owner, rownum||'name' object_name,'PACKAGE' object_type from dual connect by level < 10; + + --Act + ut3_develop.ut.expect(l_actual).to_contain(l_expected).unordered(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure cursor_to_contain_fail is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + --Arrange + open l_actual for select rownum owner,rownum object_name, 'PACKAGE' object_type from dual connect by level < 5; + open l_expected for select rownum owner,rownum object_name, 'PACKAGE' object_type from dual connect by level < 10; + + --Act + ut3_develop.ut.expect(l_actual).to_contain(l_expected); + --Assert + l_expected_message := q'[%Actual: refcursor [ count = 4 ] was expected to contain: refcursor [ count = 9 ] +%Diff: +%Rows: [ 5 differences ] +%Missing: %%%% +%Missing: %%%% +%Missing: %%%% +%Missing: %%%% +%Missing: %%%%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure cursor_contain_joinby is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select username,user_id from all_users; + open l_expected for select username ,user_id from all_users where rownum < 5; + + --Act + ut3_develop.ut.expect(l_actual).to_contain(l_expected).join_by('USERNAME'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure cursor_contain_joinby_fail is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + --Arrange + open l_actual for select username, user_id from all_users + union all + select 'TEST' username, -600 user_id from dual + order by 1 desc; + open l_expected for select username, user_id from all_users + union all + select 'TEST' username, -601 user_id from dual + order by 1 asc; + + --Act + ut3_develop.ut.expect(l_actual).to_contain(l_expected).join_by('USERNAME'); + --Assert + l_expected_message := q'[%Actual: refcursor [ count = % ] was expected to contain: refcursor [ count = % ] +%Diff: +%Rows: [ 1 differences ] +%PK TEST - Actual: -600 +%PK TEST - Expected: -601%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + + end; + + procedure to_contain_incl_cols_as_list + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 6; + open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_contain(l_expected).include(ut3_develop.ut_varchar2_list('RN','//A_Column','SOME_COL')); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure to_cont_join_incl_cols_as_lst + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 10; + open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_contain(l_expected).include(ut3_develop.ut_varchar2_list('RN','//A_Column','SOME_COL')).join_by('RN'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure contain_join_excl_cols_as_lst + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 10; + open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_contain(l_expected).exclude(ut3_develop.ut_varchar2_list('//Some_Col','A_COLUMN')).join_by('RN'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure contain_excl_cols_as_list + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 10; + open l_expected for select rownum as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).to_contain(l_expected).exclude(ut3_develop.ut_varchar2_list('A_COLUMN|//Some_Col')); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure cursor_not_to_contain + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + open l_expected for select 'TEST' username, -600 user_id from dual; + + open l_actual for select username, user_id from all_users + union all + select 'TEST1' username, -601 user_id from dual; + + --Act + ut3_develop.ut.expect(l_actual).not_to_contain(l_expected); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure cursor_not_to_contain2 + as + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + open l_expected for select 'TEST' username, -600 user_id from dual; + + open l_actual for select username, user_id from all_users + union all + select 'TEST1' username, -601 user_id from dual; + + --Act + ut3_develop.ut.expect(l_actual).not_to(ut3_develop.contain(l_expected)); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure cursor_not_to_contain_fail is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + --Arrange + open l_expected for select 'TEST' username, -600 user_id from dual; + + open l_actual for select username, user_id from all_users + union all + select 'TEST' username, -600 user_id from dual; + + --Act + ut3_develop.ut.expect(l_actual).not_to_contain(l_expected); + --Assert + l_expected_message := q'[%Actual: (refcursor [ count = % ])% +%Data-types:% +%VARCHAR2NUMBER% +%Data:% +%was expected not to contain:(refcursor [ count = 1 ])% +%Data-types:% +%CHARNUMBER% +%Data:% +%TEST-600%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + + procedure cursor_not_to_contain_fail2 is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + --Arrange + open l_expected for select 'TEST' username, -600 user_id from dual; + + open l_actual for select username, user_id from all_users + union all + select 'TEST' username, -600 user_id from dual; + + --Act + ut3_develop.ut.expect(l_actual).not_to(ut3_develop.contain(l_expected)); + --Assert + l_expected_message := q'[%Actual: (refcursor [ count = % ])% +%Data-types:% +%VARCHAR2NUMBER% +%Data:% +%was expected not to contain:(refcursor [ count = 1 ])% +%Data-types:% +%CHARNUMBER% +%Data:% +%TEST-600%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure cursor_not_to_contain_joinby is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select username,rownum * 10 user_id from all_users where rownum < 5; + open l_expected for select username||to_char(rownum) username ,rownum user_id from all_users where rownum < 5; + + --Act + ut3_develop.ut.expect(l_actual).not_to_contain(l_expected).join_by('USER_ID'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure cursor_not_to_contain_joinby2 is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select username,rownum * 10 user_id from all_users where rownum < 5; + open l_expected for select username||to_char(rownum) username ,rownum user_id from all_users where rownum < 5; + + --Act + ut3_develop.ut.expect(l_actual).not_to(ut3_develop.contain(l_expected).join_by('USER_ID')); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure not_cont_join_incl_cols_as_lst is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'b' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 10; + open l_expected for select rownum * 20 rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).not_to_contain(l_expected).include(ut3_develop.ut_varchar2_list('RN','//A_Column','SOME_COL')).join_by('RN'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure not_con_join_incl_cols_as_lst2 is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'b' as "A_Column", 'c' as A_COLUMN, 'x' SOME_COL, 'd' "Some_Col" from dual a connect by level < 10; + open l_expected for select rownum * 20 rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).not_to(ut3_develop.contain(l_expected).include(ut3_develop.ut_varchar2_list('RN','//A_Column','SOME_COL')).join_by('RN')); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure not_cont_join_excl_cols_as_lst is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'y' SOME_COL, 'd' "Some_Col" from dual a connect by level < 10; + open l_expected for select rownum * 20 as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).not_to_contain(l_expected).exclude(ut3_develop.ut_varchar2_list('//Some_Col','A_COLUMN')).join_by('RN'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure not_con_join_excl_cols_as_lst2 is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn, 'a' as "A_Column", 'c' as A_COLUMN, 'y' SOME_COL, 'd' "Some_Col" from dual a connect by level < 10; + open l_expected for select rownum * 20 as rn, 'a' as "A_Column", 'd' as A_COLUMN, 'x' SOME_COL, 'c' "Some_Col" from dual a connect by level < 4; + --Act + ut3_develop.ut.expect(l_actual).not_to(ut3_develop.contain(l_expected).exclude(ut3_develop.ut_varchar2_list('//Some_Col','A_COLUMN')).join_by('RN')); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure to_contain_duplicates is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_actual for select rownum as rn from dual a connect by level < 10 + union all + select rownum as rn from dual a connect by level < 4; + open l_expected for select rownum as rn from dual a connect by level < 4; + + --Act + ut3_develop.ut.expect(l_actual).to_contain(l_expected); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure to_contain_duplicates_fail is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + --Arrange + open l_actual for select rownum as rn from dual a connect by level < 10; + open l_expected for select rownum as rn from dual a connect by level < 4 + union all select rownum as rn from dual a connect by level < 4; + + --Act + ut3_develop.ut.expect(l_actual).to_contain(l_expected); + --Assert + l_expected_message := q'[%Actual: refcursor [ count = 9 ] was expected to contain: refcursor [ count = 6 ] +%Diff: +%Rows: [ 3 differences ] +%Missing: % +%Missing: % +%Missing: %]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure to_not_contain_fails_1245 is + c1 sys_refcursor; + c2 sys_refcursor; + begin + open c1 for select 'a' as letter from dual union all select 'b' from dual; + open c2 for select 'c' as letter from dual; + ut3_develop.ut.expect(c1).not_to(ut3_develop.contain(c2)); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure udt_messg_format_eq is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_expected_tab ut3_develop.ut_key_value_pairs := ut3_develop.ut_key_value_pairs(); + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + select ut3_develop.ut_key_value_pair(rownum,'Something '||rownum) + bulk collect into l_expected_tab + from dual connect by level <=2; + + --Arrange + open l_actual for select object_name, owner from all_objects where rownum < 3; + open l_expected for select value(x) as udt from table(l_expected_tab) x; + + --Act + ut3_develop.ut.expect(l_actual).to_contain(l_expected); + --Assert + l_expected_message := q'[%Actual: refcursor [ count = 2 ] was expected to contain: refcursor [ count = 2 ] +%Diff: +%Columns: +%Column [data-type: UT_KEY_VALUE_PAIR] is missing. Expected column position: 1. +%Column [position: 1, data-type: VARCHAR2] is not expected in results. +%Column [position: 2, data-type: VARCHAR2] is not expected in results. +%Rows: [ 2 differences ] +%Missing: 1Something 1 +%Missing: 2Something 2%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure udt_messg_format_empt is + l_actual sys_refcursor; + l_actual_tab ut3_develop.ut_key_value_pairs := ut3_develop.ut_key_value_pairs(); + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + select ut3_develop.ut_key_value_pair(rownum,'Something '||rownum) + bulk collect into l_actual_tab + from dual connect by level <=2; + + --Arrange + open l_actual for select value(x) as udt from table(l_actual_tab) x; + + --Act + ut3_develop.ut.expect(l_actual).to_be_empty(); + --Assert + l_expected_message := q'[%Actual: (refcursor [ count = 2 ]) +%Data-types: +%UT_KEY_VALUE_PAIR +%Data: +%1Something 12Something 2 +%was expected to be empty%]'; + + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure xml_error_actual is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_exp_message varchar2(32000); + begin + l_exp_message :='ORA-20218: SQL exception thrown when fetching data from cursor: +ORA-01476: divisor is equal to zero +at "UT3_USER.TEST_EXPECTATIONS_CURSOR%", line % ut3_develop.ut.expect(l_actual).to_equal(l_expected);% +Check the query and data for errors.'; + + open l_actual for + select 1 as test from dual; + open l_expected for + select 1/0 as test from dual; + + ut3_develop.ut.expect(l_actual).to_equal(l_expected); + --Line that error relates to in expected messag + + ut.fail('Expected exception on cursor fetch'); + exception + when others then + ut.expect(sqlerrm).to_be_like(l_exp_message); + end; + + procedure xml_error_expected is + l_actual sys_refcursor; + l_expected sys_refcursor; + l_exp_message varchar2(32000); + begin + + l_exp_message :='ORA-20218: SQL exception thrown when fetching data from cursor: +ORA-01476: divisor is equal to zero +at "UT3_USER.TEST_EXPECTATIONS_CURSOR%", line % ut3_develop.ut.expect(l_actual).to_equal(l_expected);% +Check the query and data for errors.'; + + open l_expected for + select 1/0 as test from dual; + open l_actual for + select 1 as test from dual; + + ut3_develop.ut.expect(l_actual).to_equal(l_expected); + + ut.fail('Expected exception on cursor fetch'); + exception + when others then + ut.expect(sqlerrm).to_be_like(l_exp_message); + end; + + procedure no_length_datatypes is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + ut3_develop.ut.set_nls; + open l_expected for + select cast(3.14 as binary_double) as pi_double, + cast(3.14 as binary_float) as pi_float, + rowid as row_rowid, + numtodsinterval(1.12345678912, 'day') row_ds_interval, + numtoyminterval(1.1, 'year') row_ym_interval + from dual; + + open l_actual for + select cast(3.14 as binary_double) as pi_double, + cast(3.14 as binary_float) as pi_float, + rowid as row_rowid, + numtodsinterval(1.12345678912, 'day') row_ds_interval, + numtoyminterval(1.1, 'year') row_ym_interval + from dual; + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + ut3_develop.ut.reset_nls; + + end; + + procedure colon_part_of_columnname is + type t_key_val_rec is record( + key varchar2(100), + value varchar2(100)); + + l_act t_key_val_rec; + l_exp t_key_val_rec; + l_act_cur sys_refcursor; + l_exp_cur sys_refcursor; + begin + l_act.key := 'NAME'; + l_act.value := 'TEST'; + l_exp.key := 'NAME'; + l_exp.value := 'TEST'; + + OPEN l_act_cur FOR SELECT l_act.key, l_act.value + FROM dual; + + OPEN l_exp_cur FOR SELECT l_exp.key, l_exp.value + FROM dual; + + ut3_develop.ut.expect(l_act_cur).to_equal(l_exp_cur); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + + end; + + procedure specialchar_part_of_colname is + l_act_cur sys_refcursor; + l_exp_cur sys_refcursor; + begin + + OPEN l_act_cur FOR SELECT 1 as "$Test", 2 as "&Test" + FROM dual; + + OPEN l_exp_cur FOR SELECT 1 as "$Test", 2 as "&Test" + FROM dual; + + ut3_develop.ut.expect(l_act_cur).to_equal(l_exp_cur); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + + end; + + procedure nonxmlchar_part_of_colname is + l_act_cur sys_refcursor; + l_exp_cur sys_refcursor; + begin + + OPEN l_act_cur FOR SELECT 1 as "", 2 as "_Test", 3 as ".Test>" + FROM dual; + + OPEN l_exp_cur FOR SELECT 1 as "", 2 as "_Test", 3 as ".Test>" + FROM dual; + + ut3_develop.ut.expect(l_act_cur).to_equal(l_exp_cur); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + + end; + + + procedure space_only_vs_empty is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + open l_expected for + select column_value t1 from table(ut_varchar2_list('')); + + open l_actual for + select column_value t1 from table(ut_varchar2_list(' ')); + --Assert + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure tab_only_vs_empty is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + open l_expected for + select column_value t1 from table(ut_varchar2_list('')); + + open l_actual for + select column_value t1 from table(ut_varchar2_list(chr(9))); + --Assert + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure insignificant_start_end_space is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + open l_expected for + select ' t ' t1 from dual; + + open l_actual for + select 't' t1 from dual; + --Assert + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure double_vs_single_start_end_ws is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + open l_expected for + select ' t ' t1 from dual; + + open l_actual for + select ' t ' t1 from dual; + --Assert + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure leading_tab_vs_space is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + open l_expected for + select ' t' t1 from dual; + + open l_actual for + select chr(9)||'t' t1 from dual; + --Assert + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure number_from_dual is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + open l_expected for select + 12345 as n1, + cast(7456123.89 as number(7,-2)) as n2, + cast(7456123.89 as number(9,1)) as n3, + cast(7456123.89 as number(9,2)) as n4, + cast(7456123.89 as number(9)) as n5, + cast(7456123.89 as number(*,1)) as n6, + 7456123.89 as n7 + from dual; + + open l_actual for select + 12345 as n1, + 7456100 as n2, + 7456123.9 as n3, + 7456123.89 as n4, + 7456124 as n5, + 7456123.9 as n6, + 7456123.89 as n7 + from dual; + ut3_develop.ut.expect(l_actual).to_equal(l_expected); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure compare_number_pckg_type + as + l_expected sys_refcursor; + l_actual sys_refcursor; + l_expected_data t_num_tab; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + + l_expected_data(1).col1 := 2135; + l_expected_data(1).col4 := 2016; + l_expected_data(1).col5 := -1; + + --Select on package level nested table types supported only since Oracle 12 + $if dbms_db_version.version >= 12 $then + open l_expected for + select * + from table (l_expected_data); + + open l_actual for + select + 1 as col1 + ,2 as col2 + ,3 as col3 + ,2016 as col4 + ,-1 as col5 + from dual; + + ut3_develop.ut.expect(l_actual).to_equal(a_expected => l_expected); + + l_expected_message := q'[%Actual: refcursor [ count = 1 ] was expected to equal: refcursor [ count = 1 ] +%Diff: +%Rows: [ 1 differences ] +%Row No. 1 - Actual: 123 +%Row No. 1 - Expected: 2135%]'; + + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + + ut.expect(l_actual_message).to_be_like(l_expected_message); + $end + end; + + procedure uc_columns_exclude is + v_actual SYS_REFCURSOR; + v_expected SYS_REFCURSOR; + begin + open v_expected for + select to_Char(null) id, 'ok' name from dual; + open v_actual for + select 'ok' name, to_number(null) id from dual; + + ut3_develop.ut.expect(v_actual).to_equal(v_expected).exclude('ID'); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure compare_long_column_names is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + -- populate actual + $if dbms_db_version.version = 12 and dbms_db_version.release >= 2 or dbms_db_version.version > 12 $then + open l_actual for + select rownum as id, '1' some_column_with_a_pretty_long_enough_name from dual; + + open l_expected for + select rownum as id, '1' some_column_with_a_pretty_long_enough_name from dual; + + ut3_develop.ut.expect(l_actual).to_equal(l_expected).include('ID,SOME_COLUMN_WITH_A_PRETTY_LONG_ENOUGH_NAME').join_by('ID'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + $else + null; + $end + end; + + procedure compare_specific_column_names is + function get_cursor return sys_refcursor is + l_result sys_refcursor; + begin + open l_result for + select 'a' as item_data, rownum as data_id, rownum as item_no, rownum as dup_no, rownum as position from dual; + return l_result; + end; + begin + ut3_develop.ut.expect(get_cursor()).to_equal(get_cursor()); + ut3_develop.ut.expect(get_cursor()).to_equal(get_cursor()).unordered(); + ut3_develop.ut.expect(get_cursor()).to_equal(get_cursor()).join_by('ITEM_DATA,DATA_ID,ITEM_NO,DUP_NO'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure multiple_cursor_expectations is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + open l_actual for select rownum rn from dual connect by level < 5; + open l_expected for select rownum rn from dual connect by level = 1; + ut3_develop.ut.expect(l_actual).to_equal(l_expected); + open l_actual for select rownum rn from dual connect by level < 3; + open l_expected for select * from (select rownum rn from dual connect by level < 3) order by 1 desc; + ut3_develop.ut.expect(l_actual).to_equal(l_expected); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations(1)).to_equal( +'Actual: refcursor [ count = 4 ] was expected to equal: refcursor [ count = 1 ] +Diff: +Rows: [ 3 differences ] + Row No. 2 - Extra: 2 + Row No. 3 - Extra: 3 + Row No. 4 - Extra: 4' + ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations(2)).to_equal( +'Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ] +Diff: +Rows: [ 2 differences ] + Row No. 1 - Actual: 1 + Row No. 1 - Expected: 2 + Row No. 2 - Actual: 2 + Row No. 2 - Expected: 1' + ); + end; + + procedure cr_joinby_compare_issue_1293 is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_expected for + select 'FOO' username, 12 from dual union all + select 'TEST' username, -600 user_id from dual + order by 1 desc; + open l_actual for + select 'FOO' username, 12 from dual union all + select 'TEST' username, -600 user_id from dual union all + -- DUPLICATE!!! + select 'TEST' username, -600 user_id from dual + order by 1 asc; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected).join_by('USERNAME'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure cr_not_joinby_comp_issue_1293 is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + --Arrange + open l_expected for + select 'FOO' username, 12 from dual union all + select 'TEST' username, -600 user_id from dual + order by 1 desc; + open l_actual for + select 'FOO' username, 12 from dual union all + select 'TEST' username, -600 user_id from dual union all + -- DUPLICATE!!! + select 'TEST' username, -600 user_id from dual + order by 1 asc; + --Act + ut3_develop.ut.expect(l_actual).to_equal(l_expected); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + +end; +/ diff --git a/test/core/expectations/test_expectations_cursor.pks b/test/ut3_user/expectations/test_expectations_cursor.pks similarity index 61% rename from test/core/expectations/test_expectations_cursor.pks rename to test/ut3_user/expectations/test_expectations_cursor.pks index a1cff85d9..8cceb5e01 100644 --- a/test/core/expectations/test_expectations_cursor.pks +++ b/test/ut3_user/expectations/test_expectations_cursor.pks @@ -1,7 +1,7 @@ create or replace package test_expectations_cursor is --%suite(cursor expectations) - --%suitepath(utplsql.core.expectations) + --%suitepath(utplsql.test_user.expectations) --%aftereach procedure cleanup_expectations; @@ -17,6 +17,9 @@ create or replace package test_expectations_cursor is --%test(Gives success for identical data) procedure success_on_same_data; + --%test(Gives success for identical data with floats) + procedure success_on_same_data_float; + --%test(Gives success when both cursors are empty) procedure success_on_empty; @@ -68,9 +71,21 @@ create or replace package test_expectations_cursor is --%test(Gives failure when different column name is used in cursors) procedure fail_on_different_column_name; - --%test(Gives failure when different column ordering is used in cursors) + --%test(Gives failure when different column ordering is used in cursors when enforced column order) procedure fail_on_different_column_order; + --%test(Pass when different column ordering is used in cursors) + procedure pass_on_different_column_order; + + --%test(Pass when different column ordering is used in cursors - shortname) + procedure pass_on_diff_column_ord_uc; + + --%test(Fail and highlight diffrence between columns when columns are unordered and different value) + procedure fail_on_multi_diff_col_order; + + --%test(Fail and highlight diffrence between columns when columns are unordered and different value - shortname) + procedure fail_on_multi_diff_col_ord_uc; + --%test(Gives failure when different row ordering is used in cursors) procedure fail_on_different_row_order; @@ -92,7 +107,7 @@ create or replace package test_expectations_cursor is --%test(Excludes comma separated list of mixed columns and XPath) procedure exclude_columns_as_mix_csv_lst; - --%test(Exclude columns fails on invalid XPath) + --%test(Exclude column with invalid filter will result in column being included ) procedure exclude_columns_xpath_invalid; --%test(Exclude columns by XPath is case sensitive) @@ -107,9 +122,6 @@ create or replace package test_expectations_cursor is --%test(Comma separated list of columns to include is case sensitive) procedure include_columns_as_csv; - --%test(Include columns fails on invalid XPath) - procedure include_columns_xpath_invalid; - --%test(Include columns by XPath is case sensitive) procedure include_columns_xpath; @@ -134,18 +146,24 @@ create or replace package test_expectations_cursor is --%test(Reports column diff on cursor with different column name) procedure column_diff_on_col_name_diff; - --%test(Reports column diff on cursor with different column positions) + --%test(Reports column diff on cursor with different column positions when column order is enforced) procedure column_diff_on_col_position; + --%test(Reports column diff on cursor with different column positions) + procedure column_diff_on_col_pos_unord; + --%test(Reports only mismatched columns on row data mismatch) procedure data_diff_on_col_data_mismatch; --%test(Reports only first 20 rows of diff and gives a full diff count) procedure data_diff_on_20_rows_only; - --%test(Reports data diff and column diff when both are different) + --%test(Reports data diff and column diff when both are different with enforced ordered columns) procedure column_and_data_diff; + --%test(Reports data diff and column diff when both are different when columns are not ordered) + procedure col_and_data_diff_not_ordered; + procedure prepare_table; procedure cleanup_table; @@ -193,21 +211,24 @@ create or replace package test_expectations_cursor is --%test(Reports column match on cursor with column name implicit ) procedure col_mtch_on_col_name_implicit; - --%test( Fail on passing implicit column name as include filter ) - procedure include_col_name_implicit; - - --%test( Fail on passing implicit column name as exclude filter ) - procedure exclude_col_name_implicit; - --%test( Compare cursors using unordered method success) procedure cursor_unorderd_compr_success; + --%test( Compare cursors using unordered method success and unordered columns position) + procedure cursor_unord_compr_success_uc; + --%test( Compare cursors using unordered method failure) procedure cursor_unordered_compare_fail; --%test( Compare cursors join by single key ) procedure cursor_joinby_compare; + --%test( Compare cursors join by single key with unordered columns position using shortname) + procedure cursor_joinby_compare_uc; + + --%test(Compare cursors by single key with unordered columns position) + procedure cursor_joinby_col_not_ord; + --%test( Compare cursors join by composite key) procedure cursor_joinby_compare_twocols; @@ -231,6 +252,9 @@ create or replace package test_expectations_cursor is --%test( Compare cursors join by single key more than 1000 rows) procedure cursor_joinby_compare_1000; + + --%test( Compare cursors unorder more than 1000 rows) + procedure cursor_unorder_compare_1000; --%test( Compare two column cursors join by and fail to match ) procedure cursor_joinby_compare_fail; @@ -315,6 +339,157 @@ create or replace package test_expectations_cursor is --%test(Trying to join on collection element inside record ) procedure compare_rec_coll_as_join; + + --%test( Unordered fix for issues with duplicate no : #764 ) + procedure unordered_fix_764; + + --%test( Success when cursor contains data from another cursor) + procedure cursor_to_contain; + + --%test( Fail cursor contains data from another cursor using second keyword) + procedure cursor_to_contain_fail; + + --%test( Success cursor to contain cursor with unordered columns) + procedure cursor_to_contain_uc; + + --%test( Does not fail when comparing cursor to contain cursor with unordered rows option) + procedure cursor_to_contain_unordered; + + --%test( Cursor contains data from another cursor with joinby) + procedure cursor_contain_joinby; + + --%test( Fail cursor contains data from another cursor with joinby) + procedure cursor_contain_joinby_fail; + + --%test(Cursor contains data with list of columns to include) + procedure to_contain_incl_cols_as_list; + + --%test(Cursor contains data with of columns to include and join by value) + procedure to_cont_join_incl_cols_as_lst; + --%test(Cursor contains data with of columns to exclude and join by value) + procedure contain_join_excl_cols_as_lst; + + --%test(Cursor contains data with of columns to exclude) + procedure contain_excl_cols_as_list; + + --%test( Cursor not to contains data from another cursor) + procedure cursor_not_to_contain; + + --%test( Cursor not_to[contain] data from another cursor) + procedure cursor_not_to_contain2; + + --%test( Cursor fail not to contains data from another cursor) + procedure cursor_not_to_contain_fail; + + --%test( Cursor fail not_to[contain] data from another cursor) + procedure cursor_not_to_contain_fail2; + + --%test( Cursor not contains data from another cursor with joinby clause) + procedure cursor_not_to_contain_joinby; + + --%test( Cursor not_to[contain] data from another cursor with joinby clause) + procedure cursor_not_to_contain_joinby2; + + --%test(Cursor not contains data with of columns to include and join by value) + procedure not_cont_join_incl_cols_as_lst; + + --%test(Cursor not_to[contain] data with of columns to include and join by value) + procedure not_con_join_incl_cols_as_lst2; + + --%test(Cursor not contains data with of columns to exclude and join by value) + procedure not_cont_join_excl_cols_as_lst; + + --%test(Cursor not_to[contain] data with of columns to exclude and join by value) + procedure not_con_join_excl_cols_as_lst2; + + --%test(Cursor to contain duplicates) + procedure to_contain_duplicates; + + --%test(Cursor to contain duplicates fail) + procedure to_contain_duplicates_fail; + + --%test(Cursor using not_to[contain] fails #1245) + procedure to_not_contain_fails_1245; + + --%test(Display a message with a uer defined type with only type name not structure on equal) + procedure udt_messg_format_eq; + + --%test(Display a message with a uer defined type with only type name not structure on empty) + procedure udt_messg_format_empt; + + --%test(Fail to process a cursor for actual) + procedure xml_error_actual; + + --%test(Fail to process a cursor for expected) + procedure xml_error_expected; + + --%test(Check that cursor correctly handles no length dataypes) + procedure no_length_datatypes; + + --%test(Check that colon is converted properly fix #902) + procedure colon_part_of_columnname; + + --%test(Check that column name accept special characters fix #902) + procedure specialchar_part_of_colname; + + --%test(Check that column name accept non xml characters fix #902) + procedure nonxmlchar_part_of_colname; + + + /*Oracle Bug not reading properly in XMLTable - See - Issue #880 */ + --%disabled + --%test ( Space-only string is not equal empty string ) + procedure space_only_vs_empty; + + /*Oracle Bug not reading properly in XMLTable - See - Issue #880 */ + --%disabled + --%test ( Tab-only string is not equal empty string ) + procedure tab_only_vs_empty; + + --%test ( Insignificant start/end whitespaces are considered ) + procedure insignificant_start_end_space; + + --%test ( Double and single leading/trailing space is distinguished ) + procedure double_vs_single_start_end_ws; + + --%test ( Leading Tab vs. Space is distinguished ) + procedure leading_tab_vs_space; + + + --%test(Check precision of number from dual #907) + procedure number_from_dual; + + --%test( Comparing number types with different precisions works with package-type nested tables ) + procedure compare_number_pckg_type; + + type t_num_rec is record ( + col1 number(15,0), + col2 number(1,0), + col3 number(4,0), + col4 number(4,0), + col5 number(38,0)); + + + type t_num_tab is table of t_num_rec index by binary_integer; + + --%test( Mixed column order exclusion ) + procedure uc_columns_exclude; + + --%test( Compares cursors with long column names - Issue #952 ) + procedure compare_long_column_names; + + --%test( Compares cursors with specific column names - Issue #997 ) + procedure compare_specific_column_names; + + --%test( Multiple failures reported correctly - Issue #998 ) + procedure multiple_cursor_expectations; + + --%test( Compares cursors with duplicate rows using join by - Issue #1293 ) + procedure cr_joinby_compare_issue_1293; + + --%test( Compares cursors with duplicate rows - Issue #1293 ) + procedure cr_not_joinby_comp_issue_1293; + end; / diff --git a/test/ut3_user/expectations/test_expectations_json.pkb b/test/ut3_user/expectations/test_expectations_json.pkb new file mode 100644 index 000000000..2c501d71f --- /dev/null +++ b/test/ut3_user/expectations/test_expectations_json.pkb @@ -0,0 +1,1807 @@ +create or replace package body test_expectations_json is + + procedure cleanup_expectations is + begin + ut3_tester_helper.main_helper.clear_expectations( ); + end; + + procedure success_on_same_data + as + l_expected json_element_t; + l_actual json_element_t; + begin + -- Arrange + l_actual := json_element_t.parse(' { + "Actors": [ + { + "name": "Tom Cruise", + "age": 56, + "Born At": "Syracuse, NY", + "Birthdate": "July 3, 1962", + "photo": "https://jsonformatter.org/img/tom-cruise.jpg", + "wife": null, + "weight": 67.5, + "hasChildren": true, + "hasGreyHair": false, + "children": [ + "Suri", + "Isabella Jane", + "Connor" + ] + }, + { + "name": "Robert Downey Jr.", + "age": 53, + "Born At": "New York City, NY", + "Birthdate": "April 4, 1965", + "photo": "https://jsonformatter.org/img/Robert-Downey-Jr.jpg", + "wife": "Susan Downey", + "weight": 77.1, + "hasChildren": true, + "hasGreyHair": false, + "children": [ + "Indio Falconer", + "Avri Roel", + "Exton Elias" + ] + } + ] + }'); + + --Act + ut3_develop.ut.expect( l_actual ).to_( ut3_develop.equal( l_actual ) ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure fail_on_diff_data + as + l_expected json_element_t; + l_actual json_element_t; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + -- Arrange + l_actual := json_element_t.parse('{"Aidan Gillen": {"array": ["Game of Thrones","The Wire"],"string": "some string","int": "2","otherint": 4, "aboolean": "true", "boolean": false,"object": {"foo": "bar"}},"Amy Ryan": ["In Treatment","The Wire"],"Annie Fitzgerald": ["True Blood","Big Love","The Sopranos","Oz"],"Anwan Glover": ["Treme","The Wire"],"Alexander Skarsg?rd": ["Generation Kill","True Blood"],"Alice Farmer": ["The Corner","Oz","The Wire"]}'); + l_expected := json_element_t.parse('{"Aidan Gillen": {"array": ["Game of Thron\"es","The Wire"],"string": "some string","int": 2,"aboolean": true, "boolean": true,"object": {"foo": "bar","object1": {"new prop1": "new prop value"},"object2": {"new prop1": "new prop value"},"object3": {"new prop1": "new prop value"},"object4": {"new prop1": "new prop value"}}},"Amy Ryan": {"one": "In Treatment","two": "The Wire"},"Annie Fitzgerald": ["Big Love","True Blood"],"Anwan Glover": ["Treme","The Wire"],"Alexander Skarsgard": ["Generation Kill","True Blood"], "Clarke Peters": null}'); + + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + --Assert + l_expected_message := q'[%Missing property: "Alexander Skarsg?rd" on path: $ +%Extra property: "Alexander Skarsgard" on path: $ +%Missing property: "Alice Farmer" on path: $ +%Extra property: "Clarke Peters" on path: $ +%Extra property: "one" on path: $."Amy Ryan" +%Missing property: "The Sopranos" on path: $."Annie Fitzgerald"[2] +%Extra property: "two" on path: $."Amy Ryan" +%Missing property: "Oz" on path: $."Annie Fitzgerald"[3] +%Missing property: "otherint" on path: $."Aidan Gillen" +%Extra property: "object1" on path: $."Aidan Gillen"."object" +%Extra property: "object2" on path: $."Aidan Gillen"."object" +%Extra property: "object3" on path: $."Aidan Gillen"."object" +%Extra property: "object4" on path: $."Aidan Gillen"."object" +%Actual type: 'array' was expected to be: 'object' on path: $."Amy Ryan" +%Actual type: 'string' was expected to be: 'number' on path: $."Aidan Gillen"."int" +%Actual type: 'string' was expected to be: 'boolean' on path: $."Aidan Gillen"."aboolean" +%Actual value: "True Blood" was expected to be: "Big Love" on path: $."Annie Fitzgerald"[0] +%Actual value: "Big Love" was expected to be: "True Blood" on path: $."Annie Fitzgerald"[1] +%Actual value: FALSE was expected to be: TRUE on path: $."Aidan Gillen"."boolean" +%Actual value: "Game of Thrones" was expected to be: "Game of Thron\"es" on path: $."Aidan Gillen"."array"[0]%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + ut.expect(l_actual_message).to_be_like('%Diff: 20 differences found%'); + ut.expect(l_actual_message).to_be_like('%13 missing properties%'); + ut.expect(l_actual_message).to_be_like('%4 unequal values%'); + ut.expect(l_actual_message).to_be_like('%3 incorrect types%'); + end; + + procedure null_json_variable + as + l_expected json_object_t ; + begin + -- Arrange + l_expected := cast (null as json_object_t ); + + --Act + ut3_develop.ut.expect( l_expected ).to_be_null; + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure not_null_json_variable + as + l_expected json_object_t ; + begin + -- Arrange + l_expected := json_object_t(); + + --Act + ut3_develop.ut.expect( l_expected ).not_to_be_null; + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure fail_null_json_var + as + l_expected json_object_t ; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + -- Arrange + l_expected := json_object_t('{ "t" : "1" }'); + + --Act + ut3_develop.ut.expect( l_expected ).to_be_null; + --Assert + l_expected_message := q'[%Actual: (json) +%'{"t":"1"}' +%was expected to be null%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure fail_not_null_json_var + as + l_expected json_object_t; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + -- Arrange + l_expected := cast (null as json_object_t ); + + --Act + ut3_develop.ut.expect( l_expected ).not_to_be_null; + --Assert + l_expected_message := q'[%Actual: NULL (json) was expected not to be null%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure empty_json + as + l_expected json_object_t; + begin + -- Arrange + l_expected := json_object_t(); + + --Act + ut3_develop.ut.expect( l_expected ).to_be_empty; + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure not_empty_json + as + l_expected json_object_t; + begin + -- Arrange + l_expected := json_object_t.parse('{ "name" : "test" }'); + + --Act + ut3_develop.ut.expect( l_expected ).not_to_be_empty; + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure fail_empty_json + as + l_expected json_object_t; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + -- Arrange + l_expected := json_object_t.parse('{ "name" : "test" }'); + + --Act + ut3_develop.ut.expect( l_expected ).to_be_empty; + --Assert + l_expected_message := q'[%Actual: (json) +%'{"name":"test"}' +%was expected to be empty%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure fail_not_empty_json + as + l_expected json_object_t; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + -- Arrange + l_expected := json_object_t(); + + --Act + ut3_develop.ut.expect( l_expected ).not_to_be_empty; + --Assert + l_expected_message := q'[%Actual: (json) +%'{}' +%was expected not to be empty%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure to_have_count as + l_actual json_element_t; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + -- Arrange + l_actual := json_element_t.parse('{"Aidan Gillen": {"array": ["Game of Thrones","The Wire"],"string": "some string","int": "2","otherint": 4, "aboolean": "true", "boolean": false,"object": {"foo": "bar"}},"Amy Ryan": ["In Treatment","The Wire"],"Annie Fitzgerald": ["True Blood","Big Love","The Sopranos","Oz"],"Anwan Glover": ["Treme","The Wire"],"Alexander Skarsg?rd": ["Generation Kill","True Blood"],"Alice Farmer": ["The Corner","Oz","The Wire"]}'); + + --Act + ut3_develop.ut.expect( l_actual ).to_have_count( 6 ); + + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + + end; + + procedure fail_to_have_count + as + l_actual json_element_t; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + -- Arrange + l_actual := json_element_t.parse('{"Aidan Gillen": {"array": ["Game of Thrones","The Wire"],"string": "some string","int": "2","otherint": 4, "aboolean": "true", "boolean": false,"object": {"foo": "bar"}},"Amy Ryan": ["In Treatment","The Wire"],"Annie Fitzgerald": ["True Blood","Big Love","The Sopranos","Oz"],"Anwan Glover": ["Treme","The Wire"],"Alexander Skarsg?rd": ["Generation Kill","True Blood"],"Alice Farmer": ["The Corner","Oz","The Wire"]}'); + + --Act + ut3_develop.ut.expect( l_actual ).to_have_count( 2 ); + --Assert + l_expected_message := q'[%Actual: (json [ count = 6 ]) was expected to have [ count = 2 ]%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + + end; + + procedure not_to_have_count + as + l_actual json_element_t; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + -- Arrange + l_actual := json_element_t.parse('{"Aidan Gillen": {"array": ["Game of Thrones","The Wire"],"string": "some string","int": "2","otherint": 4, "aboolean": "true", "boolean": false,"object": {"foo": "bar"}},"Amy Ryan": ["In Treatment","The Wire"],"Annie Fitzgerald": ["True Blood","Big Love","The Sopranos","Oz"],"Anwan Glover": ["Treme","The Wire"],"Alexander Skarsg?rd": ["Generation Kill","True Blood"],"Alice Farmer": ["The Corner","Oz","The Wire"]}'); + + --Act + ut3_develop.ut.expect( l_actual ).not_to_have_count( 7 ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure fail_not_to_have_count + as + l_actual json_element_t; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + -- Arrange + l_actual := json_element_t.parse('{"Aidan Gillen": {"array": ["Game of Thrones","The Wire"],"string": "some string","int": "2","otherint": 4, "aboolean": "true", "boolean": false,"object": {"foo": "bar"}},"Amy Ryan": ["In Treatment","The Wire"],"Annie Fitzgerald": ["True Blood","Big Love","The Sopranos","Oz"],"Anwan Glover": ["Treme","The Wire"],"Alexander Skarsg?rd": ["Generation Kill","True Blood"],"Alice Farmer": ["The Corner","Oz","The Wire"]}'); + + --Act + ut3_develop.ut.expect( l_actual ).not_to_have_count( 6 ); + --Assert + l_expected_message := q'[%Actual: json [ count = 6 ] was expected not to have [ count = 6 ]%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure to_have_count_array + as + l_actual json_element_t; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + -- Arrange + l_actual := json_element_t.parse('["Game of Thrones","The Wire"]'); + + --Act + ut3_develop.ut.expect( l_actual ).to_have_count( 2 ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure to_diff_json_extract_same + as + l_expected json_object_t; + l_actual json_object_t; + BEGIN + -- Arrange + l_expected := json_object_t.parse(' { + "Actors": [ + { + "name": "Tom Cruise", + "age": 56, + "Born At": "Syracuse, NY", + "Birthdate": "July 3, 1962", + "photo": "https://jsonformatter.org/img/tom-cruise.jpg", + "wife": null, + "weight": 67.5, + "hasChildren": true, + "hasGreyHair": false, + "children": [ + "Suri", + "Isabella Jane", + "Connor" + ] + }, + { + "name": "Robert Downey Jr.", + "age": 53, + "Born At": "New York City, NY", + "Birthdate": "April 4, 1965", + "photo": "https://jsonformatter.org/img/Robert-Downey-Jr.jpg", + "wife": "Susan Downey", + "weight": 77.1, + "hasChildren": true, + "hasGreyHair": false, + "children": [ + "Indio Falconer", + "Avri Roel", + "Exton Elias" + ] + } + ] + }' + ); + l_actual := json_object_t.parse(' { + "Actors": + { + "name": "Krzystof Jarzyna", + "age": 53, + "Born At": "Szczecin", + "Birthdate": "April 4, 1965", + "photo": "niewidzialny", + "wife": "Susan Downey", + "children": [ + "Indio Falconer", + "Avri Roel", + "Exton Elias" + ] + } + }' + ); + + + --Act + ut3_develop.ut.expect(json_array_t(json_query(l_actual.stringify,'$.Actors.children'))).to_equal(json_array_t(json_query(l_expected + .stringify,'$.Actors[1].children'))); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure to_diff_json_extract_diff + as + l_expected json_object_t; + l_actual json_object_t; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + -- Arrange + l_actual := json_object_t.parse(' { + "Actors": [ + { + "name": "Tom Cruise", + "age": 56, + "Born At": "Syracuse, NY", + "Birthdate": "July 3, 1962", + "photo": "https://jsonformatter.org/img/tom-cruise.jpg", + "wife": null, + "weight": 67.5, + "hasChildren": true, + "hasGreyHair": false, + "children": [ + "Suri", + "Isabella Jane", + "Connor" + ] + }, + { + "name": "Robert Downey Jr.", + "age": 53, + "Born At": "New York City, NY", + "Birthdate": "April 4, 1965", + "photo": "https://jsonformatter.org/img/Robert-Downey-Jr.jpg", + "wife": "Susan Downey", + "weight": 77.1, + "hasChildren": true, + "hasGreyHair": false, + "children": [ + "Noemi", + "Avri Roel", + "Exton Elias" + ] + } + ] + }' + ); + l_expected := json_object_t.parse(' { + "Actors": + { + "name": "Krzystof Jarzyna", + "age": 53, + "Born At": "Szczecin", + "Birthdate": "April 4, 1965", + "photo": "niewidzialny", + "wife": "Susan Downey", + "children": [ + "Indio Falconer", + "Avri Roel", + "Exton Elias" + ] + } + }' + ); + + + --Act + ut3_develop.ut.expect(json_array_t(json_query(l_actual.stringify,'$.Actors[1].children'))).to_equal(json_array_t(json_query(l_expected + .stringify,'$.Actors.children'))); + --Assert + l_expected_message := q'[%Actual: json was expected to equal: json +%Diff: 1 differences found +%1 unequal values +%Actual value: "Noemi" was expected to be: "Indio Falconer" on path: $[0]%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure long_json_test + as + l_actual json_element_t; + begin + l_actual := json_element_t.parse('[ + { + "_id": "5ce6dc0c3a11766d5a26f494", + "index": 0, + "guid": "a86b8b2d-216d-4061-bafa-f3820e41efbe", + "isActive": true, + "balance": "$1,754.93", + "picture": "http://placehold.it/32x32", + "age": 39, + "eyeColor": "green", + "name": "Pearlie Lott", + "gender": "female", + "company": "KOG", + "email": "pearlielott@kog.com", + "phone": "+1 (852) 567-2605", + "address": "357 Eldert Street, Benson, Montana, 5484", + "about": "Est officia consectetur reprehenderit fugiat culpa ea commodo aliqua deserunt enim eu. Exercitation adipisicing laboris nisi irure commodo dolor consectetur tempor minim sunt ullamco Lorem occaecat. Irure quis ut Lorem aliquip aute pariatur magna laboris duis veniam qui velit. Pariatur occaecat eu minim adipisicing est do. Occaecat do ipsum ut in enim quis voluptate et. Sit ea irure nulla culpa in eiusmod.\r\n", + "registered": "2018-08-24T12:46:31 -01:00", + "latitude": -22.323554, + "longitude": 139.071611, + "tags": [ + "id", + "do", + "amet", + "magna", + "est", + "veniam", + "voluptate" + ], + "friends": [ + { + "id": 0, + "name": "Tammi Lowe" + }, + { + "id": 1, + "name": "Simpson Miles" + }, + { + "id": 2, + "name": "Hogan Osborne" + } + ], + "greeting": "Hello, Pearlie Lott! You have 2 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "5ce6dc0c2b56a6f3271fc272", + "index": 1, + "guid": "2a24b446-d11a-4a52-b6c8-86acba1dc65f", + "isActive": true, + "balance": "$1,176.58", + "picture": "http://placehold.it/32x32", + "age": 30, + "eyeColor": "brown", + "name": "Bertha Mack", + "gender": "female", + "company": "AQUAFIRE", + "email": "berthamack@aquafire.com", + "phone": "+1 (804) 504-2151", + "address": "636 Bouck Court, Cresaptown, Vermont, 5203", + "about": "Ipsum est exercitation excepteur reprehenderit ipsum. Do velit dolore minim ad. Quis amet dolor dolore exercitation sint Lorem. Exercitation nulla magna ut incididunt enim veniam voluptate Lorem velit adipisicing sunt deserunt sunt aute. Ullamco id anim Lorem dolore do labore excepteur et reprehenderit sit adipisicing sunt esse veniam. Anim laborum labore labore incididunt in labore exercitation ad occaecat amet ea quis veniam ut.\r\n", + "registered": "2017-12-29T06:00:27 -00:00", + "latitude": 75.542572, + "longitude": 147.312705, + "tags": [ + "veniam", + "sunt", + "commodo", + "ad", + "enim", + "officia", + "nisi" + ], + "friends": [ + { + "id": 0, + "name": "Riddle Williams" + }, + { + "id": 1, + "name": "Tracy Wagner" + }, + { + "id": 2, + "name": "Morrow Phillips" + } + ], + "greeting": "Hello, Bertha Mack! You have 8 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "5ce6dc0c6d8631fbfdd2afc7", + "index": 2, + "guid": "66ca5411-4c88-4347-9972-e1016f628098", + "isActive": false, + "balance": "$2,732.22", + "picture": "http://placehold.it/32x32", + "age": 33, + "eyeColor": "blue", + "name": "Fox Morgan", + "gender": "male", + "company": "PERKLE", + "email": "foxmorgan@perkle.com", + "phone": "+1 (985) 401-3450", + "address": "801 Whitty Lane, Snyderville, Guam, 5253", + "about": "Ex officia eu Lorem velit ullamco qui cupidatat irure sunt ea ad deserunt. Officia est consequat aute labore occaecat aliquip. Velit commodo cillum incididunt cupidatat ad id veniam aute labore tempor qui culpa voluptate dolor. Occaecat in ea id labore exercitation non tempor occaecat laboris aute irure fugiat dolor mollit. Voluptate non proident officia deserunt ex et ullamco aute eiusmod cupidatat consequat elit id.\r\n", + "registered": "2015-04-02T06:40:53 -01:00", + "latitude": -27.612441, + "longitude": -134.005929, + "tags": [ + "occaecat", + "amet", + "eu", + "dolore", + "ad", + "fugiat", + "quis" + ], + "friends": [ + { + "id": 0, + "name": "Case Preston" + }, + { + "id": 1, + "name": "Pollard Dawson" + }, + { + "id": 2, + "name": "Frye Mann" + } + ], + "greeting": "Hello, Fox Morgan! You have 2 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ce6dc0c0a7fea91e0a1fdf5", + "index": 3, + "guid": "f895a236-fc0d-4c08-b2f0-9d1638dc256d", + "isActive": true, + "balance": "$2,746.32", + "picture": "http://placehold.it/32x32", + "age": 34, + "eyeColor": "green", + "name": "Deleon Tucker", + "gender": "male", + "company": "ZANILLA", + "email": "deleontucker@zanilla.com", + "phone": "+1 (883) 415-2709", + "address": "540 Vandam Street, Chical, Wyoming, 5181", + "about": "Consectetur consectetur sint Lorem non id. Fugiat reprehenderit nulla dolore nisi culpa esse ea. Ad occaecat qui magna proident ex pariatur aliquip adipisicing do aute aute sunt. Aliqua aliqua et exercitation sunt ut adipisicing.\r\n", + "registered": "2017-10-08T09:05:49 -01:00", + "latitude": 34.893845, + "longitude": 110.699256, + "tags": [ + "culpa", + "sunt", + "sit", + "ut", + "eiusmod", + "laboris", + "ullamco" + ], + "friends": [ + { + "id": 0, + "name": "Bernadine Pennington" + }, + { + "id": 1, + "name": "Latoya Bradshaw" + }, + { + "id": 2, + "name": "Iva Caldwell" + } + ], + "greeting": "Hello, Deleon Tucker! You have 7 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "5ce6dc0c18bc92716a12a8e4", + "index": 4, + "guid": "6ed45f42-1a2b-48b2-89ce-5fdb2505343b", + "isActive": true, + "balance": "$1,049.96", + "picture": "http://placehold.it/32x32", + "age": 30, + "eyeColor": "blue", + "name": "Schwartz Norman", + "gender": "male", + "company": "UPDAT", + "email": "schwartznorman@updat.com", + "phone": "+1 (826) 404-3309", + "address": "925 Harman Street, Cornucopia, Georgia, 5748", + "about": "Qui Lorem ullamco veniam irure aliquip amet exercitation. Velit nisi id laboris adipisicing in esse adipisicing commodo cillum do exercitation tempor. Consequat tempor dolor minim consequat minim ad do tempor excepteur.\r\n", + "registered": "2014-08-10T08:34:27 -01:00", + "latitude": 27.35547, + "longitude": -77.343791, + "tags": [ + "reprehenderit", + "nisi", + "duis", + "fugiat", + "id", + "non", + "laboris" + ], + "friends": [ + { + "id": 0, + "name": "Dora Combs" + }, + { + "id": 1, + "name": "Emerson Wade" + }, + { + "id": 2, + "name": "Alma Mccormick" + } + ], + "greeting": "Hello, Schwartz Norman! You have 1 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ce6dc0cb7ae44eb76c3e5fd", + "index": 5, + "guid": "0516df27-73db-42a8-b2c3-d34bd976e031", + "isActive": false, + "balance": "$3,679.94", + "picture": "http://placehold.it/32x32", + "age": 32, + "eyeColor": "brown", + "name": "Christi Oneal", + "gender": "female", + "company": "SUREPLEX", + "email": "christioneal@sureplex.com", + "phone": "+1 (985) 408-3098", + "address": "640 Fayette Street, Dennard, Washington, 7962", + "about": "Dolore fugiat sit non dolore nostrud mollit enim id sint culpa do reprehenderit ad. Velit occaecat incididunt nostrud aliqua incididunt do cillum occaecat laboris quis duis. Non tempor culpa aliquip est est consectetur ullamco elit. Voluptate et sit do et. Amet sit irure eu ex enim nulla anim deserunt ut. Sit aute ea ut fugiat eu tempor Lorem.\r\n", + "registered": "2015-05-10T09:24:56 -01:00", + "latitude": 43.343805, + "longitude": 79.535043, + "tags": [ + "occaecat", + "laboris", + "nulla", + "nisi", + "dolore", + "cillum", + "dolore" + ], + "friends": [ + { + "id": 0, + "name": "Marquez Wiggins" + }, + { + "id": 1, + "name": "Mai Fischer" + }, + { + "id": 2, + "name": "Newman Davenport" + } + ], + "greeting": "Hello, Christi Oneal! You have 8 unread messages.", + "favoriteFruit": "strawberry" + } +]'); + + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_actual ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure json_same_diffrent_ord + as + l_expected json_element_t; + l_actual json_element_t; + begin + -- Arrange + l_expected := json_element_t.parse('{ + "records": [ + {"field1": "outer", "field2": "thought"}, + {"field2": "thought", "field1": "outer"} + ] , + "special message": "hello, world!" +}'); + l_actual := json_element_t.parse('{ + "special message": "hello, world!" , + "records": [ + {"field2": "thought" ,"field1": "outer"}, + {"field1": "outer" , "field2": "thought"} + ] +}'); + + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure long_json_test2 + as + l_actual json_element_t; + begin + l_actual := json_element_t.parse('[ + { + "_id":"5ce6dc0c3a11766d5a26f494", + "index":0, + "guid":"a86b8b2d-216d-4061-bafa-f3820e41efbe", + "isActive":true, + "balance":"$1,754.93", + "picture":"http://placehold.it/32x32", + "age":39, + "eyeColor":"green", + "name":"Pearlie Lott", + "gender":"female", + "company":"KOG", + "email":"pearlielott@kog.com", + "phone":"+1 (852) 567-2605", + "address":"357 Eldert Street, Benson, Montana, 5484", + "about":"Est officia consectetur reprehenderit fugiat culpa ea commodo aliqua deserunt enim eu. Exercitation adipisicing laboris nisi irure commodo dolor consectetur tempor minim sunt ullamco Lorem occaecat. Irure quis ut Lorem aliquip aute pariatur magna laboris duis veniam qui velit. Pariatur occaecat eu minim adipisicing est do. Occaecat do ipsum ut in enim quis voluptate et. Sit ea irure nulla culpa in eiusmod.\r\n", + "registered":"2018-08-24T12:46:31 -01:00", + "latitude":-22.323554, + "longitude":139.071611, + "tags":[ + "id", + "do", + "amet", + "magna", + "est", + "veniam", + "voluptate" + ], + "friends":[ + { + "id":0, + "name":"Tammi Lowe" + }, + { + "id":1, + "name":"Simpson Miles" + }, + { + "id":2, + "name":"Hogan Osborne" + } + ], + "greeting":"Hello, Pearlie Lott! You have 2 unread messages.", + "favoriteFruit":"banana" + }, + { + "_id":"5ce6dc0c2b56a6f3271fc272", + "index":1, + "guid":"2a24b446-d11a-4a52-b6c8-86acba1dc65f", + "isActive":true, + "balance":"$1,176.58", + "picture":"http://placehold.it/32x32", + "age":30, + "eyeColor":"brown", + "name":"Bertha Mack", + "gender":"female", + "company":"AQUAFIRE", + "email":"berthamack@aquafire.com", + "phone":"+1 (804) 504-2151", + "address":"636 Bouck Court, Cresaptown, Vermont, 5203", + "about":"Ipsum est exercitation excepteur reprehenderit ipsum. Do velit dolore minim ad. Quis amet dolor dolore exercitation sint Lorem. Exercitation nulla magna ut incididunt enim veniam voluptate Lorem velit adipisicing sunt deserunt sunt aute. Ullamco id anim Lorem dolore do labore excepteur et reprehenderit sit adipisicing sunt esse veniam. Anim laborum labore labore incididunt in labore exercitation ad occaecat amet ea quis veniam ut.\r\n", + "registered":"2017-12-29T06:00:27 -00:00", + "latitude":75.542572, + "longitude":147.312705, + "tags":[ + "veniam", + "sunt", + "commodo", + "ad", + "enim", + "officia", + "nisi" + ], + "friends":[ + { + "id":0, + "name":"Riddle Williams" + }, + { + "id":1, + "name":"Tracy Wagner" + }, + { + "id":2, + "name":"Morrow Phillips" + } + ], + "greeting":"Hello, Bertha Mack! You have 8 unread messages.", + "favoriteFruit":"banana" + }, + { + "_id":"5ce6dc0c6d8631fbfdd2afc7", + "index":2, + "guid":"66ca5411-4c88-4347-9972-e1016f628098", + "isActive":false, + "balance":"$2,732.22", + "picture":"http://placehold.it/32x32", + "age":33, + "eyeColor":"blue", + "name":"Fox Morgan", + "gender":"male", + "company":"PERKLE", + "email":"foxmorgan@perkle.com", + "phone":"+1 (985) 401-3450", + "address":"801 Whitty Lane, Snyderville, Guam, 5253", + "about":"Ex officia eu Lorem velit ullamco qui cupidatat irure sunt ea ad deserunt. Officia est consequat aute labore occaecat aliquip. Velit commodo cillum incididunt cupidatat ad id veniam aute labore tempor qui culpa voluptate dolor. Occaecat in ea id labore exercitation non tempor occaecat laboris aute irure fugiat dolor mollit. Voluptate non proident officia deserunt ex et ullamco aute eiusmod cupidatat consequat elit id.\r\n", + "registered":"2015-04-02T06:40:53 -01:00", + "latitude":-27.612441, + "longitude":-134.005929, + "tags":[ + "occaecat", + "amet", + "eu", + "dolore", + "ad", + "fugiat", + "quis" + ], + "friends":[ + { + "id":0, + "name":"Case Preston" + }, + { + "id":1, + "name":"Pollard Dawson" + }, + { + "id":2, + "name":"Frye Mann" + } + ], + "greeting":"Hello, Fox Morgan! You have 2 unread messages.", + "favoriteFruit":"apple" + }, + { + "_id":"5ce6dc0c0a7fea91e0a1fdf5", + "index":3, + "guid":"f895a236-fc0d-4c08-b2f0-9d1638dc256d", + "isActive":true, + "balance":"$2,746.32", + "picture":"http://placehold.it/32x32", + "age":34, + "eyeColor":"green", + "name":"Deleon Tucker", + "gender":"male", + "company":"ZANILLA", + "email":"deleontucker@zanilla.com", + "phone":"+1 (883) 415-2709", + "address":"540 Vandam Street, Chical, Wyoming, 5181", + "about":"Consectetur consectetur sint Lorem non id. Fugiat reprehenderit nulla dolore nisi culpa esse ea. Ad occaecat qui magna proident ex pariatur aliquip adipisicing do aute aute sunt. Aliqua aliqua et exercitation sunt ut adipisicing.\r\n", + "registered":"2017-10-08T09:05:49 -01:00", + "latitude":34.893845, + "longitude":110.699256, + "tags":[ + "culpa", + "sunt", + "sit", + "ut", + "eiusmod", + "laboris", + "ullamco" + ], + "friends":[ + { + "id":0, + "name":"Bernadine Pennington" + }, + { + "id":1, + "name":"Latoya Bradshaw" + }, + { + "id":2, + "name":"Iva Caldwell" + } + ], + "greeting":"Hello, Deleon Tucker! You have 7 unread messages.", + "favoriteFruit":"banana" + }, + { + "_id":"5ce6dc0c18bc92716a12a8e4", + "index":4, + "guid":"6ed45f42-1a2b-48b2-89ce-5fdb2505343b", + "isActive":true, + "balance":"$1,049.96", + "picture":"http://placehold.it/32x32", + "age":30, + "eyeColor":"blue", + "name":"Schwartz Norman", + "gender":"male", + "company":"UPDAT", + "email":"schwartznorman@updat.com", + "phone":"+1 (826) 404-3309", + "address":"925 Harman Street, Cornucopia, Georgia, 5748", + "about":"Qui Lorem ullamco veniam irure aliquip amet exercitation. Velit nisi id laboris adipisicing in esse adipisicing commodo cillum do exercitation tempor. Consequat tempor dolor minim consequat minim ad do tempor excepteur.\r\n", + "registered":"2014-08-10T08:34:27 -01:00", + "latitude":27.35547, + "longitude":-77.343791, + "tags":[ + "reprehenderit", + "nisi", + "duis", + "fugiat", + "id", + "non", + "laboris" + ], + "friends":[ + { + "id":0, + "name":"Dora Combs" + }, + { + "id":1, + "name":"Emerson Wade" + }, + { + "id":2, + "name":"Alma Mccormick" + } + ], + "greeting":"Hello, Schwartz Norman! You have 1 unread messages.", + "favoriteFruit":"apple" + }, + { + "_id":"5ce6dc0cb7ae44eb76c3e5fd", + "index":5, + "guid":"0516df27-73db-42a8-b2c3-d34bd976e031", + "isActive":false, + "balance":"$3,679.94", + "picture":"http://placehold.it/32x32", + "age":32, + "eyeColor":"brown", + "name":"Christi Oneal", + "gender":"female", + "company":"SUREPLEX", + "email":"christioneal@sureplex.com", + "phone":"+1 (985) 408-3098", + "address":"640 Fayette Street, Dennard, Washington, 7962", + "about":"Dolore fugiat sit non dolore nostrud mollit enim id sint culpa do reprehenderit ad. Velit occaecat incididunt nostrud aliqua incididunt do cillum occaecat laboris quis duis. Non tempor culpa aliquip est est consectetur ullamco elit. Voluptate et sit do et. Amet sit irure eu ex enim nulla anim deserunt ut. Sit aute ea ut fugiat eu tempor Lorem.\r\n", + "registered":"2015-05-10T09:24:56 -01:00", + "latitude":43.343805, + "longitude":79.535043, + "tags":[ + "occaecat", + "laboris", + "nulla", + "nisi", + "dolore", + "cillum", + "dolore" + ], + "friends":[ + { + "id":0, + "name":"Marquez Wiggins" + }, + { + "id":1, + "name":"Mai Fischer" + }, + { + "id":2, + "name":"Newman Davenport" + } + ], + "greeting":"Hello, Christi Oneal! You have 8 unread messages.", + "favoriteFruit":"strawberry" + } +]'); + + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_actual ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure long_json_diff as + l_expected json_element_t; + l_actual json_element_t; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + -- Arrange + l_actual := json_element_t.parse('[ + { + "_id": "5ce6ec46cb9977b050f15d97", + "index": 0, + "guid": "1acb2b6b-15b5-4747-a62f-db477e18df61", + "isActive": false, + "balance": "$1,443.80", + "picture": "http://placehold.it/32x32", + "age": 33, + "eyeColor": "brown", + "name": "Carson Conley", + "gender": "male", + "company": "EYEWAX", + "email": "carsonconley@eyewax.com", + "phone": "+1 (873) 520-2117", + "address": "289 Wallabout Street, Cazadero, Nevada, 4802", + "about": "Lorem aliqua veniam eiusmod exercitation anim sunt esse qui tempor officia amet nulla labore enim. Fugiat eiusmod amet exercitation incididunt mollit pariatur amet et quis et ex amet adipisicing. Elit in commodo tempor adipisicing exercitation Lorem amet cillum sint sint aliquip. Officia enim do irure velit qui officia et reprehenderit qui enim.\r\n", + "registered": "2018-08-07T05:03:13 -01:00", + "latitude": -1.973252, + "longitude": 17.835529, + "tags": [ + "dolore", + "occaecat", + "proident", + "laborum", + "nostrud", + "non", + "occaecat" + ], + "friends": [ + { + "id": 0, + "name": "Riggs Cardenas" + }, + { + "id": 1, + "name": "Duncan Schultz" + }, + { + "id": 2, + "name": "Galloway Bond" + } + ], + "greeting": "Hello, Carson Conley! You have 5 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "5ce6ec469ba57bef5c421021", + "index": 1, + "guid": "59be5b73-fffe-4a4f-acea-65c5abbdb53c", + "isActive": true, + "balance": "$3,895.35", + "picture": "http://placehold.it/32x32", + "age": 21, + "eyeColor": "brown", + "name": "Melton Carroll", + "gender": "male", + "company": "ISOSPHERE", + "email": "meltoncarroll@isosphere.com", + "phone": "+1 (804) 416-2235", + "address": "114 Windsor Place, Dubois, Oklahoma, 9648", + "about": "Pariatur ea voluptate aute dolor minim laborum cillum ad reprehenderit. Mollit sint voluptate duis et culpa amet irure laborum. Nulla veniam fugiat sint proident aliquip dolore laboris nisi et. Nisi in do aliqua voluptate cupidatat enim dolor minim minim qui tempor. Eu anim ea mollit sunt esse et est cillum cillum pariatur dolor. Ea anim duis sunt eiusmod sit cillum consectetur aliquip ad et elit culpa irure commodo.\r\n", + "registered": "2018-10-20T01:38:32 -01:00", + "latitude": 46.821539, + "longitude": 19.78817, + "tags": [ + "sunt", + "aliquip", + "commodo", + "occaecat", + "mollit", + "minim", + "sint" + ], + "friends": [ + { + "id": 0, + "name": "Tameka Reese" + }, + { + "id": 1, + "name": "Rosemarie Buckley" + }, + { + "id": 2, + "name": "Houston Moran" + } + ], + "greeting": "Hello, Melton Carroll! You have 10 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "5ce6ec464e6f8751e75ed29f", + "index": 2, + "guid": "42e07b71-b769-4078-b226-f79048b75bd2", + "isActive": false, + "balance": "$3,366.81", + "picture": "http://placehold.it/32x32", + "age": 23, + "eyeColor": "blue", + "name": "Kathie Cameron", + "gender": "female", + "company": "EVENTIX", + "email": "kathiecameron@eventix.com", + "phone": "+1 (949) 416-3458", + "address": "171 Henderson Walk, Barstow, American Samoa, 3605", + "about": "Lorem est mollit consequat pariatur elit. Enim adipisicing ipsum sit labore exercitation fugiat qui eu enim. Quis irure Lorem exercitation laborum sunt quis Lorem pariatur officia veniam aute officia mollit quis.\r\n", + "registered": "2015-07-15T08:40:18 -01:00", + "latitude": -12.947501, + "longitude": 51.221756, + "tags": [ + "voluptate", + "officia", + "laborum", + "nulla", + "anim", + "mollit", + "adipisicing" + ], + "friends": [ + { + "id": 0, + "name": "Noelle Leonard" + }, + { + "id": 1, + "name": "Sally Barr" + }, + { + "id": 2, + "name": "Rosie Rutledge" + } + ], + "greeting": "Hello, Kathie Cameron! You have 10 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "5ce6ec4632328a654d592cb6", + "index": 3, + "guid": "6b9124a9-fbde-4c60-8dac-e296f5daa3c4", + "isActive": true, + "balance": "$2,374.96", + "picture": "http://placehold.it/32x32", + "age": 32, + "eyeColor": "brown", + "name": "Ebony Carver", + "gender": "female", + "company": "EVENTEX", + "email": "ebonycarver@eventex.com", + "phone": "+1 (816) 535-3332", + "address": "452 Lott Street, Iberia, South Carolina, 1635", + "about": "Ea cupidatat occaecat in Lorem adipisicing quis sunt. Occaecat sit Lorem eiusmod et. Velit nostrud cupidatat do exercitation. Officia esse excepteur labore aliqua fugiat dolor duis. Ullamco qui ipsum eu do nostrud et laboris magna dolor cillum. Dolore eiusmod do occaecat dolore.\r\n", + "registered": "2017-04-12T09:20:02 -01:00", + "latitude": 65.70655, + "longitude": 150.667286, + "tags": [ + "do", + "laboris", + "exercitation", + "quis", + "laboris", + "amet", + "sint" + ], + "friends": [ + { + "id": 0, + "name": "Rowena Holloway" + }, + { + "id": 1, + "name": "Lee Chang" + }, + { + "id": 2, + "name": "Delaney Kennedy" + } + ], + "greeting": "Hello, Ebony Carver! You have 10 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ce6ec46d9dbfbf9b184cee7", + "index": 4, + "guid": "9dece65b-6b48-4960-880b-7795ff63c81c", + "isActive": false, + "balance": "$2,927.54", + "picture": "http://placehold.it/32x32", + "age": 27, + "eyeColor": "green", + "name": "Mae Payne", + "gender": "female", + "company": "ZEPITOPE", + "email": "maepayne@zepitope.com", + "phone": "+1 (904) 531-2930", + "address": "575 Amity Street, Eden, Iowa, 4017", + "about": "Voluptate ex enim aliqua ea et proident ipsum est anim nostrud. Duis aliquip voluptate voluptate non aliquip. Elit commodo Lorem aliqua sit elit consectetur reprehenderit in aute minim. Dolor non incididunt do tempor aliquip esse non magna anim eiusmod ut id id.\r\n", + "registered": "2016-08-29T06:23:00 -01:00", + "latitude": -60.325313, + "longitude": 88.598722, + "tags": [ + "est", + "incididunt", + "officia", + "sunt", + "eu", + "ut", + "deserunt" + ], + "friends": [ + { + "id": 0, + "name": "Taylor Walton" + }, + { + "id": 1, + "name": "Celina Mcdonald" + }, + { + "id": 2, + "name": "Berry Rivers" + } + ], + "greeting": "Hello, Mae Payne! You have 4 unread messages.", + "favoriteFruit": "strawberry" + } +]'); + l_expected := json_element_t.parse('[ + { + "_id": "5ce6ec6660565269b16cf836", + "index": 0, + "guid": "c222eda5-d925-4163-89e3-4b0e50d5e297", + "isActive": false, + "balance": "$3,626.25", + "picture": "http://placehold.it/32x32", + "age": 28, + "eyeColor": "green", + "name": "Leigh Munoz", + "gender": "female", + "company": "OATFARM", + "email": "leighmunoz@oatfarm.com", + "phone": "+1 (969) 545-2708", + "address": "218 Mersereau Court, Homeworth, Connecticut, 4423", + "about": "Eiusmod exercitation incididunt ea incididunt anim voluptate. Duis laboris ut Lorem pariatur tempor voluptate occaecat laboris. Enim duis excepteur cillum ullamco pariatur sint. Dolor labore qui ullamco deserunt do consectetur labore velit occaecat officia incididunt Lorem dolore. Pariatur dolor voluptate ex adipisicing labore quis aliquip aliquip. Culpa tempor proident nisi occaecat aliqua mollit ullamco nisi cillum ipsum exercitation quis excepteur. Consequat officia ex ipsum id consequat deserunt sunt id nostrud magna.\r\n", + "registered": "2018-10-08T10:24:07 -01:00", + "latitude": -42.796797, + "longitude": -14.220273, + "tags": [ + "ex", + "elit", + "consectetur", + "ipsum", + "aute", + "ipsum", + "Lorem" + ], + "friends": [ + { + "id": 0, + "name": "Selena Dunn" + }, + { + "id": 1, + "name": "Wilda Haynes" + }, + { + "id": 2, + "name": "Calderon Long" + } + ], + "greeting": "Hello, Leigh Munoz! You have 6 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "5ce6ec66383ddbf3c400e3ed", + "index": 1, + "guid": "2e778803-50d3-411f-b34d-47d0f19d03f7", + "isActive": false, + "balance": "$2,299.28", + "picture": "http://placehold.it/32x32", + "age": 23, + "eyeColor": "blue", + "name": "Velez Drake", + "gender": "male", + "company": "GENMY", + "email": "velezdrake@genmy.com", + "phone": "+1 (870) 564-2219", + "address": "526 Erskine Loop, Websterville, Nebraska, 1970", + "about": "Consectetur Lorem do ex est dolor. Consectetur do tempor amet elit. Amet dolore cupidatat Lorem sunt reprehenderit.\r\n", + "registered": "2017-11-24T04:42:37 -00:00", + "latitude": -45.78579, + "longitude": 142.062878, + "tags": [ + "do", + "esse", + "nisi", + "sunt", + "et", + "nisi", + "nostrud" + ], + "friends": [ + { + "id": 0, + "name": "Bessie Schmidt" + }, + { + "id": 1, + "name": "Harriett Lyons" + }, + { + "id": 2, + "name": "Jerry Gonzales" + } + ], + "greeting": "Hello, Velez Drake! You have 1 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ce6ec660a8b5f95ed543305", + "index": 2, + "guid": "bb0eaa88-f7fd-4b72-8538-8c0b4595bcec", + "isActive": true, + "balance": "$3,085.28", + "picture": "http://placehold.it/32x32", + "age": 36, + "eyeColor": "green", + "name": "Gallegos Dominguez", + "gender": "male", + "company": "QOT", + "email": "gallegosdominguez@qot.com", + "phone": "+1 (947) 581-3675", + "address": "375 Temple Court, Beaulieu, Minnesota, 3880", + "about": "Qui consequat est aliquip esse minim Lorem qui quis. Enim consequat anim culpa consequat ex incididunt ad incididunt est id excepteur nulla culpa. Aliqua enim enim exercitation anim velit occaecat voluptate qui minim ut ullamco fugiat. Anim voluptate nulla minim labore dolore eu veniam. Exercitation sint eiusmod aute aliqua magna aliqua pariatur Lorem velit pariatur ex duis.\r\n", + "registered": "2019-03-11T12:36:55 -00:00", + "latitude": -1.619328, + "longitude": -160.580052, + "tags": [ + "ipsum", + "reprehenderit", + "id", + "aliqua", + "ad", + "do", + "sunt" + ], + "friends": [ + { + "id": 0, + "name": "Justice Bruce" + }, + { + "id": 1, + "name": "Alta Clements" + }, + { + "id": 2, + "name": "Amy Hobbs" + } + ], + "greeting": "Hello, Gallegos Dominguez! You have 10 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "5ce6ec6600fb7aaee2d1243e", + "index": 3, + "guid": "4a4363b5-9d65-4b22-9b58-a5c8c1c5bd5d", + "isActive": false, + "balance": "$3,152.70", + "picture": "http://placehold.it/32x32", + "age": 37, + "eyeColor": "green", + "name": "Bobbie Baldwin", + "gender": "female", + "company": "IDEGO", + "email": "bobbiebaldwin@idego.com", + "phone": "+1 (937) 501-3123", + "address": "271 Coles Street, Deltaville, Massachusetts, 349", + "about": "Dolor labore quis Lorem eiusmod duis adipisicing ut. Aute aute aliquip exercitation eiusmod veniam ullamco irure sit est. Ut Lorem incididunt do sint laborum cillum Lorem commodo duis. Dolor nulla ad consectetur non cillum. Est excepteur esse mollit elit laborum ullamco exercitation sit esse. Reprehenderit occaecat ad ad reprehenderit adipisicing non Lorem ipsum fugiat culpa. Do quis non exercitation ea magna elit non.\r\n", + "registered": "2014-06-25T07:44:03 -01:00", + "latitude": -70.045195, + "longitude": 117.328462, + "tags": [ + "anim", + "excepteur", + "aliqua", + "mollit", + "non", + "in", + "adipisicing" + ], + "friends": [ + { + "id": 0, + "name": "Lora Little" + }, + { + "id": 1, + "name": "Stanton Pollard" + }, + { + "id": 2, + "name": "Bernice Knowles" + } + ], + "greeting": "Hello, Bobbie Baldwin! You have 5 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ce6ec660585cbb589b34fc8", + "index": 4, + "guid": "18547241-6fd0-466d-9f79-21aeb0485294", + "isActive": false, + "balance": "$3,853.86", + "picture": "http://placehold.it/32x32", + "age": 32, + "eyeColor": "blue", + "name": "Erika Benton", + "gender": "female", + "company": "SURETECH", + "email": "erikabenton@suretech.com", + "phone": "+1 (833) 472-2277", + "address": "893 Jamison Lane, Grayhawk, Illinois, 1820", + "about": "Ullamco nisi quis esse fugiat eu proident nisi cupidatat reprehenderit nostrud nulla laborum duis. Duis quis ipsum ad voluptate enim. Et excepteur irure proident adipisicing enim eu veniam aliquip nostrud amet sit est. Non laborum reprehenderit qui ullamco occaecat elit sunt ea nostrud reprehenderit incididunt sunt.\r\n", + "registered": "2018-01-19T11:58:53 -00:00", + "latitude": -44.595301, + "longitude": 100.938225, + "tags": [ + "cupidatat", + "aliqua", + "nostrud", + "nostrud", + "ipsum", + "ipsum", + "commodo" + ], + "friends": [ + { + "id": 0, + "name": "Addie Benjamin" + }, + { + "id": 1, + "name": "Brock Nolan" + }, + { + "id": 2, + "name": "Betty Suarez" + } + ], + "greeting": "Hello, Erika Benton! You have 5 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ce6ec66ff15753596332021", + "index": 5, + "guid": "f865dabb-4871-4f29-9c56-17361d254f39", + "isActive": true, + "balance": "$3,474.90", + "picture": "http://placehold.it/32x32", + "age": 32, + "eyeColor": "blue", + "name": "Rice Owens", + "gender": "male", + "company": "ACIUM", + "email": "riceowens@acium.com", + "phone": "+1 (975) 576-3718", + "address": "400 Halleck Street, Lafferty, District Of Columbia, 495", + "about": "Cupidatat laborum mollit non eu aute amet consectetur aliqua officia consectetur consequat. Tempor labore pariatur Lorem sint quis laborum est dolore et. Est ipsum incididunt eiusmod enim nostrud laboris duis est enim proident do laborum id culpa.\r\n", + "registered": "2018-05-06T02:43:06 -01:00", + "latitude": 2.843708, + "longitude": -3.301217, + "tags": [ + "laboris", + "velit", + "dolore", + "sunt", + "ad", + "aliqua", + "duis" + ], + "friends": [ + { + "id": 0, + "name": "Ramirez King" + }, + { + "id": 1, + "name": "Jeannie Boyer" + }, + { + "id": 2, + "name": "Deloris Jensen" + } + ], + "greeting": "Hello, Rice Owens! You have 9 unread messages.", + "favoriteFruit": "banana" + } +]'); + + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + --Assert + l_expected_message := q'[%Extra property: object on path: $[5] +%Actual value: "5ce6ec46cb9977b050f15d97" was expected to be: "5ce6ec6660565269b16cf836" on path: $[0]."_id" +%Actual value: "5ce6ec469ba57bef5c421021" was expected to be: "5ce6ec66383ddbf3c400e3ed" on path: $[1]."_id" +%Actual value: "5ce6ec4632328a654d592cb6" was expected to be: "5ce6ec6600fb7aaee2d1243e" on path: $[3]."_id" +%Actual value: "5ce6ec464e6f8751e75ed29f" was expected to be: "5ce6ec660a8b5f95ed543305" on path: $[2]."_id" +%Actual value: "5ce6ec46d9dbfbf9b184cee7" was expected to be: "5ce6ec660585cbb589b34fc8" on path: $[4]."_id" +%Actual value: "59be5b73-fffe-4a4f-acea-65c5abbdb53c" was expected to be: "2e778803-50d3-411f-b34d-47d0f19d03f7" on path: $[1]."guid" +%Actual value: "9dece65b-6b48-4960-880b-7795ff63c81c" was expected to be: "18547241-6fd0-466d-9f79-21aeb0485294" on path: $[4]."guid" +%Actual value: "42e07b71-b769-4078-b226-f79048b75bd2" was expected to be: "bb0eaa88-f7fd-4b72-8538-8c0b4595bcec" on path: $[2]."guid" +%Actual value: "6b9124a9-fbde-4c60-8dac-e296f5daa3c4" was expected to be: "4a4363b5-9d65-4b22-9b58-a5c8c1c5bd5d" on path: $[3]."guid" +%Actual value: "1acb2b6b-15b5-4747-a62f-db477e18df61" was expected to be: "c222eda5-d925-4163-89e3-4b0e50d5e297" on path: $[0]."guid" +%Actual value: FALSE was expected to be: TRUE on path: $[2]."isActive" +%Actual value: TRUE was expected to be: FALSE on path: $[3]."isActive" +%Actual value: TRUE was expected to be: FALSE on path: $[1]."isActive" +%Actual value: "$3,895.35" was expected to be: "$2,299.28" on path: $[1]."balance" +%Actual value: "$1,443.80" was expected to be: "$3,626.25" on path: $[0]."balance" +%Actual value: "$3,366.81" was expected to be: "$3,085.28" on path: $[2]."balance" +%Actual value: "$2,927.54" was expected to be: "$3,853.86" on path: $[4]."balance" +%Actual value: "$2,374.96" was expected to be: "$3,152.70" on path: $[3]."balance" +%Actual value: 23 was expected to be: 36 on path: $[2]."age"%]'; + + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + ut.expect(l_actual_message).to_be_like('%Diff: 133 differences found, showing first 20%'); + ut.expect(l_actual_message).to_be_like('%1 missing properties%'); + ut.expect(l_actual_message).to_be_like('%132 unequal values%'); + end; + + procedure check_json_objects is + l_expected json_object_t; + l_actual json_object_t; + begin + l_expected := json_object_t('{ "name" : "Bond", "proffesion" : "spy", "drink" : "martini"}'); + l_actual := json_object_t('{ "proffesion" : "spy","name" : "Bond", "drink" : "martini"}'); + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure check_json_arrays is + l_expected json_array_t; + l_actual json_array_t; + begin + l_expected := json_array_t('[ {"name" : "Bond", "proffesion" : "spy", "drink" : "martini"} , {"name" : "Kloss", "proffesion" : "spy", "drink" : "beer"} ]'); + l_actual := json_array_t('[ {"name" : "Bond", "proffesion" : "spy", "drink" : "martini"} , {"name" : "Kloss", "proffesion" : "spy", "drink" : "beer"} ]'); + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + $if dbms_db_version.version >= 21 $then + + procedure success_on_same_data_njson + as + l_actual json; + begin + -- Arrange + l_actual := json(' { + "Actors": [ + { + "name": "Tom Cruise", + "age": 56, + "Born At": "Syracuse, NY", + "Birthdate": "July 3, 1962", + "photo": "https://jsonformatter.org/img/tom-cruise.jpg", + "wife": null, + "weight": 67.5, + "hasChildren": true, + "hasGreyHair": false, + "children": [ + "Suri", + "Isabella Jane", + "Connor" + ] + }, + { + "name": "Robert Downey Jr.", + "age": 53, + "Born At": "New York City, NY", + "Birthdate": "April 4, 1965", + "photo": "https://jsonformatter.org/img/Robert-Downey-Jr.jpg", + "wife": "Susan Downey", + "weight": 77.1, + "hasChildren": true, + "hasGreyHair": false, + "children": [ + "Indio Falconer", + "Avri Roel", + "Exton Elias" + ] + } + ] + }'); + + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_actual ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure fail_on_diff_data_njson + as + l_expected json; + l_actual json; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + -- Arrange + l_actual := json('{"Aidan Gillen": {"array": ["Game of Thrones","The Wire"],"string": "some string","int": "2","otherint": 4, "aboolean": "true", "boolean": false,"object": {"foo": "bar"}},"Amy Ryan": ["In Treatment","The Wire"],"Annie Fitzgerald": ["True Blood","Big Love","The Sopranos","Oz"],"Anwan Glover": ["Treme","The Wire"],"Alexander Skarsg?rd": ["Generation Kill","True Blood"],"Alice Farmer": ["The Corner","Oz","The Wire"]}'); + l_expected := json('{"Aidan Gillen": {"array": ["Game of Thron\"es","The Wire"],"string": "some string","int": 2,"aboolean": true, "boolean": true,"object": {"foo": "bar","object1": {"new prop1": "new prop value"},"object2": {"new prop1": "new prop value"},"object3": {"new prop1": "new prop value"},"object4": {"new prop1": "new prop value"}}},"Amy Ryan": {"one": "In Treatment","two": "The Wire"},"Annie Fitzgerald": ["Big Love","True Blood"],"Anwan Glover": ["Treme","The Wire"],"Alexander Skarsgard": ["Generation Kill","True Blood"], "Clarke Peters": null}'); + + --Act + ut3_develop.ut.expect( l_actual ).to_equal( l_expected ); + --Assert + l_expected_message := q'[%Missing property: "Alexander Skarsg?rd" on path: $ +%Extra property: "Alexander Skarsgard" on path: $ +%Missing property: "Alice Farmer" on path: $ +%Extra property: "Clarke Peters" on path: $ +%Extra property: "one" on path: $."Amy Ryan" +%Missing property: "The Sopranos" on path: $."Annie Fitzgerald"[2] +%Extra property: "two" on path: $."Amy Ryan" +%Missing property: "Oz" on path: $."Annie Fitzgerald"[3] +%Missing property: "otherint" on path: $."Aidan Gillen" +%Extra property: "object1" on path: $."Aidan Gillen"."object" +%Extra property: "object2" on path: $."Aidan Gillen"."object" +%Extra property: "object3" on path: $."Aidan Gillen"."object" +%Extra property: "object4" on path: $."Aidan Gillen"."object" +%Actual type: 'array' was expected to be: 'object' on path: $."Amy Ryan" +%Actual type: 'string' was expected to be: 'number' on path: $."Aidan Gillen"."int" +%Actual type: 'string' was expected to be: 'boolean' on path: $."Aidan Gillen"."aboolean" +%Actual value: "True Blood" was expected to be: "Big Love" on path: $."Annie Fitzgerald"[0] +%Actual value: "Big Love" was expected to be: "True Blood" on path: $."Annie Fitzgerald"[1] +%Actual value: FALSE was expected to be: TRUE on path: $."Aidan Gillen"."boolean" +%Actual value: "Game of Thrones" was expected to be: "Game of Thron\"es" on path: $."Aidan Gillen"."array"[0]%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + ut.expect(l_actual_message).to_be_like('%Diff: 20 differences found%'); + ut.expect(l_actual_message).to_be_like('%13 missing properties%'); + ut.expect(l_actual_message).to_be_like('%4 unequal values%'); + ut.expect(l_actual_message).to_be_like('%3 incorrect types%'); + end; + + + --Please note that by the looks of things the call to json() results in null value being returned. + procedure null_json_variable_njson + as + l_expected json ; + begin + -- Arrange + l_expected := cast (null as json ); + + --Act + ut3_develop.ut.expect( l_expected ).to_be_null; + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure to_have_count_njson as + l_actual json; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + -- Arrange + l_actual := json('{"Aidan Gillen": {"array": ["Game of Thrones","The Wire"],"string": "some string","int": "2","otherint": 4, "aboolean": "true", "boolean": false,"object": {"foo": "bar"}},"Amy Ryan": ["In Treatment","The Wire"],"Annie Fitzgerald": ["True Blood","Big Love","The Sopranos","Oz"],"Anwan Glover": ["Treme","The Wire"],"Alexander Skarsg?rd": ["Generation Kill","True Blood"],"Alice Farmer": ["The Corner","Oz","The Wire"]}'); + + --Act + ut3_develop.ut.expect( l_actual ).to_have_count( 6 ); + + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + + end; + + procedure fail_to_have_count_njson + as + l_actual json; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + -- Arrange + l_actual := json('{"Aidan Gillen": {"array": ["Game of Thrones","The Wire"],"string": "some string","int": "2","otherint": 4, "aboolean": "true", "boolean": false,"object": {"foo": "bar"}},"Amy Ryan": ["In Treatment","The Wire"],"Annie Fitzgerald": ["True Blood","Big Love","The Sopranos","Oz"],"Anwan Glover": ["Treme","The Wire"],"Alexander Skarsg?rd": ["Generation Kill","True Blood"],"Alice Farmer": ["The Corner","Oz","The Wire"]}'); + + --Act + ut3_develop.ut.expect( l_actual ).to_have_count( 2 ); + --Assert + l_expected_message := q'[%Actual: (json [ count = 6 ]) was expected to have [ count = 2 ]%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + + end; + + procedure not_to_have_count_njson + as + l_actual json; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + -- Arrange + l_actual := json('{"Aidan Gillen": {"array": ["Game of Thrones","The Wire"],"string": "some string","int": "2","otherint": 4, "aboolean": "true", "boolean": false,"object": {"foo": "bar"}},"Amy Ryan": ["In Treatment","The Wire"],"Annie Fitzgerald": ["True Blood","Big Love","The Sopranos","Oz"],"Anwan Glover": ["Treme","The Wire"],"Alexander Skarsg?rd": ["Generation Kill","True Blood"],"Alice Farmer": ["The Corner","Oz","The Wire"]}'); + + --Act + ut3_develop.ut.expect( l_actual ).not_to_have_count( 7 ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure fail_not_to_have_count_njson + as + l_actual json; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + -- Arrange + l_actual := json('{"Aidan Gillen": {"array": ["Game of Thrones","The Wire"],"string": "some string","int": "2","otherint": 4, "aboolean": "true", "boolean": false,"object": {"foo": "bar"}},"Amy Ryan": ["In Treatment","The Wire"],"Annie Fitzgerald": ["True Blood","Big Love","The Sopranos","Oz"],"Anwan Glover": ["Treme","The Wire"],"Alexander Skarsg?rd": ["Generation Kill","True Blood"],"Alice Farmer": ["The Corner","Oz","The Wire"]}'); + + --Act + ut3_develop.ut.expect( l_actual ).not_to_have_count( 6 ); + --Assert + l_expected_message := q'[%Actual: json [ count = 6 ] was expected not to have [ count = 6 ]%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + $end + + procedure p_1113_reg_exp_chg_with_act is + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + ut3_develop.ut.expect(json_element_t.parse('{"a":"value a"}')).to_equal(json_element_t.parse('{"a":"value b"}')); + + --Assert + l_expected_message := q'[%Actual: json was expected to equal: json +%Diff: 1 differences found +%1 unequal values +%Actual value: "value a" was expected to be: "value b" on path: $."a"%]'; + + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + +end; +/ diff --git a/test/ut3_user/expectations/test_expectations_json.pks b/test/ut3_user/expectations/test_expectations_json.pks new file mode 100644 index 000000000..410c3050b --- /dev/null +++ b/test/ut3_user/expectations/test_expectations_json.pks @@ -0,0 +1,107 @@ +create or replace package test_expectations_json is + + --%suite(json expectations) + --%suitepath(utplsql.test_user.expectations) + + --%aftereach + procedure cleanup_expectations; + + --%test(Gives success for identical data) + procedure success_on_same_data; + + --%test(Gives failure for different data) + procedure fail_on_diff_data; + + --%test( Json variable is null) + procedure null_json_variable; + + --%test( Json variable is not null) + procedure not_null_json_variable; + + --%test( Fail json variable is null) + procedure fail_null_json_var; + + --%test( Fail json variable is not null) + procedure fail_not_null_json_var; + + --%test(Json string is empty) + procedure empty_json; + + --%test(Json string is not empty) + procedure not_empty_json; + + --%test( Fail json string is empty) + procedure fail_empty_json; + + --%test( Fail json string is not empty) + procedure fail_not_empty_json; + + --%test( Json object to have count ) + procedure to_have_count; + + --%test( Fail Json object to have count) + procedure fail_to_have_count; + + --%test( Json object not to have count) + procedure not_to_have_count; + + --%test( Fail Json object not to have count) + procedure fail_not_to_have_count; + + --%test( Json object to have count on array) + procedure to_have_count_array; + + --%test( Two json use plsql function to extract same pieces and compare) + procedure to_diff_json_extract_same; + + --%test( Two json use plsql function to extract diff pieces and compare) + procedure to_diff_json_extract_diff; + + --%test( Long JSON test same ) + procedure long_json_test; + + --%test( JSON test same semantic content different order ) + procedure json_same_diffrent_ord; + + --%test( Long complex nested JSON test ) + procedure long_json_test2; + + --%test( Long complex json differences ) + procedure long_json_diff; + + --%test( Compare two objects json ) + procedure check_json_objects; + + --%test( Compare two json arrays ) + procedure check_json_arrays; + + $if dbms_db_version.version >= 21 $then + + --%test(Gives success for identical data using native json for 21c and above) + procedure success_on_same_data_njson; + + --%test(Gives failure for different data using native json for 21c and above) + procedure fail_on_diff_data_njson; + + --%test( Json variable is null using native json for 21c and above) + procedure null_json_variable_njson; + + --%test( Json object to have count using native json for 21c and above) + procedure to_have_count_njson; + + --%test( Fail Json object to have count using native json for 21c and above) + procedure fail_to_have_count_njson; + + --%test( Json object not to have count using native json for 21c and above) + procedure not_to_have_count_njson; + + --%test( Fail Json object not to have count using native json for 21c and above) + procedure fail_not_to_have_count_njson; + + $end + + --%test( Regression scenario tests for issue #1113 where the expected has been switched with actual) + procedure p_1113_reg_exp_chg_with_act; + +end; +/ diff --git a/test/core/expectations/test_matchers.pkb b/test/ut3_user/expectations/test_matchers.pkb similarity index 52% rename from test/core/expectations/test_matchers.pkb rename to test/ut3_user/expectations/test_matchers.pkb index 1a15986b9..e1d87d4cb 100644 --- a/test/core/expectations/test_matchers.pkb +++ b/test/ut3_user/expectations/test_matchers.pkb @@ -2,7 +2,7 @@ create or replace package body test_matchers is procedure cleanup_expectations is begin - expectations.cleanup_expectations( ); + ut3_tester_helper.main_helper.clear_expectations( ); end; procedure exec_matcher(a_type varchar2, a_actual_value varchar2, a_expected_value varchar2, a_matcher varchar2, a_result integer, a_prefix varchar2 := null) is @@ -13,13 +13,13 @@ create or replace package body test_matchers is l_actual '||a_type||' := '||a_actual_value||'; l_expected '||a_type||' := '||a_expected_value||'; begin - ut3.ut.expect( l_actual ).'||a_prefix||'to_'||a_matcher||'( l_expected ); + ut3_develop.ut.expect( l_actual ).'||a_prefix||'to_'||a_matcher||'( l_expected ); end;'; execute immediate l_statement; - if a_result = ut3.ut_utils.gc_success then - ut.expect(expectations.failed_expectations_data()).to_be_empty(); + if a_result = ut3_tester_helper.main_helper.gc_success then + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num()).to_equal(0); else - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num()).to_be_greater_than(0); end if; cleanup_expectations(); end exec_matcher; @@ -33,13 +33,13 @@ create or replace package body test_matchers is l_lower '||a_type||' := '||a_expected1_value||'; l_higher '||a_type||' := '||a_expected2_value||'; begin - ut3.ut.expect(l_actual_value).to_be_between(l_lower, l_higher); + ut3_develop.ut.expect(l_actual_value).to_be_between(l_lower, l_higher); end;'; execute immediate l_statement; - if a_result = ut3.ut_utils.gc_success then - ut.expect(expectations.failed_expectations_data()).to_be_empty(); + if a_result = ut3_tester_helper.main_helper.gc_success then + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num()).to_equal(0); else - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num()).to_be_greater_than(0); end if; cleanup_expectations(); end exec_be_between; @@ -53,13 +53,13 @@ create or replace package body test_matchers is l_value1 '||a_type||' := '||a_expected1_value||'; l_value2 '||a_type||' := '||a_expected2_value||'; begin - ut3.ut.expect(l_actual_value).'||a_not_prefix||'to_be_between(l_value1, l_value2); + ut3_develop.ut.expect(l_actual_value).'||a_not_prefix||'to_be_between(l_value1, l_value2); end;'; execute immediate l_statement; - if a_result = ut3.ut_utils.gc_success then - ut.expect(expectations.failed_expectations_data()).to_be_empty(); + if a_result = ut3_tester_helper.main_helper.gc_success then + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num()).to_equal(0); else - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num()).to_be_greater_than(0); end if; cleanup_expectations(); end exec_be_between2; @@ -73,16 +73,17 @@ create or replace package body test_matchers is l_escape_char varchar2(32767) := :a_escape; l_result integer; begin - ut3.ut.expect( l_actual ).' || a_prefix ||q'[to_be_like(l_pattern, l_escape_char); + ut3_develop.ut.expect( l_actual ).' || a_prefix ||q'[to_be_like(l_pattern, l_escape_char); end;]' using a_pattern, a_escape; - if a_result = ut3.ut_utils.gc_success then - ut.expect(expectations.failed_expectations_data()).to_be_empty(); + if a_result = ut3_tester_helper.main_helper.gc_success then + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num()).to_equal(0); else - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num()).to_be_greater_than(0); end if; cleanup_expectations(); end; + procedure exec_match(a_type varchar2, a_actual_value varchar2, a_pattern varchar2, a_modifiers varchar2, a_result integer, a_not_prefix varchar2 default null) is l_statement varchar2(32767); begin @@ -93,13 +94,13 @@ create or replace package body test_matchers is l_modifiers varchar2(32767) := :a_modifiers; l_result integer; begin - ut3.ut.expect( l_actual ).'||a_not_prefix||'to_match(l_pattern, l_modifiers); + ut3_develop.ut.expect( l_actual ).'||a_not_prefix||'to_match(l_pattern, l_modifiers); end;'; execute immediate l_statement using a_pattern, a_modifiers; - if a_result = ut3.ut_utils.gc_success then - ut.expect(expectations.failed_expectations_data()).to_be_empty(); + if a_result = ut3_tester_helper.main_helper.gc_success then + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num()).to_equal(0); else - ut.expect(expectations.failed_expectations_data()).not_to_be_empty(); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num()).to_be_greater_than(0); end if; cleanup_expectations(); end; @@ -108,135 +109,135 @@ create or replace package body test_matchers is begin --failure when value out of range - exec_be_between2('date', 'sysdate', 'sysdate-2', 'sysdate-1', ut3.ut_utils.gc_failure, ''); - exec_be_between2('number', '2.0', '1.99', '1.999', ut3.ut_utils.gc_failure, ''); - exec_be_between2('varchar2(1)', '''c''', '''a''', '''b''', ut3.ut_utils.gc_failure, ''); - exec_be_between2('timestamp', 'systimestamp+1', 'systimestamp-1', 'systimestamp', ut3.ut_utils.gc_failure, ''); - exec_be_between2('timestamp with local time zone', 'systimestamp+1', 'systimestamp-1', 'systimestamp', ut3.ut_utils.gc_failure, ''); - exec_be_between2('timestamp with time zone', 'systimestamp+1', 'systimestamp-1', 'systimestamp', ut3.ut_utils.gc_failure, ''); - exec_be_between2('interval year to month', '''2-2''', '''2-0''', '''2-1''', ut3.ut_utils.gc_failure, ''); - exec_be_between2('interval day to second', '''2 01:00:00''', '''2 00:59:58''', '''2 00:59:59''', ut3.ut_utils.gc_failure, ''); + exec_be_between2('date', 'sysdate', 'sysdate-2', 'sysdate-1', ut3_tester_helper.main_helper.gc_failure, ''); + exec_be_between2('number', '2.0', '1.99', '1.999', ut3_tester_helper.main_helper.gc_failure, ''); + exec_be_between2('varchar2(1)', '''c''', '''a''', '''b''', ut3_tester_helper.main_helper.gc_failure, ''); + exec_be_between2('timestamp', 'systimestamp+1', 'systimestamp-1', 'systimestamp', ut3_tester_helper.main_helper.gc_failure, ''); + exec_be_between2('timestamp with local time zone', 'systimestamp+1', 'systimestamp-1', 'systimestamp', ut3_tester_helper.main_helper.gc_failure, ''); + exec_be_between2('timestamp with time zone', 'systimestamp+1', 'systimestamp-1', 'systimestamp', ut3_tester_helper.main_helper.gc_failure, ''); + exec_be_between2('interval year to month', '''2-2''', '''2-0''', '''2-1''', ut3_tester_helper.main_helper.gc_failure, ''); + exec_be_between2('interval day to second', '''2 01:00:00''', '''2 00:59:58''', '''2 00:59:59''', ut3_tester_helper.main_helper.gc_failure, ''); --success when value in range - exec_be_between2('date', 'sysdate', 'sysdate-1', 'sysdate+1', ut3.ut_utils.gc_success, ''); - exec_be_between2('number', '2.0', '1.99', '2.01', ut3.ut_utils.gc_success, ''); - exec_be_between2('varchar2(1)', '''b''', '''a''', '''c''', ut3.ut_utils.gc_success, ''); - exec_be_between2('timestamp', 'systimestamp', 'systimestamp-1', 'systimestamp+1', ut3.ut_utils.gc_success, ''); - exec_be_between2('timestamp with local time zone', 'systimestamp', 'systimestamp-1', 'systimestamp+1', ut3.ut_utils.gc_success, ''); - exec_be_between2('timestamp with time zone', 'systimestamp', 'systimestamp-1', 'systimestamp+1', ut3.ut_utils.gc_success, ''); - exec_be_between2('interval year to month', '''2-1''', '''2-0''', '''2-2''', ut3.ut_utils.gc_success, ''); - exec_be_between2('interval day to second', '''2 01:00:00''', '''2 00:59:58''', '''2 01:00:01''', ut3.ut_utils.gc_success, ''); + exec_be_between2('date', 'sysdate', 'sysdate-1', 'sysdate+1', ut3_tester_helper.main_helper.gc_success, ''); + exec_be_between2('number', '2.0', '1.99', '2.01', ut3_tester_helper.main_helper.gc_success, ''); + exec_be_between2('varchar2(1)', '''b''', '''a''', '''c''', ut3_tester_helper.main_helper.gc_success, ''); + exec_be_between2('timestamp', 'systimestamp', 'systimestamp-1', 'systimestamp+1', ut3_tester_helper.main_helper.gc_success, ''); + exec_be_between2('timestamp with local time zone', 'systimestamp', 'systimestamp-1', 'systimestamp+1', ut3_tester_helper.main_helper.gc_success, ''); + exec_be_between2('timestamp with time zone', 'systimestamp', 'systimestamp-1', 'systimestamp+1', ut3_tester_helper.main_helper.gc_success, ''); + exec_be_between2('interval year to month', '''2-1''', '''2-0''', '''2-2''', ut3_tester_helper.main_helper.gc_success, ''); + exec_be_between2('interval day to second', '''2 01:00:00''', '''2 00:59:58''', '''2 01:00:01''', ut3_tester_helper.main_helper.gc_success, ''); --success when value not in range - exec_be_between2('date', 'sysdate', 'sysdate-2', 'sysdate-1', ut3.ut_utils.gc_success, 'not_'); - exec_be_between2('number', '2.0', '1.99', '1.999', ut3.ut_utils.gc_success, 'not_'); - exec_be_between2('varchar2(1)', '''c''', '''a''', '''b''', ut3.ut_utils.gc_success, 'not_'); - exec_be_between2('timestamp', 'systimestamp+1', 'systimestamp-1', 'systimestamp', ut3.ut_utils.gc_success, 'not_'); - exec_be_between2('timestamp with local time zone', 'systimestamp+1', 'systimestamp-1', 'systimestamp', ut3.ut_utils.gc_success, 'not_'); - exec_be_between2('timestamp with time zone', 'systimestamp+1', 'systimestamp-1', 'systimestamp', ut3.ut_utils.gc_success, 'not_'); - exec_be_between2('interval year to month', '''2-2''', '''2-0''', '''2-1''', ut3.ut_utils.gc_success, 'not_'); - exec_be_between2('interval day to second', '''2 01:00:00''', '''2 00:59:58''', '''2 00:59:59''', ut3.ut_utils.gc_success, 'not_'); + exec_be_between2('date', 'sysdate', 'sysdate-2', 'sysdate-1', ut3_tester_helper.main_helper.gc_success, 'not_'); + exec_be_between2('number', '2.0', '1.99', '1.999', ut3_tester_helper.main_helper.gc_success, 'not_'); + exec_be_between2('varchar2(1)', '''c''', '''a''', '''b''', ut3_tester_helper.main_helper.gc_success, 'not_'); + exec_be_between2('timestamp', 'systimestamp+1', 'systimestamp-1', 'systimestamp', ut3_tester_helper.main_helper.gc_success, 'not_'); + exec_be_between2('timestamp with local time zone', 'systimestamp+1', 'systimestamp-1', 'systimestamp', ut3_tester_helper.main_helper.gc_success, 'not_'); + exec_be_between2('timestamp with time zone', 'systimestamp+1', 'systimestamp-1', 'systimestamp', ut3_tester_helper.main_helper.gc_success, 'not_'); + exec_be_between2('interval year to month', '''2-2''', '''2-0''', '''2-1''', ut3_tester_helper.main_helper.gc_success, 'not_'); + exec_be_between2('interval day to second', '''2 01:00:00''', '''2 00:59:58''', '''2 00:59:59''', ut3_tester_helper.main_helper.gc_success, 'not_'); --failure when value not out of range - exec_be_between2('date', 'sysdate', 'sysdate-1', 'sysdate+1', ut3.ut_utils.gc_failure, 'not_'); - exec_be_between2('number', '2.0', '1.99', '2.01', ut3.ut_utils.gc_failure, 'not_'); - exec_be_between2('varchar2(1)', '''b''', '''a''', '''c''', ut3.ut_utils.gc_failure, 'not_'); - exec_be_between2('timestamp', 'systimestamp', 'systimestamp-1', 'systimestamp+1', ut3.ut_utils.gc_failure, 'not_'); - exec_be_between2('timestamp with local time zone', 'systimestamp', 'systimestamp-1', 'systimestamp+1', ut3.ut_utils.gc_failure, 'not_'); - exec_be_between2('timestamp with time zone', 'systimestamp', 'systimestamp-1', 'systimestamp+1', ut3.ut_utils.gc_failure, 'not_'); - exec_be_between2('interval year to month', '''2-1''', '''2-0''', '''2-2''', ut3.ut_utils.gc_failure, 'not_'); - exec_be_between2('interval day to second', '''2 01:00:00''', '''2 00:59:58''', '''2 01:00:01''', ut3.ut_utils.gc_failure, 'not_'); + exec_be_between2('date', 'sysdate', 'sysdate-1', 'sysdate+1', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_between2('number', '2.0', '1.99', '2.01', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_between2('varchar2(1)', '''b''', '''a''', '''c''', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_between2('timestamp', 'systimestamp', 'systimestamp-1', 'systimestamp+1', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_between2('timestamp with local time zone', 'systimestamp', 'systimestamp-1', 'systimestamp+1', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_between2('timestamp with time zone', 'systimestamp', 'systimestamp-1', 'systimestamp+1', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_between2('interval year to month', '''2-1''', '''2-0''', '''2-2''', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_between2('interval day to second', '''2 01:00:00''', '''2 00:59:58''', '''2 01:00:01''', ut3_tester_helper.main_helper.gc_failure, 'not_'); --failure when value is null - exec_be_between2('date', 'null', 'sysdate-1', 'sysdate+1', ut3.ut_utils.gc_failure, ''); - exec_be_between2('number', 'null', '1.99', '2.01', ut3.ut_utils.gc_failure, ''); - exec_be_between2('varchar2(1)', 'null', '''a''', '''c''', ut3.ut_utils.gc_failure, ''); - exec_be_between2('timestamp', 'null', 'systimestamp-1', 'systimestamp+1', ut3.ut_utils.gc_failure, ''); - exec_be_between2('timestamp with local time zone', 'null', 'systimestamp-1', 'systimestamp+1', ut3.ut_utils.gc_failure, ''); - exec_be_between2('timestamp with time zone', 'null', 'systimestamp-1', 'systimestamp+1', ut3.ut_utils.gc_failure, ''); - exec_be_between2('interval year to month', 'null', '''2-0''', '''2-2''', ut3.ut_utils.gc_failure, ''); - exec_be_between2('interval day to second', 'null', '''2 00:59:58''', '''2 01:00:01''', ut3.ut_utils.gc_failure, ''); + exec_be_between2('date', 'null', 'sysdate-1', 'sysdate+1', ut3_tester_helper.main_helper.gc_failure, ''); + exec_be_between2('number', 'null', '1.99', '2.01', ut3_tester_helper.main_helper.gc_failure, ''); + exec_be_between2('varchar2(1)', 'null', '''a''', '''c''', ut3_tester_helper.main_helper.gc_failure, ''); + exec_be_between2('timestamp', 'null', 'systimestamp-1', 'systimestamp+1', ut3_tester_helper.main_helper.gc_failure, ''); + exec_be_between2('timestamp with local time zone', 'null', 'systimestamp-1', 'systimestamp+1', ut3_tester_helper.main_helper.gc_failure, ''); + exec_be_between2('timestamp with time zone', 'null', 'systimestamp-1', 'systimestamp+1', ut3_tester_helper.main_helper.gc_failure, ''); + exec_be_between2('interval year to month', 'null', '''2-0''', '''2-2''', ut3_tester_helper.main_helper.gc_failure, ''); + exec_be_between2('interval day to second', 'null', '''2 00:59:58''', '''2 01:00:01''', ut3_tester_helper.main_helper.gc_failure, ''); - exec_be_between2('date', 'null', 'sysdate-2', 'sysdate-1', ut3.ut_utils.gc_failure, 'not_'); - exec_be_between2('number', 'null', '1.99', '1.999', ut3.ut_utils.gc_failure, 'not_'); - exec_be_between2('varchar2(1)', 'null', '''a''', '''b''', ut3.ut_utils.gc_failure, 'not_'); - exec_be_between2('timestamp', 'null', 'systimestamp-1', 'systimestamp', ut3.ut_utils.gc_failure, 'not_'); - exec_be_between2('timestamp with local time zone', 'null', 'systimestamp-1', 'systimestamp', ut3.ut_utils.gc_failure, 'not_'); - exec_be_between2('timestamp with time zone', 'null', 'systimestamp-1', 'systimestamp', ut3.ut_utils.gc_failure, 'not_'); - exec_be_between2('interval year to month', 'null', '''2-0''', '''2-1''', ut3.ut_utils.gc_failure, 'not_'); - exec_be_between2('interval day to second', 'null', '''2 00:59:58''', '''2 00:59:59''', ut3.ut_utils.gc_failure, 'not_'); + exec_be_between2('date', 'null', 'sysdate-2', 'sysdate-1', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_between2('number', 'null', '1.99', '1.999', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_between2('varchar2(1)', 'null', '''a''', '''b''', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_between2('timestamp', 'null', 'systimestamp-1', 'systimestamp', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_between2('timestamp with local time zone', 'null', 'systimestamp-1', 'systimestamp', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_between2('timestamp with time zone', 'null', 'systimestamp-1', 'systimestamp', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_between2('interval year to month', 'null', '''2-0''', '''2-1''', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_between2('interval day to second', 'null', '''2 00:59:58''', '''2 00:59:59''', ut3_tester_helper.main_helper.gc_failure, 'not_'); --failure when lower bound is null - exec_be_between2('date', 'sysdate', 'null', 'sysdate+1', ut3.ut_utils.gc_failure, ''); - exec_be_between2('number', '2.0', 'null', '2.01', ut3.ut_utils.gc_failure, ''); - exec_be_between2('varchar2(1)', '''b''', 'null', '''c''', ut3.ut_utils.gc_failure, ''); - exec_be_between2('timestamp', 'systimestamp', 'null', 'systimestamp+1', ut3.ut_utils.gc_failure, ''); - exec_be_between2('timestamp with local time zone', 'systimestamp', 'null', 'systimestamp+1', ut3.ut_utils.gc_failure, ''); - exec_be_between2('timestamp with time zone', 'systimestamp', 'null', 'systimestamp+1', ut3.ut_utils.gc_failure, ''); - exec_be_between2('interval year to month', '''2-1''', 'null', '''2-2''', ut3.ut_utils.gc_failure, ''); - exec_be_between2('interval day to second', '''2 01:00:00''', 'null', '''2 01:00:01''', ut3.ut_utils.gc_failure, ''); + exec_be_between2('date', 'sysdate', 'null', 'sysdate+1', ut3_tester_helper.main_helper.gc_failure, ''); + exec_be_between2('number', '2.0', 'null', '2.01', ut3_tester_helper.main_helper.gc_failure, ''); + exec_be_between2('varchar2(1)', '''b''', 'null', '''c''', ut3_tester_helper.main_helper.gc_failure, ''); + exec_be_between2('timestamp', 'systimestamp', 'null', 'systimestamp+1', ut3_tester_helper.main_helper.gc_failure, ''); + exec_be_between2('timestamp with local time zone', 'systimestamp', 'null', 'systimestamp+1', ut3_tester_helper.main_helper.gc_failure, ''); + exec_be_between2('timestamp with time zone', 'systimestamp', 'null', 'systimestamp+1', ut3_tester_helper.main_helper.gc_failure, ''); + exec_be_between2('interval year to month', '''2-1''', 'null', '''2-2''', ut3_tester_helper.main_helper.gc_failure, ''); + exec_be_between2('interval day to second', '''2 01:00:00''', 'null', '''2 01:00:01''', ut3_tester_helper.main_helper.gc_failure, ''); - exec_be_between2('date', 'sysdate', 'null', 'sysdate-1', ut3.ut_utils.gc_failure, 'not_'); - exec_be_between2('number', '2.0', 'null', '1.999', ut3.ut_utils.gc_failure, 'not_'); - exec_be_between2('varchar2(1)', '''b''', 'null', '''b''', ut3.ut_utils.gc_failure, 'not_'); - exec_be_between2('timestamp', 'systimestamp+1', 'null', 'systimestamp', ut3.ut_utils.gc_failure, 'not_'); - exec_be_between2('timestamp with local time zone', 'systimestamp+1', 'null', 'systimestamp', ut3.ut_utils.gc_failure, 'not_'); - exec_be_between2('timestamp with time zone', 'systimestamp+1', 'null', 'systimestamp', ut3.ut_utils.gc_failure, 'not_'); - exec_be_between2('interval year to month', '''2-2''', 'null', '''2-1''', ut3.ut_utils.gc_failure, 'not_'); - exec_be_between2('interval day to second', '''2 01:00:00''', 'null', '''2 00:59:59''', ut3.ut_utils.gc_failure, 'not_'); + exec_be_between2('date', 'sysdate', 'null', 'sysdate-1', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_between2('number', '2.0', 'null', '1.999', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_between2('varchar2(1)', '''b''', 'null', '''b''', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_between2('timestamp', 'systimestamp+1', 'null', 'systimestamp', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_between2('timestamp with local time zone', 'systimestamp+1', 'null', 'systimestamp', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_between2('timestamp with time zone', 'systimestamp+1', 'null', 'systimestamp', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_between2('interval year to month', '''2-2''', 'null', '''2-1''', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_between2('interval day to second', '''2 01:00:00''', 'null', '''2 00:59:59''', ut3_tester_helper.main_helper.gc_failure, 'not_'); --Fails for unsupported data-type - exec_be_between2('clob', '''b''', '''a''', '''c''', ut3.ut_utils.gc_failure, ''); + exec_be_between2('clob', '''b''', '''a''', '''c''', ut3_tester_helper.main_helper.gc_failure, ''); end; procedure test_match is begin - exec_match('varchar2(100)', '''Stephen''', '^Ste(v|ph)en$', '', ut3.ut_utils.gc_success); - exec_match('varchar2(100)', '''sTEPHEN''', '^Ste(v|ph)en$', 'i', ut3.ut_utils.gc_success); - exec_match('clob', 'to_clob(rpad('', '',32767)||''Stephen'')', 'Ste(v|ph)en$', '', ut3.ut_utils.gc_success); - exec_match('clob', 'to_clob(rpad('', '',32767)||''sTEPHEN'')', 'Ste(v|ph)en$', 'i', ut3.ut_utils.gc_success); + exec_match('varchar2(100)', '''Stephen''', '^Ste(v|ph)en$', '', ut3_tester_helper.main_helper.gc_success); + exec_match('varchar2(100)', '''sTEPHEN''', '^Ste(v|ph)en$', 'i', ut3_tester_helper.main_helper.gc_success); + exec_match('clob', 'to_clob(rpad('', '',32767)||''Stephen'')', 'Ste(v|ph)en$', '', ut3_tester_helper.main_helper.gc_success); + exec_match('clob', 'to_clob(rpad('', '',32767)||''sTEPHEN'')', 'Ste(v|ph)en$', 'i', ut3_tester_helper.main_helper.gc_success); - exec_match('varchar2(100)', '''Stephen''', '^Steven$', '', ut3.ut_utils.gc_failure); - exec_match('varchar2(100)', '''sTEPHEN''', '^Steven$', 'i', ut3.ut_utils.gc_failure); - exec_match('clob', 'to_clob(rpad('', '',32767)||''Stephen'')', '^Stephen', '', ut3.ut_utils.gc_failure); - exec_match('clob', 'to_clob(rpad('', '',32767)||''sTEPHEN'')', '^Stephen', 'i', ut3.ut_utils.gc_failure); + exec_match('varchar2(100)', '''Stephen''', '^Steven$', '', ut3_tester_helper.main_helper.gc_failure); + exec_match('varchar2(100)', '''sTEPHEN''', '^Steven$', 'i', ut3_tester_helper.main_helper.gc_failure); + exec_match('clob', 'to_clob(rpad('', '',32767)||''Stephen'')', '^Stephen', '', ut3_tester_helper.main_helper.gc_failure); + exec_match('clob', 'to_clob(rpad('', '',32767)||''sTEPHEN'')', '^Stephen', 'i', ut3_tester_helper.main_helper.gc_failure); - exec_match('varchar2(100)', '''Stephen''', '^Ste(v|ph)en$', '', ut3.ut_utils.gc_failure, 'not_'); - exec_match('varchar2(100)', '''sTEPHEN''', '^Ste(v|ph)en$', 'i', ut3.ut_utils.gc_failure, 'not_'); - exec_match('clob', 'to_clob(rpad('', '',32767)||''Stephen'')', 'Ste(v|ph)en$', '', ut3.ut_utils.gc_failure, 'not_'); - exec_match('clob', 'to_clob(rpad('', '',32767)||''sTEPHEN'')', 'Ste(v|ph)en$', 'i', ut3.ut_utils.gc_failure, 'not_'); + exec_match('varchar2(100)', '''Stephen''', '^Ste(v|ph)en$', '', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_match('varchar2(100)', '''sTEPHEN''', '^Ste(v|ph)en$', 'i', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_match('clob', 'to_clob(rpad('', '',32767)||''Stephen'')', 'Ste(v|ph)en$', '', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_match('clob', 'to_clob(rpad('', '',32767)||''sTEPHEN'')', 'Ste(v|ph)en$', 'i', ut3_tester_helper.main_helper.gc_failure, 'not_'); - exec_match('varchar2(100)', '''Stephen''', '^Steven$', '', ut3.ut_utils.gc_success, 'not_'); - exec_match('varchar2(100)', '''sTEPHEN''', '^Steven$', 'i', ut3.ut_utils.gc_success, 'not_'); - exec_match('clob', 'to_clob(rpad('', '',32767)||''Stephen'')', '^Stephen', '', ut3.ut_utils.gc_success, 'not_'); - exec_match('clob', 'to_clob(rpad('', '',32767)||''sTEPHEN'')', '^Stephen', 'i', ut3.ut_utils.gc_success, 'not_'); + exec_match('varchar2(100)', '''Stephen''', '^Steven$', '', ut3_tester_helper.main_helper.gc_success, 'not_'); + exec_match('varchar2(100)', '''sTEPHEN''', '^Steven$', 'i', ut3_tester_helper.main_helper.gc_success, 'not_'); + exec_match('clob', 'to_clob(rpad('', '',32767)||''Stephen'')', '^Stephen', '', ut3_tester_helper.main_helper.gc_success, 'not_'); + exec_match('clob', 'to_clob(rpad('', '',32767)||''sTEPHEN'')', '^Stephen', 'i', ut3_tester_helper.main_helper.gc_success, 'not_'); --Fails for unsupported data-type - exec_match('number', '12345', '^123.*', 'i', ut3.ut_utils.gc_failure); + exec_match('number', '12345', '^123.*', 'i', ut3_tester_helper.main_helper.gc_failure); end; procedure test_be_like is begin - exec_be_like('varchar2(100)', '''Stephen_King''', 'Ste__en%', '', ut3.ut_utils.gc_success); - exec_be_like('varchar2(100)', '''Stephen_King''', 'Ste__en\_K%', '\', ut3.ut_utils.gc_success); - exec_be_like('clob', 'to_clob(rpad(''a'',32767,''a'')||''Stephen_King'')', 'a%Ste__en%', '', ut3.ut_utils.gc_success); - exec_be_like('clob', 'to_clob(rpad(''a'',32767,''a'')||''Stephen_King'')', 'a%Ste__en\_K%', '\', ut3.ut_utils.gc_success); + exec_be_like('varchar2(100)', '''Stephen_King''', 'Ste__en%', '', ut3_tester_helper.main_helper.gc_success); + exec_be_like('varchar2(100)', '''Stephen_King''', 'Ste__en\_K%', '\', ut3_tester_helper.main_helper.gc_success); + exec_be_like('clob', 'to_clob(rpad(''a'',32767,''a'')||''Stephen_King'')', 'a%Ste__en%', '', ut3_tester_helper.main_helper.gc_success); + exec_be_like('clob', 'to_clob(rpad(''a'',32767,''a'')||''Stephen_King'')', 'a%Ste__en\_K%', '\', ut3_tester_helper.main_helper.gc_success); - exec_be_like('varchar2(100)', '''Stephen_King''', 'Ste_en%', '', ut3.ut_utils.gc_failure); - exec_be_like('varchar2(100)', '''Stephen_King''', 'Stephe\__%', '\', ut3.ut_utils.gc_failure); - exec_be_like('clob', 'to_clob(rpad(''a'',32767,''a'')||''Stephen_King'')', 'a%Ste_en%', '', ut3.ut_utils.gc_failure); - exec_be_like('clob', 'to_clob(rpad(''a'',32767,''a'')||''Stephen_King'')', 'a%Stephe\__%', '\', ut3.ut_utils.gc_failure); + exec_be_like('varchar2(100)', '''Stephen_King''', 'Ste_en%', '', ut3_tester_helper.main_helper.gc_failure); + exec_be_like('varchar2(100)', '''Stephen_King''', 'Stephe\__%', '\', ut3_tester_helper.main_helper.gc_failure); + exec_be_like('clob', 'to_clob(rpad(''a'',32767,''a'')||''Stephen_King'')', 'a%Ste_en%', '', ut3_tester_helper.main_helper.gc_failure); + exec_be_like('clob', 'to_clob(rpad(''a'',32767,''a'')||''Stephen_King'')', 'a%Stephe\__%', '\', ut3_tester_helper.main_helper.gc_failure); - exec_be_like('varchar2(100)', '''Stephen_King''', 'Ste__en%', '', ut3.ut_utils.gc_failure, 'not_'); - exec_be_like('varchar2(100)', '''Stephen_King''', 'Ste__en\_K%', '\', ut3.ut_utils.gc_failure, 'not_'); - exec_be_like('clob', 'to_clob(rpad(''a'',32767,''a'')||''Stephen_King'')', 'a%Ste__en%', '', ut3.ut_utils.gc_failure, 'not_'); - exec_be_like('clob', 'to_clob(rpad(''a'',32767,''a'')||''Stephen_King'')', 'a%Ste__en\_K%', '\', ut3.ut_utils.gc_failure, 'not_'); + exec_be_like('varchar2(100)', '''Stephen_King''', 'Ste__en%', '', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_like('varchar2(100)', '''Stephen_King''', 'Ste__en\_K%', '\', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_like('clob', 'to_clob(rpad(''a'',32767,''a'')||''Stephen_King'')', 'a%Ste__en%', '', ut3_tester_helper.main_helper.gc_failure, 'not_'); + exec_be_like('clob', 'to_clob(rpad(''a'',32767,''a'')||''Stephen_King'')', 'a%Ste__en\_K%', '\', ut3_tester_helper.main_helper.gc_failure, 'not_'); - exec_be_like('varchar2(100)', '''Stephen_King''', 'Ste_en%', '', ut3.ut_utils.gc_success, 'not_'); - exec_be_like('varchar2(100)', '''Stephen_King''', 'Stephe\__%', '\', ut3.ut_utils.gc_success, 'not_'); - exec_be_like('clob', 'to_clob(rpad(''a'',32767,''a'')||''Stephen_King'')', 'a%Ste_en%', '', ut3.ut_utils.gc_success, 'not_'); - exec_be_like('clob', 'to_clob(rpad(''a'',32767,''a'')||''Stephen_King'')', 'a%Stephe\__%', '\', ut3.ut_utils.gc_success, 'not_'); + exec_be_like('varchar2(100)', '''Stephen_King''', 'Ste_en%', '', ut3_tester_helper.main_helper.gc_success, 'not_'); + exec_be_like('varchar2(100)', '''Stephen_King''', 'Stephe\__%', '\', ut3_tester_helper.main_helper.gc_success, 'not_'); + exec_be_like('clob', 'to_clob(rpad(''a'',32767,''a'')||''Stephen_King'')', 'a%Ste_en%', '', ut3_tester_helper.main_helper.gc_success, 'not_'); + exec_be_like('clob', 'to_clob(rpad(''a'',32767,''a'')||''Stephen_King'')', 'a%Stephe\__%', '\', ut3_tester_helper.main_helper.gc_success, 'not_'); --Fails for unsupported data-type - exec_be_like('number', '12345', '123%', '', ut3.ut_utils.gc_failure); + exec_be_like('number', '12345', '123%', '', ut3_tester_helper.main_helper.gc_failure); end; procedure test_timestamp_between is @@ -244,8 +245,8 @@ create or replace package body test_matchers is l_value_lower timestamp := to_timestamp('1997-01-31 09:26:50.11','YYYY-MM-DD HH24.MI.SS.FF'); l_value_upper timestamp := to_timestamp('1997-01-31 09:26:50.14','YYYY-MM-DD HH24.MI.SS.FF'); begin - ut3.ut.expect(l_value).to_be_between(l_value_lower, l_value_upper); - ut3.ut.expect(l_value).not_to_be_between(l_value_upper, l_value_lower); + ut3_develop.ut.expect(l_value).to_be_between(l_value_lower, l_value_upper); + ut3_develop.ut.expect(l_value).not_to_be_between(l_value_upper, l_value_lower); end; procedure test_timestamp_ltz_between is @@ -253,8 +254,8 @@ create or replace package body test_matchers is l_value_lower timestamp with local time zone := to_timestamp_tz('1997-01-31 09:26:50.12 +03:00','YYYY-MM-DD HH24.MI.SS.FF TZR'); l_value_upper timestamp with local time zone := to_timestamp_tz('1997-01-31 09:26:50.12 +01:00','YYYY-MM-DD HH24.MI.SS.FF TZR'); begin - ut3.ut.expect(l_value).to_be_between(l_value_lower, l_value_upper); - ut3.ut.expect(l_value).not_to_be_between(l_value_upper, l_value_lower); + ut3_develop.ut.expect(l_value).to_be_between(l_value_lower, l_value_upper); + ut3_develop.ut.expect(l_value).not_to_be_between(l_value_upper, l_value_lower); end; procedure test_timestamp_tz_between is @@ -262,8 +263,8 @@ create or replace package body test_matchers is l_value_lower timestamp with time zone := to_timestamp_tz('1997-01-31 09:26:50.12 +03:00','YYYY-MM-DD HH24.MI.SS.FF TZR'); l_value_upper timestamp with time zone := to_timestamp_tz('1997-01-31 09:26:50.12 +01:00','YYYY-MM-DD HH24.MI.SS.FF TZR'); begin - ut3.ut.expect(l_value).to_be_between(l_value_lower, l_value_upper); - ut3.ut.expect(l_value).not_to_be_between(l_value_upper, l_value_lower); + ut3_develop.ut.expect(l_value).to_be_between(l_value_lower, l_value_upper); + ut3_develop.ut.expect(l_value).not_to_be_between(l_value_upper, l_value_lower); end; end test_matchers; diff --git a/test/core/expectations/test_matchers.pks b/test/ut3_user/expectations/test_matchers.pks similarity index 88% rename from test/core/expectations/test_matchers.pks rename to test/ut3_user/expectations/test_matchers.pks index 0fa0953d4..e3e22e0cd 100644 --- a/test/core/expectations/test_matchers.pks +++ b/test/ut3_user/expectations/test_matchers.pks @@ -1,11 +1,11 @@ create or replace package test_matchers is --%suite(matchers) - --%suitepath(utplsql.core.expectations) + --%suitepath(utplsql.test_user.expectations) --%aftereach procedure cleanup_expectations; - + --%test procedure test_be_between2; --%test diff --git a/test/ut3_user/expectations/unary/test_expect_not_to_be_null.pkb b/test/ut3_user/expectations/unary/test_expect_not_to_be_null.pkb new file mode 100644 index 000000000..448addb8c --- /dev/null +++ b/test/ut3_user/expectations/unary/test_expect_not_to_be_null.pkb @@ -0,0 +1,265 @@ +create or replace package body test_expect_not_to_be_null +is + gc_object_name constant varchar2(30) := 't_not_to_be_null_test'; + gc_nested_table_name constant varchar2(30) := 'tt_not_to_be_null_test'; + gc_varray_name constant varchar2(30) := 'tv_not_to_be_null_test'; + + procedure cleanup_expectations is + begin + ut3_tester_helper.main_helper.clear_expectations( ); + end; + + procedure create_types is + pragma autonomous_transaction; + begin + execute immediate 'create type ' || gc_object_name || ' is object (dummy number)'; + execute immediate 'create type ' || gc_nested_table_name || ' is table of number'; + execute immediate 'create type ' || gc_varray_name || ' is varray(1) of number'; + end; + + procedure drop_types is + pragma autonomous_transaction; + begin + execute immediate 'drop type ' || gc_object_name; + execute immediate 'drop type ' || gc_nested_table_name; + execute immediate 'drop type ' || gc_varray_name; + end; + + procedure blob_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'not_to_be_null', 'blob', 'to_blob(''abc'')' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure blob_0_length is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'not_to_be_null', 'blob', 'empty_blob()' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure boolean_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'not_to_be_null', 'boolean', 'true' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure clob_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'not_to_be_null', 'clob', 'to_clob(''abc'')' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + + procedure clob_0_length is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'not_to_be_null', 'clob', 'empty_clob()' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure date_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'not_to_be_null', 'date', 'sysdate' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure number_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'not_to_be_null', 'number', '1234' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure timestamp_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'not_to_be_null', 'timestamp', 'systimestamp' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure timestamp_with_ltz_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( + 'not_to_be_null', 'timestamp with local time zone', 'systimestamp' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure timestamp_with_tz_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'not_to_be_null', 'timestamp with time zone', + 'systimestamp' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure varchar2_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'not_to_be_null', 'varchar2(4000)', '''abc''' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure initialized_object is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_object_block( + 'not_to_be_null', gc_object_name, gc_object_name || '(1)', 'object' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure initialized_nested_table is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_object_block( + 'not_to_be_null', gc_nested_table_name, gc_nested_table_name || '()', 'collection' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure initialized_varray is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_object_block( + 'not_to_be_null', gc_varray_name, gc_varray_name || '()', 'collection' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure null_blob is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'not_to_be_null', 'blob', 'null' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure null_boolean is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'not_to_be_null', 'boolean', 'null' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure null_clob is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'not_to_be_null', 'clob', 'null' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure null_date is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'not_to_be_null', 'date', 'null' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure null_number is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'not_to_be_null', 'number', 'null' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure null_timestamp is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'not_to_be_null', 'timestamp', 'null' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure null_timestamp_with_ltz is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( + 'not_to_be_null', 'timestamp with local time zone', 'null' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure null_timestamp_with_tz is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( + 'not_to_be_null', 'timestamp with time zone', 'null' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure null_varchar2 is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'not_to_be_null', 'varchar2(4000)', 'null' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure null_anydata is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'not_to_be_null', 'anydata', 'null' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure uninit_object_in_anydata is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_object_block( + 'not_to_be_null', gc_object_name, 'null', 'object' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure uninit_nested_table_in_anydata is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_object_block( + 'not_to_be_null', gc_nested_table_name, 'null', 'collection' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure uninit_varray_in_anydata is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_object_block( + 'not_to_be_null', gc_varray_name, 'null', 'collection' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + +end test_expect_not_to_be_null; +/ diff --git a/test/core/expectations/unary/test_expect_not_to_be_null.pks b/test/ut3_user/expectations/unary/test_expect_not_to_be_null.pks similarity index 97% rename from test/core/expectations/unary/test_expect_not_to_be_null.pks rename to test/ut3_user/expectations/unary/test_expect_not_to_be_null.pks index fa2d6193f..11648d5d2 100644 --- a/test/core/expectations/unary/test_expect_not_to_be_null.pks +++ b/test/ut3_user/expectations/unary/test_expect_not_to_be_null.pks @@ -1,7 +1,7 @@ create or replace package test_expect_not_to_be_null is --%suite(not_to_be_null) - --%suitepath(utplsql.core.expectations.unary) + --%suitepath(utplsql.test_user.expectations.unary) --%aftereach procedure cleanup_expectations; diff --git a/test/ut3_user/expectations/unary/test_expect_to_be_empty.pkb b/test/ut3_user/expectations/unary/test_expect_to_be_empty.pkb new file mode 100644 index 000000000..931e24d10 --- /dev/null +++ b/test/ut3_user/expectations/unary/test_expect_to_be_empty.pkb @@ -0,0 +1,270 @@ +create or replace package body test_expect_to_be_empty is + + procedure cleanup_expectations is + begin + ut3_tester_helper.main_helper.clear_expectations( ); + end; + procedure success_be_empty_cursor is + l_cursor sys_refcursor; + begin + --Arrange + open l_cursor for select * from dual where 1 = 2; + --Act + ut3_develop.ut.expect(l_cursor).to_be_empty; + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure fail_be_empty_cursor is + l_cursor sys_refcursor; + begin + --Arrange + open l_cursor for select * from dual; + --Act + ut3_develop.ut.expect(l_cursor).to_be_empty; + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure fail_be_empty_cursor_report is + l_cursor sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_cursor for select * from dual; + --Act + ut3_develop.ut.expect(l_cursor).to_be_empty; + + l_expected_message := q'[Actual: (refcursor [ count = 1 ])% + X% + was expected to be empty%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure success_not_be_empty_cursor is + l_cursor sys_refcursor; + begin + --Arrange + open l_cursor for select * from dual; + --Act + ut3_develop.ut.expect(l_cursor).not_to_be_empty; + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure fail_not_be_empty_cursor is + l_cursor sys_refcursor; + begin + --Arrange + open l_cursor for select * from dual where 1 = 2; + --Act + ut3_develop.ut.expect(l_cursor).not_to_be_empty; + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure success_be_empty_collection is + l_actual anydata; + begin + --Arrange + l_actual := anydata.convertcollection(ora_mining_varchar2_nt()); + -- Act + ut3_develop.ut.expect(l_actual).to_be_empty(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure fail_be_empty_collection is + l_actual anydata; + begin + --Arrange + l_actual := anydata.convertcollection(ora_mining_varchar2_nt('a')); + -- Act + ut3_develop.ut.expect(l_actual).to_be_empty(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure success_not_be_empty_coll is + l_actual anydata; + begin + --Arrange + l_actual := anydata.convertcollection(ora_mining_varchar2_nt('a')); + -- Act + ut3_develop.ut.expect(l_actual).not_to_be_empty(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure fail_not_be_empty_collection is + l_actual anydata; + begin + --Arrange + l_actual := anydata.convertcollection(ora_mining_varchar2_nt()); + -- Act + ut3_develop.ut.expect(l_actual).not_to_be_empty(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure fail_be_empty_null_collection is + l_actual anydata; + l_data ora_mining_varchar2_nt; + begin + --Arrange + l_actual := anydata.convertcollection(l_data); + -- Act + ut3_develop.ut.expect(l_actual).to_be_empty(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure fail_not_be_empty_null_coll is + l_actual anydata; + l_data ora_mining_varchar2_nt; + begin + --Arrange + l_actual := anydata.convertcollection(l_data); + -- Act + ut3_develop.ut.expect(l_actual).not_to_be_empty(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure fail_be_empty_object is + l_actual anydata; + begin + --Arrange + l_actual := anydata.convertObject(ut3_tester_helper.test_dummy_number(1)); + -- Act + ut3_develop.ut.expect(l_actual).to_be_empty(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure fail_be_empty_null_object is + l_actual anydata; + l_data ut3_tester_helper.test_dummy_number; + begin + --Arrange + l_actual := anydata.convertObject(l_data); + -- Act + ut3_develop.ut.expect(l_actual).to_be_empty(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure fail_be_empty_number is + begin + -- Act + ut3_develop.ut.expect( 1 ).to_( ut3_develop.be_empty() ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + /** + * https://docs.oracle.com/en/database/oracle/oracle-database/18/adobj/declaring-initializing-objects-in-plsql.html#GUID-23135172-82E2-4C3E-800D-E584B43B578E + * User-defined types, just like collections, are atomically null, until you initialize the object by calling the constructor for its object type. That is, the object itself is null, not just its attributes. + */ + procedure fail_not_be_empty_object is + l_actual anydata; + begin + --Arrange + l_actual := anydata.convertObject(ut3_tester_helper.test_dummy_number(1)); + -- Act + ut3_develop.ut.expect(l_actual).not_to_be_empty(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure fail_not_be_empty_null_object is + l_actual anydata; + l_data ut3_tester_helper.test_dummy_number; + begin + --Arrange + l_actual := anydata.convertObject(l_data); + -- Act + ut3_develop.ut.expect(l_actual).not_to_be_empty(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure fail_not_be_empty_number is + begin + -- Act + ut3_develop.ut.expect( 1 ).not_to( ut3_develop.be_empty() ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure success_be_empty_clob is + begin + -- Act + ut3_develop.ut.expect( empty_clob() ).to_( ut3_develop.be_empty() ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure fail_be_empty_clob is + begin + -- Act + ut3_develop.ut.expect( to_clob(' ') ).to_( ut3_develop.be_empty() ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure success_be_empty_blob is + begin + -- Act + ut3_develop.ut.expect( empty_blob() ).to_( ut3_develop.be_empty() ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure fail_be_empty_blob is + begin + -- Act + ut3_develop.ut.expect( to_blob('AA') ).to_( ut3_develop.be_empty() ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + + procedure fail_not_be_empty_clob is + begin + -- Act + ut3_develop.ut.expect( empty_clob() ).not_to( ut3_develop.be_empty() ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure success_not_be_empty_clob is + begin + -- Act + ut3_develop.ut.expect( to_clob(' ') ).not_to( ut3_develop.be_empty() ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure fail_not_be_empty_blob is + begin + -- Act + ut3_develop.ut.expect( empty_blob() ).not_to( ut3_develop.be_empty() ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure success_not_be_empty_blob is + begin + -- Act + ut3_develop.ut.expect( to_blob('AA') ).not_to( ut3_develop.be_empty() ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + +end; +/ \ No newline at end of file diff --git a/test/core/expectations/unary/test_expect_to_be_empty.pks b/test/ut3_user/expectations/unary/test_expect_to_be_empty.pks similarity index 95% rename from test/core/expectations/unary/test_expect_to_be_empty.pks rename to test/ut3_user/expectations/unary/test_expect_to_be_empty.pks index f48db600f..a76787ac5 100644 --- a/test/core/expectations/unary/test_expect_to_be_empty.pks +++ b/test/ut3_user/expectations/unary/test_expect_to_be_empty.pks @@ -1,7 +1,7 @@ create or replace package test_expect_to_be_empty is --%suite - --%suitepath(utplsql.core.expectations.unary) + --%suitepath(utplsql.test_user.expectations.unary) --%aftereach procedure cleanup_expectations; @@ -66,7 +66,7 @@ create or replace package test_expect_to_be_empty is --%test(Gives failure for an empty collection) procedure fail_not_be_empty_null_coll; - --%test(Gives failure for an object) + --%test(Gives failure for an empty object) procedure fail_not_be_empty_object; --%test(Gives failure for a null object) diff --git a/test/ut3_user/expectations/unary/test_expect_to_be_not_null.pkb b/test/ut3_user/expectations/unary/test_expect_to_be_not_null.pkb new file mode 100644 index 000000000..0e747eb85 --- /dev/null +++ b/test/ut3_user/expectations/unary/test_expect_to_be_not_null.pkb @@ -0,0 +1,264 @@ +create or replace package body test_expect_to_be_not_null +is + gc_object_name constant varchar2(30) := 't_to_be_not_null_test'; + gc_nested_table_name constant varchar2(30) := 'tt_to_be_not_null_test'; + gc_varray_name constant varchar2(30) := 'tv_to_be_not_null_test'; + + procedure cleanup_expectations is + begin + ut3_tester_helper.main_helper.clear_expectations( ); + end; + + procedure create_types is + pragma autonomous_transaction; + begin + execute immediate 'create type '||gc_object_name||' is object (dummy number)'; + execute immediate 'create type '||gc_nested_table_name||' is table of number'; + execute immediate 'create type '||gc_varray_name||' is varray(1) of number'; + end; + + procedure drop_types is + pragma autonomous_transaction; + begin + execute immediate 'drop type '||gc_object_name; + execute immediate 'drop type '||gc_nested_table_name; + execute immediate 'drop type '||gc_varray_name; + end; + + procedure blob_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block('to_be_not_null', 'blob', 'to_blob(''abc'')'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure empty_blob is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block('to_be_not_null', 'blob', 'empty_blob()'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure boolean_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block('to_be_not_null', 'boolean', 'true'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure clob_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block('to_be_not_null', 'clob', 'to_clob(''abc'')'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure empty_clob is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block('to_be_not_null', 'clob', 'empty_clob()'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure date_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block('to_be_not_null', 'date', 'sysdate'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure number_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block('to_be_not_null', 'number', '1234'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure timestamp_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block('to_be_not_null', 'timestamp', 'systimestamp'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure timestamp_with_ltz_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block('to_be_not_null', 'timestamp with local time zone', 'systimestamp'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure timestamp_with_tz_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block('to_be_not_null', 'timestamp with time zone', 'systimestamp'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure varchar2_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block('to_be_not_null', 'varchar2(4000)', '''abc'''); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure initialized_object is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_object_block( + 'to_be_not_null', gc_object_name, gc_object_name||'(1)', 'object' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure initialized_nested_table is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_object_block( + 'to_be_not_null', gc_nested_table_name, gc_nested_table_name||'()', 'collection' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure initialized_varray is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_object_block( + 'to_be_not_null', gc_varray_name, gc_varray_name||'()', 'collection' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure null_blob is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block('to_be_not_null', 'blob', 'null'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure null_boolean is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block('to_be_not_null', 'boolean', 'null'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + + procedure null_clob is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block('to_be_not_null', 'clob', 'null'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + + procedure null_date is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block('to_be_not_null', 'date', 'null'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + + procedure null_number is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block('to_be_not_null', 'number', 'null'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + + procedure null_timestamp is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block('to_be_not_null', 'timestamp', 'null'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + + procedure null_timestamp_with_ltz is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block('to_be_not_null', 'timestamp with local time zone', 'null'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + + procedure null_timestamp_with_tz is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block('to_be_not_null', 'timestamp with time zone', 'null'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + + procedure null_varchar2 is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block('to_be_not_null', 'varchar2(4000)', 'null'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure null_anydata is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block('to_be_not_null', 'anydata', 'null'); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure uninit_object_in_anydata is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_object_block( + 'to_be_not_null', gc_object_name, 'null', 'object' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure uninit_nested_table_in_anydata is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_object_block( + 'to_be_not_null', gc_nested_table_name, 'null', 'collection' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure uninit_varray_in_anydata is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_object_block( + 'to_be_not_null', gc_varray_name, 'null', 'collection' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + +end test_expect_to_be_not_null; +/ diff --git a/test/core/expectations/unary/test_expect_to_be_not_null.pks b/test/ut3_user/expectations/unary/test_expect_to_be_not_null.pks similarity index 97% rename from test/core/expectations/unary/test_expect_to_be_not_null.pks rename to test/ut3_user/expectations/unary/test_expect_to_be_not_null.pks index 351482fee..7cb7cc265 100644 --- a/test/core/expectations/unary/test_expect_to_be_not_null.pks +++ b/test/ut3_user/expectations/unary/test_expect_to_be_not_null.pks @@ -1,7 +1,7 @@ create or replace package test_expect_to_be_not_null is --%suite(to_be_not_null) - --%suitepath(utplsql.core.expectations.unary) + --%suitepath(utplsql.test_user.expectations.unary) --%aftereach procedure cleanup_expectations; diff --git a/test/ut3_user/expectations/unary/test_expect_to_be_null.pkb b/test/ut3_user/expectations/unary/test_expect_to_be_null.pkb new file mode 100644 index 000000000..c0899c08d --- /dev/null +++ b/test/ut3_user/expectations/unary/test_expect_to_be_null.pkb @@ -0,0 +1,260 @@ +create or replace package body test_expect_to_be_null +is + gc_object_name constant varchar2(30) := 't_to_be_null_test'; + gc_nested_table_name constant varchar2(30) := 'tt_to_be_null_test'; + gc_varray_name constant varchar2(30) := 'tv_to_be_null_test'; + + procedure cleanup_expectations is + begin + ut3_tester_helper.main_helper.clear_expectations( ); + end; + + procedure create_types is + pragma autonomous_transaction; + begin + execute immediate 'create type ' || gc_object_name || ' is object (dummy number)'; + execute immediate 'create type ' || gc_nested_table_name || ' is table of number'; + execute immediate 'create type ' || gc_varray_name || ' is varray(1) of number'; + end; + + procedure drop_types is + pragma autonomous_transaction; + begin + execute immediate 'drop type ' || gc_object_name; + execute immediate 'drop type ' || gc_nested_table_name; + execute immediate 'drop type ' || gc_varray_name; + end; + + procedure null_blob is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'to_be_null', 'blob', 'null' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure null_boolean is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'to_be_null', 'boolean', 'null' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure null_clob is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'to_be_null', 'clob', 'null' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure null_date is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'to_be_null', 'date', 'null' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure null_number is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'to_be_null', 'number', 'null' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure null_timestamp is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'to_be_null', 'timestamp', 'null' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure null_timestamp_with_ltz is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'to_be_null', 'timestamp with local time zone', 'null' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure null_timestamp_with_tz is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'to_be_null', 'timestamp with time zone', 'null' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure null_varchar2 is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'to_be_null', 'varchar2(4000)', 'null' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure null_anydata is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'to_be_null', 'anydata', 'null' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure uninit_object_in_anydata is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_object_block( + 'to_be_null', gc_object_name, 'null', 'object' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure uninit_nested_table_in_anydata is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_object_block( + 'to_be_null', gc_nested_table_name, 'null', 'collection' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure uninit_varray_in_anydata is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_object_block( 'to_be_null', gc_varray_name, + 'null', 'collection' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure blob_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'to_be_null', 'blob', 'to_blob(''abc'')' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure empty_blob is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'to_be_null', 'blob', 'empty_blob()' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure boolean_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'to_be_null', 'boolean', 'true' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure clob_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'to_be_null', 'clob', 'to_clob(''abc'')' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure empty_clob is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'to_be_null', 'clob', 'empty_clob()' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure date_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'to_be_null', 'date', 'sysdate' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure number_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'to_be_null', 'number', '1234' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure timestamp_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'to_be_null', 'timestamp', 'systimestamp' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure timestamp_with_ltz_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( + 'to_be_null', 'timestamp with local time zone', 'systimestamp' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure timestamp_with_tz_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( + 'to_be_null', 'timestamp with time zone', 'systimestamp' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure varchar2_not_null is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_block( 'to_be_null', 'varchar2(4000)', '''abc''' ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure initialized_object is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_object_block( + 'to_be_null', gc_object_name, gc_object_name || '(1)', 'object' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure initialized_nested_table is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_object_block( + 'to_be_null', gc_nested_table_name, gc_nested_table_name || '()', 'collection' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure initialized_varray is + begin + --Act + execute immediate ut3_tester_helper.expectations_helper.unary_expectation_object_block( + 'to_be_null', gc_varray_name, gc_varray_name || '()', 'collection' + ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + +end test_expect_to_be_null; +/ diff --git a/test/core/expectations/unary/test_expect_to_be_null.pks b/test/ut3_user/expectations/unary/test_expect_to_be_null.pks similarity index 97% rename from test/core/expectations/unary/test_expect_to_be_null.pks rename to test/ut3_user/expectations/unary/test_expect_to_be_null.pks index 8b34e1279..f1758316e 100644 --- a/test/core/expectations/unary/test_expect_to_be_null.pks +++ b/test/ut3_user/expectations/unary/test_expect_to_be_null.pks @@ -1,7 +1,7 @@ create or replace package test_expect_to_be_null is --%suite(to_be_null) - --%suitepath(utplsql.core.expectations.unary) + --%suitepath(utplsql.test_user.expectations.unary) --%aftereach procedure cleanup_expectations; diff --git a/test/ut3_user/expectations/unary/test_expect_to_be_true_false.pkb b/test/ut3_user/expectations/unary/test_expect_to_be_true_false.pkb new file mode 100644 index 000000000..c1067044b --- /dev/null +++ b/test/ut3_user/expectations/unary/test_expect_to_be_true_false.pkb @@ -0,0 +1,139 @@ +create or replace package body test_expect_to_be_true_false +is + + procedure cleanup_expectations is + begin + ut3_tester_helper.main_helper.clear_expectations( ); + end; + + procedure to_be_true_null_boolean is + begin + --Act + ut3_develop.ut.expect( 1=null ).to_be_true(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure to_be_true_success is + begin + --Act + ut3_develop.ut.expect( 1=1 ).to_be_true(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure to_be_true_failure is + begin + --Act + ut3_develop.ut.expect( 1=2 ).to_be_true(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure to_be_true_bad_type is + begin + --Act + ut3_develop.ut.expect( 1 ).to_be_true(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure not_to_be_true_null_boolean is + begin + --Act + ut3_develop.ut.expect( 1=null ).not_to_be_true(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure not_to_be_true_success is + begin + --Act + ut3_develop.ut.expect( 1=2 ).not_to_be_true(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure not_to_be_true_failure is + begin + --Act + ut3_develop.ut.expect( 1=1 ).not_to_be_true(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + + procedure not_to_be_true_bad_type is + begin + --Act + ut3_develop.ut.expect( 1 ).not_to_be_true(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure to_be_false_null_boolean is + begin + --Act + ut3_develop.ut.expect( 1=null ).to_be_false(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure to_be_false_success is + begin + --Act + ut3_develop.ut.expect( 1=2 ).to_be_false(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure to_be_false_failure is + begin + --Act + ut3_develop.ut.expect( 1=1 ).to_be_false(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure to_be_false_bad_type is + begin + --Act + ut3_develop.ut.expect( 1 ).to_be_false(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure not_to_be_false_null_boolean is + begin + --Act + ut3_develop.ut.expect( 1=null ).not_to_be_false(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure not_to_be_false_success is + begin + --Act + ut3_develop.ut.expect( 1=1 ).not_to_be_false(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure not_to_be_false_failure is + begin + --Act + ut3_develop.ut.expect( 1=2 ).not_to_be_false(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure not_to_be_false_bad_type is + begin + --Act + ut3_develop.ut.expect( 1 ).not_to_be_false(); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + +end; +/ diff --git a/test/core/expectations/unary/test_expect_to_be_true_false.pks b/test/ut3_user/expectations/unary/test_expect_to_be_true_false.pks similarity index 97% rename from test/core/expectations/unary/test_expect_to_be_true_false.pks rename to test/ut3_user/expectations/unary/test_expect_to_be_true_false.pks index abdbf44b6..28bbae6f7 100644 --- a/test/core/expectations/unary/test_expect_to_be_true_false.pks +++ b/test/ut3_user/expectations/unary/test_expect_to_be_true_false.pks @@ -1,7 +1,7 @@ create or replace package test_expect_to_be_true_false is --%suite(to_be_true/false) - --%suitepath(utplsql.core.expectations.unary) + --%suitepath(utplsql.test_user.expectations.unary) --%aftereach procedure cleanup_expectations; diff --git a/test/ut3_user/expectations/unary/test_expect_to_have_count.pkb b/test/ut3_user/expectations/unary/test_expect_to_have_count.pkb new file mode 100644 index 000000000..2167c44ef --- /dev/null +++ b/test/ut3_user/expectations/unary/test_expect_to_have_count.pkb @@ -0,0 +1,210 @@ +create or replace package body test_expect_to_have_count is + + procedure cleanup_expectations is + begin + ut3_tester_helper.main_helper.clear_expectations( ); + end; + + procedure success_have_count_cursor is + l_cursor sys_refcursor; + begin + --Arrange + open l_cursor for select * from dual connect by level <= 11; + --Act + ut3_develop.ut.expect(l_cursor).to_have_count(11); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure fail_have_count_cursor is + l_cursor sys_refcursor; + begin + --Arrange + open l_cursor for select * from dual where 0=1; + --Act + ut3_develop.ut.expect(l_cursor).to_have_count(1); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure fail_have_count_cursor_report is + l_cursor sys_refcursor; + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + open l_cursor for select * from dual; + --Act + ut3_develop.ut.expect(l_cursor).to_have_count(2); + + l_expected_message := q'[Actual: (refcursor [ count = 1 ]) was expected to have [ count = 2 ]%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure success_not_have_count_cursor is + l_cursor sys_refcursor; + begin + --Arrange + open l_cursor for select * from dual; + --Act + ut3_develop.ut.expect(l_cursor).not_to_have_count(2); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure fail_not_have_count_cursor is + l_cursor sys_refcursor; + begin + --Arrange + open l_cursor for select * from dual where 1 = 2; + --Act + ut3_develop.ut.expect(l_cursor).not_to_have_count(0); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure success_have_count_collection is + l_actual anydata; + begin + --Arrange + l_actual := anydata.convertcollection(ora_mining_varchar2_nt()); + -- Act + ut3_develop.ut.expect(l_actual).to_have_count(0); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure fail_have_count_collection is + l_actual anydata; + begin + --Arrange + l_actual := anydata.convertcollection(ora_mining_varchar2_nt('a')); + -- Act + ut3_develop.ut.expect(l_actual).to_have_count(0); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure success_not_have_count_coll is + l_actual anydata; + begin + --Arrange + l_actual := anydata.convertcollection(ora_mining_varchar2_nt('a')); + -- Act + ut3_develop.ut.expect(l_actual).not_to_have_count(2); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure fail_not_have_count_coll is + l_actual anydata; + begin + --Arrange + l_actual := anydata.convertcollection(ora_mining_varchar2_nt()); + -- Act + ut3_develop.ut.expect(l_actual).not_to_have_count(0); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure fail_have_count_null_coll is + l_actual anydata; + l_data ora_mining_varchar2_nt; + begin + --Arrange + l_actual := anydata.convertcollection(l_data); + -- Act + ut3_develop.ut.expect(l_actual).to_have_count(0); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure fail_not_have_count_null_coll is + l_actual anydata; + l_data ora_mining_varchar2_nt; + begin + --Arrange + l_actual := anydata.convertcollection(l_data); + -- Act + ut3_develop.ut.expect(l_actual).not_to_have_count(0); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure fail_have_count_object is + l_actual anydata; + begin + --Arrange + l_actual := anydata.convertObject(ut3_tester_helper.test_dummy_number(1)); + -- Act + ut3_develop.ut.expect(l_actual).to_have_count(0); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure fail_have_count_null_object is + l_actual anydata; + l_data ut3_tester_helper.test_dummy_number; + begin + --Arrange + l_actual := anydata.convertObject(l_data); + -- Act + ut3_develop.ut.expect(l_actual).to_have_count(0); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure fail_have_count_number is + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + -- Act + ut3_develop.ut.expect( 1 ).to_( ut3_develop.have_count(0) ); + --Assert + l_expected_message := q'[%The matcher 'have count' cannot be used with data type (number).%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure fail_not_have_count_object is + l_actual anydata; + l_expected_message varchar2(32767); + l_actual_message varchar2(32767); + begin + --Arrange + l_actual := anydata.convertObject(ut3_tester_helper.test_dummy_number(1)); + -- Act + ut3_develop.ut.expect(l_actual).not_to_have_count(0); + --Assert + l_expected_message := q'[%The matcher 'have count' cannot be used with data type (ut3_tester_helper.test_dummy_number).%]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure fail_not_have_count_null_obj is + l_actual anydata; + l_data ut3_tester_helper.test_dummy_number; + begin + --Arrange + l_actual := anydata.convertObject(l_data); + -- Act + ut3_develop.ut.expect(l_actual).not_to_have_count(0); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + + procedure fail_not_have_count_number is + begin + -- Act + ut3_develop.ut.expect( 1 ).not_to( ut3_develop.have_count(0) ); + --Assert + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_be_greater_than(0); + end; + +end; +/ \ No newline at end of file diff --git a/test/core/expectations/unary/test_expect_to_have_count.pks b/test/ut3_user/expectations/unary/test_expect_to_have_count.pks similarity index 96% rename from test/core/expectations/unary/test_expect_to_have_count.pks rename to test/ut3_user/expectations/unary/test_expect_to_have_count.pks index 636f98ba4..b944d8800 100644 --- a/test/core/expectations/unary/test_expect_to_have_count.pks +++ b/test/ut3_user/expectations/unary/test_expect_to_have_count.pks @@ -1,7 +1,7 @@ create or replace package test_expect_to_have_count is --%suite((not)to_have_count) - --%suitepath(utplsql.core.expectations.unary) + --%suitepath(utplsql.test_user.expectations.unary) --%aftereach procedure cleanup_expectations; diff --git a/test/ut3_user/helpers/some_item.tps b/test/ut3_user/helpers/some_item.tps new file mode 100644 index 000000000..336f44d9a --- /dev/null +++ b/test/ut3_user/helpers/some_item.tps @@ -0,0 +1,6 @@ +create or replace type some_item force as object( + item_id number(38), + item_name varchar2(250) +) +/ + diff --git a/test/ut3_user/helpers/some_items.tps b/test/ut3_user/helpers/some_items.tps new file mode 100644 index 000000000..8b984f8a4 --- /dev/null +++ b/test/ut3_user/helpers/some_items.tps @@ -0,0 +1,2 @@ +create or replace type some_items force as table of some_item +/ diff --git a/test/ut3_user/helpers/some_object.tps b/test/ut3_user/helpers/some_object.tps new file mode 100644 index 000000000..024379974 --- /dev/null +++ b/test/ut3_user/helpers/some_object.tps @@ -0,0 +1,7 @@ +create or replace type some_object force as object( + object_owner varchar2(250), + object_name varchar2(250), + create_time timestamp, + items some_items +) +/ diff --git a/test/core/reporters.pkb b/test/ut3_user/reporters.pkb similarity index 52% rename from test/core/reporters.pkb rename to test/ut3_user/reporters.pkb index abd9e6007..031683615 100644 --- a/test/core/reporters.pkb +++ b/test/ut3_user/reporters.pkb @@ -14,8 +14,8 @@ as --%beforeeach procedure beforeeach; - --%context(some_context) - --%displayname(A description of some context) + --%context(A description of some context) + --%name(some_context) --%test --%beforetest(beforetest) @@ -35,9 +35,13 @@ as procedure erroring_test; --%test(a disabled test) - --%disabled + --%disabled(Disabled for testing purpose) procedure disabled_test; + --%test(a disabled test with no reason) + --%disabled + procedure disabled_test_no_reason; + --%aftereach procedure aftereach; @@ -74,30 +78,36 @@ as is begin dbms_output.put_line(''); - ut3.ut.expect(1,'Test 1 Should Pass').to_equal(1); + ut3_develop.ut.expect(1,'Test 1 Should Pass').to_equal(1); end; procedure failing_test is begin dbms_output.put_line(''); - ut3.ut.expect('number [1] ','Fails as values are different').to_equal('number [2] '); + ut3_develop.ut.expect('number [1] ','Fails as values are different').to_equal('number [2] '); end; procedure erroring_test is - l_variable integer; + l_integer_variable integer; begin dbms_output.put_line(''); - l_variable := 'a string'; - ut3.ut.expect(l_variable).to_equal(1); + l_integer_variable := 'a string'; end; procedure disabled_test is begin dbms_output.put_line(''); - ut3.ut.expect(1,'this should not execute').to_equal(1); + ut3_develop.ut.expect(1,'this should not execute').to_equal(1); + end; + + procedure disabled_test_no_reason + is + begin + dbms_output.put_line(''); + ut3_develop.ut.expect(1,'this should not execute').to_equal(1); end; procedure beforeall is @@ -110,8 +120,24 @@ as dbms_output.put_line(''); end; -end;]'; - +end;]'; + + execute immediate q'[create or replace package check_fail_escape is + --%suitepath(core) + --%suite(Check JUNIT XML failure is escaped) + + --%test(Fail Miserably) + procedure fail_miserably; + + end;]'; + + execute immediate q'[create or replace package body check_fail_escape is + procedure fail_miserably is + begin + ut3_develop.ut.expect('test').to_equal(''); + end; + end;]'; + end; procedure reporters_setup is @@ -122,6 +148,7 @@ end;]'; procedure drop_test_helper_package is begin execute immediate 'drop package test_reporters'; + execute immediate 'drop package check_fail_escape'; end; procedure reporters_cleanup is @@ -131,20 +158,39 @@ end;]'; end; procedure check_xml_encoding_included( - a_reporter ut3.ut_output_reporter_base, + a_reporter ut3_develop.ut_reporter_base, a_client_character_set varchar2 ) is - l_results ut3.ut_varchar2_list; + l_results ut3_develop.ut_varchar2_list; l_actual clob; begin --Act select * bulk collect into l_results - from table(ut3.ut.run('test_reporters', a_reporter, a_client_character_set => a_client_character_set)); - l_actual := ut3.ut_utils.table_to_clob(l_results); + from table(ut3_develop.ut.run('test_reporters', a_reporter, a_client_character_set => a_client_character_set)); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); --Assert ut.expect(l_actual).to_be_like('%'); end; + procedure check_xml_failure_escaped( + a_reporter ut3_develop.ut_reporter_base + ) is + l_results ut3_develop.ut_varchar2_list; + l_actual clob; + begin + --Act + select * + bulk collect into l_results + from table( ut3_develop.ut.run( 'check_fail_escape', a_reporter ) ); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + --Assert + ut.expect(l_actual).to_be_like('%' (varchar2)%]' + ||q'[at "UT3_USER.CHECK_FAIL_ESCAPE%", line % ut3_develop.ut.expect('test').to_equal('');]' + ||'%]]>%' + ); + end; + end reporters; / diff --git a/test/core/reporters.pks b/test/ut3_user/reporters.pks similarity index 57% rename from test/core/reporters.pks rename to test/ut3_user/reporters.pks index 229e4e9b1..c5ad72e22 100644 --- a/test/core/reporters.pks +++ b/test/ut3_user/reporters.pks @@ -1,7 +1,7 @@ create or replace package reporters is --%suite - --%suitepath(utplsql.core) + --%suitepath(utplsql.test_user) --%beforeall procedure reporters_setup; @@ -10,9 +10,13 @@ create or replace package reporters is procedure reporters_cleanup; procedure check_xml_encoding_included( - a_reporter ut3.ut_output_reporter_base, + a_reporter ut3_develop.ut_reporter_base, a_client_character_set varchar2 ); + procedure check_xml_failure_escaped( + a_reporter ut3_develop.ut_reporter_base + ); + end reporters; / diff --git a/test/ut3_user/reporters/test_coverage.pks b/test/ut3_user/reporters/test_coverage.pks new file mode 100644 index 000000000..11bc6d480 --- /dev/null +++ b/test/ut3_user/reporters/test_coverage.pks @@ -0,0 +1,14 @@ +create or replace package test_coverage is + + --%suite + --%suitepath(utplsql.test_user.reporters) + + --%beforeall(ut3_tester_helper.coverage_helper.create_test_results_table) + --%beforeall(ut3_tester_helper.coverage_helper.create_dummy_coverage) + + + --%afterall(ut3_tester_helper.coverage_helper.drop_dummy_coverage) + --%afterall(ut3_tester_helper.coverage_helper.drop_test_results_table) + +end; +/ diff --git a/test/ut3_user/reporters/test_coverage/test_cov_cobertura_reporter.pkb b/test/ut3_user/reporters/test_coverage/test_cov_cobertura_reporter.pkb new file mode 100644 index 000000000..ad6c9dbb4 --- /dev/null +++ b/test/ut3_user/reporters/test_coverage/test_cov_cobertura_reporter.pkb @@ -0,0 +1,57 @@ +create or replace package body test_cov_cobertura_reporter is + + procedure report_on_file is + l_expected clob; + l_actual clob; + l_block_cov clob; + l_name varchar2(250); + l_file_path varchar2(250); + begin + + + --Arrange + l_name := ut3_tester_helper.coverage_helper.covered_package_name; + l_file_path := 'test/ut3_develop.'||ut3_tester_helper.coverage_helper.covered_package_name||'.pkb'; + if ut3_tester_helper.coverage_helper.block_coverage_available then + l_block_cov := ''; + else + l_block_cov := ''; + end if; + l_expected := + q'[ + + + +]'||l_file_path||q'[ + + + + + + +]'||l_block_cov||q'[ + + + + + + +]'; + --Act + l_actual := + ut3_tester_helper.coverage_helper.run_tests_as_job( + q'[ + ut3_develop.ut.run( + a_path => 'ut3_develop.test_dummy_coverage', + a_reporter => ut3_develop.ut_coverage_cobertura_reporter( ), + a_source_files => ut3_develop.ut_varchar2_list( ']'||l_file_path||q'[' ), + a_test_files => ut3_develop.ut_varchar2_list( ) + ) + ]' + ); + --Assert + ut.expect(l_actual).to_be_like(l_expected); + end; + +end; +/ diff --git a/test/core/reporters/test_coverage/test_cov_cobertura_reporter.pks b/test/ut3_user/reporters/test_coverage/test_cov_cobertura_reporter.pks similarity index 79% rename from test/core/reporters/test_coverage/test_cov_cobertura_reporter.pks rename to test/ut3_user/reporters/test_coverage/test_cov_cobertura_reporter.pks index ac347fb9d..365815964 100644 --- a/test/core/reporters/test_coverage/test_cov_cobertura_reporter.pks +++ b/test/ut3_user/reporters/test_coverage/test_cov_cobertura_reporter.pks @@ -1,7 +1,7 @@ create or replace package test_cov_cobertura_reporter is --%suite(ut_cov_cobertura_reporter) - --%suitepath(utplsql.core.reporters.test_coverage) + --%suitepath(utplsql.test_user.reporters.test_coverage) --%test(reports on a project file mapped to database object) procedure report_on_file; diff --git a/test/ut3_user/reporters/test_coverage/test_coverage_sonar_reporter.pkb b/test/ut3_user/reporters/test_coverage/test_coverage_sonar_reporter.pkb new file mode 100644 index 000000000..50d7bfe4c --- /dev/null +++ b/test/ut3_user/reporters/test_coverage/test_coverage_sonar_reporter.pkb @@ -0,0 +1,43 @@ +create or replace package body test_coverage_sonar_reporter is + + procedure report_on_file is + l_expected clob; + l_actual clob; + l_block_cov clob; + begin + --Arrange + if ut3_tester_helper.coverage_helper.block_coverage_available then + l_block_cov := ''; + else + l_block_cov := ''; + end if; + l_expected := ' + + +'||l_block_cov||' + + +'; + --Act + l_actual := + ut3_tester_helper.coverage_helper.run_tests_as_job( + q'[ + ut3_develop.ut.run( + a_path => 'ut3_develop.test_dummy_coverage', + a_reporter=> ut3_develop.ut_coverage_sonar_reporter( ), + a_source_files => ut3_develop.ut_varchar2_list( 'test/ut3_develop.]'||ut3_tester_helper.coverage_helper.covered_package_name||q'[.pkb' ), + a_test_files => ut3_develop.ut_varchar2_list( ) + ) + ]' + ); + --Assert + ut.expect(l_actual).to_equal(l_expected); + end; + + procedure check_encoding_included is + begin + reporters.check_xml_encoding_included(ut3_develop.ut_coverage_sonar_reporter(), 'UTF-8'); + end; + +end; +/ diff --git a/test/core/reporters/test_coverage/test_coverage_sonar_reporter.pks b/test/ut3_user/reporters/test_coverage/test_coverage_sonar_reporter.pks similarity index 83% rename from test/core/reporters/test_coverage/test_coverage_sonar_reporter.pks rename to test/ut3_user/reporters/test_coverage/test_coverage_sonar_reporter.pks index 31cb358dd..7a98355cf 100644 --- a/test/core/reporters/test_coverage/test_coverage_sonar_reporter.pks +++ b/test/ut3_user/reporters/test_coverage/test_coverage_sonar_reporter.pks @@ -1,7 +1,7 @@ create or replace package test_coverage_sonar_reporter is --%suite(ut_coverge_sonar_reporter) - --%suitepath(utplsql.core.reporters.test_coverage) + --%suitepath(utplsql.test_user.reporters.test_coverage) --%test(reports on a project file mapped to database object) procedure report_on_file; diff --git a/test/ut3_user/reporters/test_coverage/test_coverage_standalone.pkb b/test/ut3_user/reporters/test_coverage/test_coverage_standalone.pkb new file mode 100644 index 000000000..90cfb484e --- /dev/null +++ b/test/ut3_user/reporters/test_coverage/test_coverage_standalone.pkb @@ -0,0 +1,101 @@ +create or replace package body test_coverage_standalone is + + function run_coverage_twice(a_overage_run_id raw, a_object_name varchar2, a_charset varchar2) return clob is + l_expected clob; + l_block_cov clob; + l_file_path varchar2(250); + begin + l_file_path := 'package body ut3_develop.'||a_object_name; + --Arrange + if ut3_tester_helper.coverage_helper.block_coverage_available then + l_block_cov := ''; + else + l_block_cov := ''; + end if; + l_expected := + q'[ + + + +]'||l_file_path||q'[ + + + + + + +]'||l_block_cov||q'[ + + + + + + +]'; + --Act + ut3_tester_helper.coverage_helper.run_coverage_job(a_overage_run_id, 1); + ut3_tester_helper.coverage_helper.run_coverage_job(a_overage_run_id, 3); + return l_expected; + end; + + procedure coverage_without_ut_run is + l_coverage_run_id raw(32) := sys_guid(); + l_actual ut3_develop.ut_varchar2_list; + l_expected clob; + l_name varchar2(250); + l_charset varchar2(100) := 'ISO-8859-1'; + begin + l_name := ut3_tester_helper.coverage_helper.covered_package_name; + + --Arrange and Act + l_expected := run_coverage_twice(l_coverage_run_id, l_name, l_charset); + + select * + bulk collect into l_actual + from + table ( + ut3_develop.ut_coverage_cobertura_reporter().get_report( + a_coverage_options => ut3_develop.ut_coverage_options( + coverage_run_id => l_coverage_run_id, + include_objects => ut3_develop.ut_varchar2_rows(l_name), + schema_names => ut3_develop.ut_varchar2_rows('UT3_DEVELOP') + ), + a_client_character_set => l_charset + ) + ); + + --Assert + ut.expect(ut3_tester_helper.main_helper.table_to_clob(l_actual)).to_be_like( l_expected ); + end; + + procedure coverage_cursor_without_ut_run is + l_coverage_run_id raw(32) := sys_guid(); + l_coverage_cursor sys_refcursor; + l_actual ut3_develop.ut_varchar2_list; + l_expected clob; + l_name varchar2(250); + l_charset varchar2(100) := 'ISO-8859-1'; + begin + l_name := ut3_tester_helper.coverage_helper.covered_package_name; + + --Arrange and Act + l_expected := run_coverage_twice(l_coverage_run_id, l_name, l_charset); + + l_coverage_cursor := + ut3_develop.ut_coverage_cobertura_reporter( ).get_report_cursor( + a_coverage_options => ut3_develop.ut_coverage_options( + coverage_run_id => l_coverage_run_id, + include_objects => ut3_develop.ut_varchar2_rows(l_name), + schema_names => ut3_develop.ut_varchar2_rows('UT3_DEVELOP') + ), + a_client_character_set => l_charset + ); + fetch l_coverage_cursor bulk collect into l_actual; + close l_coverage_cursor; + + --Assert + ut.expect(ut3_tester_helper.main_helper.table_to_clob(l_actual)).to_be_like( l_expected ); + end; + +end; +/ diff --git a/test/ut3_user/reporters/test_coverage/test_coverage_standalone.pks b/test/ut3_user/reporters/test_coverage/test_coverage_standalone.pks new file mode 100644 index 000000000..1d5bb9a2c --- /dev/null +++ b/test/ut3_user/reporters/test_coverage/test_coverage_standalone.pks @@ -0,0 +1,12 @@ +create or replace package test_coverage_standalone authid current_user is + + --%suite + --%suitepath(utplsql.test_user.reporters.test_coverage) + + --%test(Coverage can be invoked standalone in multiple sessions and a combined report can be produced at the end) + procedure coverage_without_ut_run; + + --%test(Coverage can be invoked standalone in multiple sessions and a combined report can be produced at the end as cursor) + procedure coverage_cursor_without_ut_run; +end; +/ diff --git a/test/ut3_user/reporters/test_coverage/test_coveralls_reporter.pkb b/test/ut3_user/reporters/test_coverage/test_coveralls_reporter.pkb new file mode 100644 index 000000000..e3806cd97 --- /dev/null +++ b/test/ut3_user/reporters/test_coverage/test_coveralls_reporter.pkb @@ -0,0 +1,77 @@ +create or replace package body test_coveralls_reporter is + + procedure report_on_file is + l_expected clob; + l_actual clob; + l_file_path varchar2(250); + begin + --Arrange + l_file_path := 'test/ut3_develop.'||ut3_tester_helper.coverage_helper.covered_package_name||'.pkb'; + l_expected := q'[{"source_files":[ +{ "name": "]'||l_file_path||q'[", +"coverage": [ +null, +null, +null, +3, +null, +0 +] +} +]} + ]'; + l_actual := + ut3_tester_helper.coverage_helper.run_tests_as_job( + q'[ + ut3_develop.ut.run( + a_path => 'ut3_develop.test_dummy_coverage', + a_reporter => ut3_develop.ut_coveralls_reporter( ), + a_source_files => ut3_develop.ut_varchar2_list( ']'||l_file_path||q'[' ), + a_test_files => ut3_develop.ut_varchar2_list( ) + ) + ]' + ); + --Assert + ut.expect(l_actual).to_equal(l_expected); + end; + + procedure report_zero_coverage is + l_expected clob; + l_actual clob; + begin + --Arrange + l_expected := q'[{"source_files":[ +{ "name": "package body ut3_develop.]'||ut3_tester_helper.coverage_helper.covered_package_name||q'[", +"coverage": [ +0, +0, +0, +0, +0, +0, +0, +0, +0 +] +} +]} + ]'; + + --Act + l_actual := + ut3_tester_helper.coverage_helper.run_tests_as_job( + q'[ + ut3_develop.ut.run( + 'ut3_develop.test_dummy_coverage.zero_coverage', + ut3_develop.ut_coveralls_reporter(), + a_include_objects => ut3_develop.ut_varchar2_list('UT3_DEVELOP.]'||ut3_tester_helper.coverage_helper.covered_package_name||q'[') + ) + ]' + ); + --Assert + ut.expect(l_actual).to_equal(l_expected); + + end; + +end; +/ diff --git a/test/core/reporters/test_coverage/test_coveralls_reporter.pks b/test/ut3_user/reporters/test_coverage/test_coveralls_reporter.pks similarity index 83% rename from test/core/reporters/test_coverage/test_coveralls_reporter.pks rename to test/ut3_user/reporters/test_coverage/test_coveralls_reporter.pks index bf2b861f7..d958b8f12 100644 --- a/test/core/reporters/test_coverage/test_coveralls_reporter.pks +++ b/test/ut3_user/reporters/test_coverage/test_coveralls_reporter.pks @@ -1,7 +1,7 @@ create or replace package test_coveralls_reporter is --%suite(ut_coveralls_reporter) - --%suitepath(utplsql.core.reporters.test_coverage) + --%suitepath(utplsql.test_user.reporters.test_coverage) --%test(reports on a project file mapped to database object) procedure report_on_file; diff --git a/test/ut3_user/reporters/test_coverage/test_extended_coverage.pkb b/test/ut3_user/reporters/test_coverage/test_extended_coverage.pkb new file mode 100644 index 000000000..d7f1b61d7 --- /dev/null +++ b/test/ut3_user/reporters/test_coverage/test_extended_coverage.pkb @@ -0,0 +1,318 @@ +create or replace package body test_extended_coverage is + + function get_block_coverage_line return clob is + begin + return + case + when ut3_tester_helper.coverage_helper.block_coverage_available then + '%' + else + '%' + end; + end; + procedure coverage_for_object is + l_expected clob; + l_actual clob; + begin + --Arrange + l_expected := '%' || + get_block_coverage_line|| + '%%'; + --Act + l_actual := + ut3_tester_helper.coverage_helper.run_tests_as_job( + q'[ + ut3_develop.ut.run( + a_path => 'ut3_develop.test_dummy_coverage', + a_reporter=> ut3_develop.ut_coverage_sonar_reporter( ), + a_include_objects => ut3_develop.ut_varchar2_list( 'ut3_develop.]'||ut3_tester_helper.coverage_helper.covered_package_name||q'[' ) + ) + ]' + ); + --Assert + ut.expect(l_actual).to_be_like(l_expected); + end; + + procedure coverage_for_schema is + l_expected clob; + l_actual clob; + begin + --Arrange + l_expected := '%' || + get_block_coverage_line || + '%%'; + --Act + l_actual := + ut3_tester_helper.coverage_helper.run_tests_as_job( + q'[ + ut3_develop.ut.run( + a_path => 'ut3_develop.test_dummy_coverage', + a_reporter=> ut3_develop.ut_coverage_sonar_reporter( ), + a_coverage_schemes => ut3_develop.ut_varchar2_list( 'ut3_develop' ) + ) + ]' + ); + --Assert + ut.expect(l_actual).to_be_like(l_expected); + ut.expect(l_actual).to_be_like('%%%'); + end; + + procedure coverage_for_file is + l_expected clob; + l_actual clob; + l_file_path varchar2(250); + begin + --Arrange + l_file_path := 'test/ut3_develop.'||ut3_tester_helper.coverage_helper.covered_package_name||'.pkb'; + l_expected := '%' || + get_block_coverage_line || + '%%'; + --Act + l_actual := + ut3_tester_helper.coverage_helper.run_tests_as_job( + q'[ + ut3_develop.ut.run( + a_path => 'ut3_develop.test_dummy_coverage', + a_reporter=> ut3_develop.ut_coverage_sonar_reporter( ), + a_source_files => ut3_develop.ut_varchar2_list( ']'||l_file_path||q'[' ), + a_test_files => ut3_develop.ut_varchar2_list( ) + ) + ]' + ); + --Assert + ut.expect(l_actual).to_be_like(l_expected); + end; + + procedure coverage_with_dbms_stats is + l_expected clob; + l_actual clob; + begin + --Arrange + l_expected := '%' || + '%%'; + --Act + l_actual := + ut3_tester_helper.coverage_helper.run_tests_as_job( + q'[ + ut3_develop.ut.run( + a_path => 'ut3_develop.test_stats', + a_reporter=> ut3_develop.ut_coverage_sonar_reporter( ), + a_coverage_schemes => ut3_develop.ut_varchar2_list( 'ut3_develop' ), + a_include_objects => ut3_develop.ut_varchar2_list('stats') + ) + ]' + ); + --Assert + ut.expect(l_actual).to_be_like(l_expected); + end; + + procedure coverage_regex_include_schema is + l_expected clob; + l_not_expected clob; + l_actual clob; + begin + --Arrange + l_expected := '%' || + '%%'; + l_not_expected := '%' || + '%%'; + --Act + l_actual := + ut3_tester_helper.coverage_helper.run_tests_as_job( + q'[ + ut3_develop.ut.run( + a_paths => ut3_develop.ut_varchar2_list('ut3_develop.test_regex_dummy_cov', 'ut3_tester_helper.test_regex_dummy_cov'), + a_reporter=> ut3_develop.ut_coverage_sonar_reporter( ), + a_include_schema_expr => '^ut3_tester_hel.*', + a_include_objects => ut3_develop.ut_varchar2_list( 'ut3_develop.regex_dummy_cov' ) + ) + ]' + ); + + --Assert + --The below is a workaround for problem with large CLOB like comparison on 11g XE db. + ut.expect(to_char(substr(l_actual,instr(l_actual,''),2000))).to_be_like(l_expected); + ut.expect(l_actual).not_to_be_like(l_not_expected); + ut.expect(l_actual).not_to_be_like('%ut3_tester_helper.test_regex_dummy_cov%'); + end; + + procedure coverage_regex_include_object is + l_expected clob; + l_not_expected clob; + l_actual clob; + begin + --Arrange + l_expected := '%' || + '%%'; + l_not_expected := '%' || + '%%'; + --Act + l_actual := + ut3_tester_helper.coverage_helper.run_tests_as_job( + q'[ + ut3_develop.ut.run( + a_paths => ut3_develop.ut_varchar2_list('ut3_develop.test_regex_dummy_cov', 'ut3_develop.test_regex123_dummy_cov'), + a_reporter=> ut3_develop.ut_coverage_sonar_reporter( ), + a_include_object_expr => 'regex123', + a_include_objects => ut3_develop.ut_varchar2_list( 'ut3_develop.regex_dummy_cov' ) + ) + ]' + ); + --Assert + ut.expect(l_actual).to_be_like(l_expected); + ut.expect(l_actual).not_to_be_like(l_not_expected); + end; + + procedure coverage_regex_exclude_schema is + l_expected clob; + l_not_expected clob; + l_actual clob; + begin + --Arrange + l_expected := '%' || + '%%'; + l_not_expected := '%' || + '%%'; + --Act + l_actual := + ut3_tester_helper.coverage_helper.run_tests_as_job( + q'[ + ut3_develop.ut.run( + a_paths => ut3_develop.ut_varchar2_list('ut3_develop.test_regex_dummy_cov', 'ut3_tester_helper.test_regex_dummy_cov'), + a_reporter=> ut3_develop.ut_coverage_sonar_reporter( ), + a_exclude_schema_expr => '^ut3_tester', + a_exclude_objects => ut3_develop.ut_varchar2_list( 'ut3_develop.regex_dummy_cov' ) + ) + ]' + ); + --Assert + ut.expect(l_actual).to_be_like(l_expected); + ut.expect(l_actual).not_to_be_like(l_not_expected); + end; + + procedure coverage_regex_exclude_object is + l_expected clob; + l_not_expected clob; + l_actual clob; + begin + --Arrange + l_expected := '%' || + '%%'; + l_not_expected := '%' || + '%%'; + --Act + l_actual := + ut3_tester_helper.coverage_helper.run_tests_as_job( + q'[ + ut3_develop.ut.run( + a_paths => ut3_develop.ut_varchar2_list('ut3_develop.test_regex_dummy_cov', 'ut3_develop.test_regex123_dummy_cov'), + a_reporter=> ut3_develop.ut_coverage_sonar_reporter( ), + a_exclude_object_expr => 'regex123', + a_exclude_objects => ut3_develop.ut_varchar2_list( 'ut3_develop.regex_dummy_cov' ) + ) + ]' + ); + --Assert + ut.expect(l_actual).to_be_like(l_expected); + ut.expect(l_actual).not_to_be_like(l_not_expected); + end; + + procedure cove_rgx_inc_schema_norun is + l_expected clob; + l_not_expected clob; + l_actual clob; + begin + --Arrange + l_expected := '%UT3_DEVELOP.REGEX_DUMMY_COV%'; + l_not_expected := '%UT3_TESTER_HELPER.REGEX123_DUMMY_COV%'; + --Act + l_actual := ut3_tester_helper.coverage_helper.gather_coverage_on_coverage( + q'[ut3_develop.ut_coverage_options( + coverage_run_id => l_coverage_run_id, + include_schema_expr => '^ut3_develop' + )]'); + --Assert + ut.expect(l_actual).to_be_like(l_expected); + ut.expect(l_actual).not_to_be_like(l_not_expected); + end; + + procedure cove_rgx_inc_object_norun is + l_expected clob; + l_not_expected clob; + l_actual clob; + begin + --Arrange + l_expected := '%UT3_DEVELOP.REGEX123_DUMMY_COV%'; + l_not_expected := '%UT3_DEVELOP.REGEX_DUMMY_COV%'; + --Act + l_actual := ut3_tester_helper.coverage_helper.gather_coverage_on_coverage( + q'[ut3_develop.ut_coverage_options( + coverage_run_id => l_coverage_run_id, + include_object_expr => 'regex123' + )]'); + --Assert + ut.expect(l_actual).to_be_like(l_expected); + ut.expect(l_actual).not_to_be_like(l_not_expected); + end; + + procedure cove_rgx_exc_schema_norun is + l_expected clob; + l_not_expected clob; + l_actual clob; + begin + --Arrange + l_expected := '%UT3_DEVELOP.REGEX_DUMMY_COV%'; + l_not_expected := '%UT3_TESTER_HELPER.REGEX_DUMMY_COV%'; + --Act + l_actual := ut3_tester_helper.coverage_helper.gather_coverage_on_coverage( + q'[ut3_develop.ut_coverage_options( + coverage_run_id => l_coverage_run_id, + schema_names => ut3_develop.ut_varchar2_rows( 'UT3_DEVELOP','UT3_TESTER_HELPER' ), + exclude_schema_expr => '^ut3_tester', + exclude_objects => ut3_develop.ut_varchar2_rows( 'ut3_develop.regex_dummy_cov' ) + )]'); + --Assert + ut.expect(l_actual).to_be_like(l_expected); + ut.expect(l_actual).not_to_be_like(l_not_expected); + end; + + procedure cove_rgx_exc_object_norun is + l_expected clob; + l_not_expected clob; + l_actual clob; + begin + --Arrange + l_expected := '%UT3_DEVELOP.REGEX_DUMMY_COV%'; + l_not_expected := '%UT3_DEVELOP.REGEX123_DUMMY_COV%'; + --Act + l_actual := ut3_tester_helper.coverage_helper.gather_coverage_on_coverage( + q'[ut3_develop.ut_coverage_options( + coverage_run_id => l_coverage_run_id, + schema_names => ut3_develop.ut_varchar2_rows( 'UT3_DEVELOP' ), + exclude_object_expr => 'regex123', + exclude_objects => ut3_develop.ut_varchar2_rows( 'ut3_develop.regex_dummy_cov' ) + )]'); + --Assert + ut.expect(l_actual).to_be_like(l_expected); + ut.expect(l_actual).not_to_be_like(l_not_expected); + end; + + procedure cov_file_mapping_no_utrun is + l_expected clob; + l_not_expected clob; + l_actual clob; + begin + --Arrange + l_expected := '%UT3_DEVELOP.REGEX_DUMMY_COV%'; + --Act + l_actual := ut3_tester_helper.coverage_helper.gather_coverage_on_coverage( + q'[ut3_develop.ut_coverage_options( + coverage_run_id => l_coverage_run_id, + file_mappings => ut3_develop.ut_file_mappings( ut3_develop.ut_file_mapping('C:\tests\helpers\core.pkb','UT3_DEVELOP','REGEX_DUMMY_COV','PACKAGE BODY')) + )]'); + --Assert + ut.expect(l_actual).to_be_like(l_expected); + end; + +end; +/ diff --git a/test/ut3_user/reporters/test_coverage/test_extended_coverage.pks b/test/ut3_user/reporters/test_coverage/test_extended_coverage.pks new file mode 100644 index 000000000..82b19fbed --- /dev/null +++ b/test/ut3_user/reporters/test_coverage/test_extended_coverage.pks @@ -0,0 +1,66 @@ +create or replace package test_extended_coverage is + + --%suite + --%suitepath(utplsql.test_user.reporters.test_coverage) + + --%test(Coverage is gathered for specified object - extended coverage type) + procedure coverage_for_object; + + --%test(Coverage is gathered for specified schema - extended coverage type) + procedure coverage_for_schema; + + --%test(Coverage is gathered for specified file - extended coverage type) + procedure coverage_for_file; + + --%beforetest(ut3_tester_helper.coverage_helper.create_cov_with_dbms_stats) + --%aftertest(ut3_tester_helper.coverage_helper.drop_cov_with_dbms_stats) + --%tags(#1097,#1094) + --%test(Extended coverage does not fail the test run then tested code calls DBMS_STATS) + procedure coverage_with_dbms_stats; + + --%beforetest(ut3_tester_helper.coverage_helper.create_regex_dummy_cov) + --%aftertest(ut3_tester_helper.coverage_helper.drop_regex_dummy_cov) + --%test(Collect coverage for objects with schema regex include with ut_run) + procedure coverage_regex_include_schema; + + --%beforetest(ut3_tester_helper.coverage_helper.create_regex_dummy_cov) + --%aftertest(ut3_tester_helper.coverage_helper.drop_regex_dummy_cov) + --%test(Collect coverage for objects with object regex include with ut_run) + procedure coverage_regex_include_object; + + --%beforetest(ut3_tester_helper.coverage_helper.create_regex_dummy_cov) + --%aftertest(ut3_tester_helper.coverage_helper.drop_regex_dummy_cov) + --%test(Collect coverage for objects with schema regex exclude with ut_run) + procedure coverage_regex_exclude_schema; + + --%beforetest(ut3_tester_helper.coverage_helper.create_regex_dummy_cov) + --%aftertest(ut3_tester_helper.coverage_helper.drop_regex_dummy_cov) + --%test(Collect coverage for objects with object regex exclude with ut_run) + procedure coverage_regex_exclude_object; + + --%beforetest(ut3_tester_helper.coverage_helper.create_regex_dummy_cov) + --%aftertest(ut3_tester_helper.coverage_helper.drop_regex_dummy_cov) + --%test(Collect coverage for objects with schema regex include without ut_run) + procedure cove_rgx_inc_schema_norun; + + --%beforetest(ut3_tester_helper.coverage_helper.create_regex_dummy_cov) + --%aftertest(ut3_tester_helper.coverage_helper.drop_regex_dummy_cov) + --%test(Collect coverage for objects with object regex include without ut_run) + procedure cove_rgx_inc_object_norun; + + --%beforetest(ut3_tester_helper.coverage_helper.create_regex_dummy_cov) + --%aftertest(ut3_tester_helper.coverage_helper.drop_regex_dummy_cov) + --%test(Collect coverage for objects with schema regex exclude without ut_run) + procedure cove_rgx_exc_schema_norun; + + --%beforetest(ut3_tester_helper.coverage_helper.create_regex_dummy_cov) + --%aftertest(ut3_tester_helper.coverage_helper.drop_regex_dummy_cov) + --%test(Collect coverage for objects with object regex exclude without ut_run) + procedure cove_rgx_exc_object_norun; + + --%beforetest(ut3_tester_helper.coverage_helper.create_regex_dummy_cov) + --%aftertest(ut3_tester_helper.coverage_helper.drop_regex_dummy_cov) + --%test(Collect coverage for file mapping without ut_run) + procedure cov_file_mapping_no_utrun; +end; +/ diff --git a/test/ut3_user/reporters/test_coverage/test_html_coverage_reporter.pkb b/test/ut3_user/reporters/test_coverage/test_html_coverage_reporter.pkb new file mode 100644 index 000000000..2f2200116 --- /dev/null +++ b/test/ut3_user/reporters/test_coverage/test_html_coverage_reporter.pkb @@ -0,0 +1,101 @@ +create or replace package body test_html_coverage_reporter is + + procedure report_on_file is + l_expected varchar2(32767); + l_actual clob; + l_block_cov clob; + l_name varchar2(250); + l_charset varchar2(100) := 'ISO-8859-1'; + begin + --Arrange + l_name := ut3_tester_helper.coverage_helper.covered_package_name; + if ut3_tester_helper.coverage_helper.block_coverage_available then + l_block_cov := '(including 1 lines partially covered ) '; + end if; + l_expected := '%%

UT3_DEVELOP.'||upper(l_name)||'

' || + '%2 relevant lines. 1 lines covered ' || + l_block_cov || 'and 1 lines missed%'; + + l_actual := + ut3_tester_helper.coverage_helper.run_tests_as_job( + q'[ + ut3_develop.ut.run( + a_path => 'ut3_develop.test_dummy_coverage', + a_reporter=> ut3_develop.ut_coverage_html_reporter(), + a_source_files => ut3_develop.ut_varchar2_list( 'test/ut3_develop.]'||l_name||q'[.pkb' ), + a_test_files => ut3_develop.ut_varchar2_list( ), + a_client_character_set => ']'||l_charset||q'[' + ) + ]' + ); + --Assert + ut.expect(l_actual).to_be_like(l_expected); + end; + + procedure setup_long_lines is + pragma autonomous_transaction; + begin + + execute immediate q'[create or replace type string_array is table of varchar2(5 char);]'; + execute immediate q'[ + create or replace function f return integer is + l_string_array string_array; + l_count integer; + begin + -- line is 1912 chars long, 1911 characters seem to be the max. line length that works (@formatter:off) + l_string_array := string_array('aahed', 'aalii', 'aargh', 'aarti', 'abaca', 'abaci', 'abacs', 'abaft', 'abaka', 'abamp', 'aband', 'abash', 'abask', 'abaya', 'abbas', 'abbed', 'abbes', 'abcee', 'abeam', 'abear', 'abele', 'abers', 'abets', 'abies', 'abler', 'ables', 'ablet', 'ablow', 'abmho', 'abohm', 'aboil', 'aboma', 'aboon', 'abord', 'abore', 'abram', 'abray', 'abrim', 'abrin', 'abris', 'absey', 'absit', 'abuna', 'abune', 'abuts', 'abuzz', 'abyes', 'abysm', 'acais', 'acari', 'accas', 'accoy', 'acerb', 'acers', 'aceta', 'achar', 'ached', 'aches', 'achoo', 'acids', 'acidy', 'acing', 'acini', 'ackee', 'acker', 'acmes', 'acmic', 'acned', 'acnes', 'acock', 'acold', 'acred', 'acres', 'acros', 'acted', 'actin', 'acton', 'acyls', 'adaws', 'adays', 'adbot', 'addax', 'added', 'adder', 'addio', 'addle', 'adeem', 'adhan', 'adieu', 'adios', 'adits', 'adman', 'admen', 'admix', 'adobo', 'adown', 'adoze', 'adrad', 'adred', 'adsum', 'aduki', 'adunc', 'adust', 'advew', 'adyta', 'adzed', 'adzes', 'aecia', 'aedes', 'aegis', 'aeons', 'aerie', 'aeros', 'aesir', 'afald', 'afara', 'afars', 'afear', 'aflaj', 'afore', 'afrit', 'afros', 'agama', 'agami', 'agars', 'agast', 'agave', 'agaze', 'agene', 'agers', 'agger', 'aggie', 'aggri', 'aggro', 'aggry', 'aghas', 'agila', 'agios', 'agism', 'agist', 'agita', 'aglee', 'aglet', 'agley', 'agloo', 'aglus', 'agmas', 'agoge', 'agone', 'agons', 'agood', 'agora', 'agria', 'agrin', 'agros', 'agued', 'agues', 'aguna', 'aguti', 'aheap', 'ahent', 'ahigh', 'ahind', 'ahing', 'ahint', 'ahold', 'ahull', 'ahuru', 'aidas', 'aided', 'aides', 'aidoi', 'aidos', 'aiery', 'aigas', 'aight', 'ailed', 'aimed', 'aimer', 'ainee', 'ainga', 'aioli', 'aired', 'airer', 'airns', 'airth', 'airts', 'aitch', 'aitus', 'aiver', 'aiyee', 'aizle', 'ajies', 'ajiva', 'ajuga', 'ajwan', 'akees', 'akela', 'akene', 'aking', 'akita', 'akkas', 'alaap', 'alack', 'alamo', 'aland', 'alane', 'alang', 'a'); + select count(*) into l_count from table(l_string_array); + return l_count; + end;]'; + + execute immediate q'[ + create or replace package test_f is + --%suite + + --%test + procedure fail_ut_coverage_html_reporter; + end;]'; + + execute immediate q'[ + create or replace package body test_f is + procedure fail_ut_coverage_html_reporter is + begin + ut3_develop.ut.expect(f()).to_be_greater_or_equal(1); + end; + end; + ]'; + end; + + procedure cleanup_long_lines is + pragma autonomous_transaction; + begin + execute immediate 'drop package test_f'; + execute immediate 'drop function f'; + execute immediate 'drop type string_array force'; + end; + + procedure report_long_lines is + l_expected varchar2(32767); + l_actual clob; + l_name varchar2(250); + begin + --Arrange + l_expected := '%l_string_array := string_array%'; + + l_actual := + ut3_tester_helper.coverage_helper.run_tests_as_job( + q'[ + ut3_develop.ut.run( + a_path => 'ut3_user.test_f', + a_reporter=> ut3_develop.ut_coverage_html_reporter(), + a_include_objects => ut3_develop.ut_varchar2_list( 'UT3_USER.F' ) + ) + ]' + ); + --Assert + ut.expect(l_actual).to_be_like(l_expected); + end; + + +end test_html_coverage_reporter; +/ diff --git a/test/ut3_user/reporters/test_coverage/test_html_coverage_reporter.pks b/test/ut3_user/reporters/test_coverage/test_html_coverage_reporter.pks new file mode 100644 index 000000000..a11f3e912 --- /dev/null +++ b/test/ut3_user/reporters/test_coverage/test_html_coverage_reporter.pks @@ -0,0 +1,18 @@ +create or replace package test_html_coverage_reporter is + + --%suite(ut_html_extended_reporter) + --%suitepath(utplsql.test_user.reporters.test_coverage.test_extended_coverage) + + --%test(reports on a project file mapped to database object in extended profiler coverage) + procedure report_on_file; + + procedure setup_long_lines; + procedure cleanup_long_lines; + + --%test(reports on lines exceeding 4000 chars after conversion to XML) + --%beforetest(setup_long_lines) + --%aftertest(cleanup_long_lines) + procedure report_long_lines; + +end test_html_coverage_reporter; +/ diff --git a/test/ut3_user/reporters/test_coverage/test_proftab_coverage.pkb b/test/ut3_user/reporters/test_coverage/test_proftab_coverage.pkb new file mode 100644 index 000000000..f3aad5702 --- /dev/null +++ b/test/ut3_user/reporters/test_coverage/test_proftab_coverage.pkb @@ -0,0 +1,211 @@ +create or replace package body test_proftab_coverage is + + procedure coverage_for_object is + l_expected clob; + l_actual clob; + begin + --Arrange + l_expected := coverage_helper.substitute_covered_package('%%'); + --Act + l_actual := + ut3_tester_helper.coverage_helper.run_tests_as_job( + coverage_helper.substitute_covered_package( + q'[ + ut3_develop.ut.run( + a_path => 'ut3_develop.test_dummy_coverage', + a_reporter=> ut3_develop.ut_coverage_sonar_reporter( ), + a_include_objects => ut3_develop.ut_varchar2_list( 'ut3_develop.{p}' ) + ) + ]' + ) + ); + --Assert + ut.expect(l_actual).to_be_like(l_expected); + end; + + procedure coverage_for_object_no_owner is + l_expected clob; + l_actual clob; + begin + --Arrange + l_expected := coverage_helper.substitute_covered_package('%%'); + --Act + l_actual := + ut3_tester_helper.coverage_helper.run_tests_as_job( + coverage_helper.substitute_covered_package( + q'[ + ut3_develop.ut.run( + a_path => 'ut3_develop.test_dummy_coverage', + a_reporter=> ut3_develop.ut_coverage_sonar_reporter( ), + a_include_objects => ut3_develop.ut_varchar2_list( '{p}' ) + ) + ]' + ) + ); + --Assert + ut.expect(l_actual).to_be_like(l_expected); + end; + + procedure coverage_for_schema is + l_expected clob; + l_actual clob; + begin + --Arrange + l_expected := ''; + l_expected := '%'||l_expected||'%'||l_expected||'%'; + --Act + l_actual := + ut3_tester_helper.coverage_helper.run_tests_as_job( + q'[ + ut3_develop.ut.run( + a_path => 'ut3_develop.test_dummy_coverage', + a_reporter=> ut3_develop.ut_coverage_sonar_reporter( ), + a_coverage_schemes => ut3_develop.ut_varchar2_list( 'ut3_develop' ) + ) + ]' + ); + --Assert + ut.expect(l_actual).to_be_like(l_expected); + ut.expect(l_actual).not_to_be_like('%%'); + end; + + procedure coverage_for_file is + l_expected clob; + l_actual clob; + l_file_path varchar2(250); + begin + --Arrange + l_file_path := coverage_helper.substitute_covered_package('test/ut3_develop.{p}.pkb'); + l_expected := '%%'; + --Act + l_actual := + ut3_tester_helper.coverage_helper.run_tests_as_job( + q'[ + ut3_develop.ut.run( + a_path => 'ut3_develop.test_dummy_coverage', + a_reporter=> ut3_develop.ut_coverage_sonar_reporter( ), + a_source_files => ut3_develop.ut_varchar2_list( ']'||l_file_path||q'[' ), + a_test_files => ut3_develop.ut_varchar2_list( ) + ) + ]' + ); + --Assert + ut.expect(l_actual).to_be_like(l_expected); + end; + + procedure dup_object_name_coverage is + l_actual clob; + l_expected clob; + begin + l_expected := + '%%' || + '%%%'; + --Act + l_actual := + ut3_tester_helper.coverage_helper.run_tests_as_job( + q'[ + ut3_develop.ut.run( + a_path => 'ut3_develop.test_duplicate_name', + a_reporter=> ut3_develop.ut_coverage_sonar_reporter( ), + a_include_objects => ut3_develop.ut_varchar2_list( 'ut3_develop.duplicate_name' ) + ) + ]' + ); + --Assert + --TODO - need to fix coverage reporting so that coverage is grouped by object type not only object name + ut.expect(l_actual).to_be_like(l_expected); + end; + + procedure coverage_tmp_data_refresh is + l_actual clob; + l_test_code varchar2(32767); + begin + l_test_code := q'[ + declare + l_tmp_data ut3_develop.ut_varchar2_list; + begin + --Arrange + select * bulk collect into l_tmp_data + from table( + ut3_develop.ut.run( + a_path => 'ut3_develop:coverage_testing', + a_reporter=> ut3_develop.ut_coverage_sonar_reporter( ), + a_include_objects => ut3_develop.ut_varchar2_list( 'ut3_develop.{p}' ) + ) + ); + coverage_helper.drop_dummy_coverage(); + coverage_helper.create_dummy_coverage_1(); + + --Act + insert into test_results + select rownum, x.* + from table( + ut3_develop.ut.run( + a_path => 'ut3_develop:coverage_testing', + a_reporter=> ut3_develop.ut_coverage_sonar_reporter( ), + a_include_objects => ut3_develop.ut_varchar2_list( 'ut3_develop.{p}' ) + ) + ) x; + commit; + end; + ]'; + + l_actual := ut3_tester_helper.coverage_helper.run_code_as_job( coverage_helper.substitute_covered_package(l_test_code) ); + --Assert + ut.expect(l_actual).to_equal(to_clob(' + +')); + end; + + procedure report_zero_coverage is + l_expected clob; + l_actual clob; + begin + --Arrange + l_expected := + q'[ + + + +package body ut3_develop.{p} + + + + + + + + + + + + + + + + + + + + +]'; + + --Act + l_actual := + ut3_tester_helper.coverage_helper.run_tests_as_job( + coverage_helper.substitute_covered_package( + q'[ + ut3_develop.ut.run( + 'ut3_develop.test_dummy_coverage.zero_coverage', + ut3_develop.ut_coverage_cobertura_reporter(), + a_include_objects => ut3_develop.ut_varchar2_list('UT3_DEVELOP.{P}') + ) + ]' + ) + ); + --Assert + ut.expect(l_actual).to_be_like(coverage_helper.substitute_covered_package(l_expected)); + end; + +end; +/ diff --git a/test/ut3_user/reporters/test_coverage/test_proftab_coverage.pks b/test/ut3_user/reporters/test_coverage/test_proftab_coverage.pks new file mode 100644 index 000000000..740862f86 --- /dev/null +++ b/test/ut3_user/reporters/test_coverage/test_proftab_coverage.pks @@ -0,0 +1,32 @@ +create or replace package test_proftab_coverage is + + --%suite + --%suitepath(utplsql.test_user.reporters.test_coverage) + + --%test(Coverage is gathered for specified object - default coverage type) + procedure coverage_for_object; + + --%test(Coverage is gathered for specified schema - default coverage type) + procedure coverage_for_object_no_owner; + + --%test(Coverage is gathered for specified schema) + procedure coverage_for_schema; + + --%test(Coverage is gathered for specified file - default coverage type) + procedure coverage_for_file; + + --%beforetest(ut3_tester_helper.coverage_helper.create_dup_object_name) + --%aftertest(ut3_tester_helper.coverage_helper.drop_dup_object_name) + --%test(Coverage on duplicate object name) + procedure dup_object_name_coverage; + + --%test(Coverage data is not cached between runs - issue #562 ) + --%aftertest(ut3_tester_helper.coverage_helper.drop_dummy_coverage_1) + --%aftertest(ut3_tester_helper.coverage_helper.create_dummy_coverage) + procedure coverage_tmp_data_refresh; + + --%test(reports zero coverage on each line of non-executed database object - Issue #917) + procedure report_zero_coverage; + +end; +/ diff --git a/test/ut3_user/reporters/test_debug_reporter.pkb b/test/ut3_user/reporters/test_debug_reporter.pkb new file mode 100644 index 000000000..a022b5af8 --- /dev/null +++ b/test/ut3_user/reporters/test_debug_reporter.pkb @@ -0,0 +1,45 @@ +create or replace package body test_debug_reporter as + + g_actual clob; + + procedure run_reporter is + l_results ut3_develop.ut_varchar2_list; + begin + select * + bulk collect into l_results + from table( + ut3_develop.ut.run( + 'test_reporters', + ut3_develop.ut_debug_reporter() + ) + ); + g_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + end; + + procedure includes_event_info is + l_expected varchar2(32767); + begin + l_expected := '\s+' || + '(\s+' || + ' [0-9\-]+T[0-9:\.]+<\/TIMESTAMP>\s+' || + '[0-9 \+:\.]+<\/TIME_FROM_START>\s+' || + '[0-9 \+:\.]+<\/TIME_FROM_PREVIOUS>\s+' || + '\w+<\/EVENT_NAME>\s+' || + '(\s|\S)+?<\/CALL_STACK>(\s|\S)+?' || + '<\/DEBUG>\s+)+' || + '<\/DEBUG_LOG>'; + ut.expect( g_actual ).to_match( l_expected, 'm' ); + end; + + procedure includes_run_info is + l_expected varchar2(32767); + begin + l_expected := '(\s|\S)+?(\s|\S)+?<\/UT_RUN_INFO>\s+<\/DEBUG>'; + ut.expect( g_actual ).to_match( l_expected, 'm' ); + end; + + +end; +/ + + diff --git a/test/ut3_user/reporters/test_debug_reporter.pks b/test/ut3_user/reporters/test_debug_reporter.pks new file mode 100644 index 000000000..4d7f7962f --- /dev/null +++ b/test/ut3_user/reporters/test_debug_reporter.pks @@ -0,0 +1,16 @@ +create or replace package test_debug_reporter as + + --%suite(ut_debug_reporter) + --%suitepath(utplsql.test_user.reporters) + + --%beforeall + procedure run_reporter; + + --%test(Includes event info for every event) + procedure includes_event_info; + + --%test(Includes run info) + procedure includes_run_info; + +end; +/ diff --git a/test/ut3_user/reporters/test_documentation_reporter.pkb b/test/ut3_user/reporters/test_documentation_reporter.pkb new file mode 100644 index 000000000..016cec256 --- /dev/null +++ b/test/ut3_user/reporters/test_documentation_reporter.pkb @@ -0,0 +1,59 @@ +create or replace package body test_documentation_reporter as + + procedure report_produces_expected_out is + l_results ut3_develop.ut_varchar2_list; + l_actual clob; + l_expected varchar2(32767):=q'[%org + utplsql + tests + helpers + A suite for testing different outcomes from reporters + + A description of some context + passing_test [% sec] + + + + + + a test with failing assertion [% sec] (FAILED - 1) + + + + a test raising unhandled exception [% sec] (FAILED - 2) + + + + a disabled test [0 sec] (DISABLED - Disabled for testing purpose) + a disabled test with no reason [0 sec] (DISABLED) + +% +Failures: +% + 1) failing_test + "Fails as values are different" + Actual: 'number [1] ' (varchar2) was expected to equal: 'number [2] ' (varchar2)% + at "UT3_USER.TEST_REPORTERS%", line 36 ut3_develop.ut.expect('number [1] ','Fails as values are different').to_equal('number [2] '); +% + 2) erroring_test + ORA-06502: PL/SQL: %: character to number conversion error + ORA-06512: at "UT3_USER.TEST_REPORTERS", line 44% + ORA-06512: at line 6 +Finished in % seconds +5 tests, 1 failed, 1 errored, 2 disabled, 0 warning(s)%]'; + + begin + select * + bulk collect into l_results + from table( + ut3_develop.ut.run( + 'test_reporters', + ut3_develop.ut_documentation_reporter() + ) + ); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + ut.expect(l_actual).to_be_like(l_expected); + end; + +end; +/ diff --git a/test/core/reporters/test_documentation_reporter.pks b/test/ut3_user/reporters/test_documentation_reporter.pks similarity index 81% rename from test/core/reporters/test_documentation_reporter.pks rename to test/ut3_user/reporters/test_documentation_reporter.pks index 09835abdc..ec6894c61 100644 --- a/test/core/reporters/test_documentation_reporter.pks +++ b/test/ut3_user/reporters/test_documentation_reporter.pks @@ -1,7 +1,7 @@ create or replace package test_documentation_reporter as --%suite(ut_documentation_reporter) - --%suitepath(utplsql.core.reporters) + --%suitepath(utplsql.test_user.reporters) --%test(Report produces expected output) procedure report_produces_expected_out; diff --git a/test/core/reporters/test_junit_reporter.pkb b/test/ut3_user/reporters/test_junit_reporter.pkb similarity index 68% rename from test/core/reporters/test_junit_reporter.pkb rename to test/ut3_user/reporters/test_junit_reporter.pkb index 6cd67b8a3..4a574591c 100644 --- a/test/core/reporters/test_junit_reporter.pkb +++ b/test/ut3_user/reporters/test_junit_reporter.pkb @@ -13,8 +13,9 @@ create or replace package body test_junit_reporter as execute immediate q'[create or replace package body check_junit_reporting is procedure test_do_stuff is begin - ut3.ut.expect(1).to_equal(1); - ut3.ut.expect(1).to_equal(2); + ut3_develop.ut.expect(1).to_equal(1); + ut3_develop.ut.expect(1).to_equal(2); + dbms_output.put_line(' ]]>'); end; end;]'; @@ -31,7 +32,7 @@ create or replace package body test_junit_reporter as execute immediate q'[create or replace package body check_junit_rep_suitepath is procedure check_junit_rep_suitepath is begin - ut3.ut.expect(1).to_equal(1); + ut3_develop.ut.expect(1).to_equal(1); end; end;]'; @@ -72,109 +73,81 @@ create or replace package body test_junit_reporter as execute immediate q'[create or replace package body Tst_Fix_Case_Sensitive as procedure bUgFiX is begin ut.expect(1).to_equal(1); end; end;]'; - - execute immediate q'[create or replace package check_fail_escape is - --%suitepath(core) - --%suite(checkfailedescape) - --%displayname(Check JUNIT XML failure is escaped) - - --%test(Fail Miserably) - procedure fail_miserably; - - end;]'; - - execute immediate q'[create or replace package body check_fail_escape is - procedure fail_miserably is - begin - ut3.ut.expect('test').to_equal(''); - end; - end;]'; end; procedure escapes_special_chars is - l_results ut3.ut_varchar2_list; + l_results ut3_develop.ut_varchar2_list; l_actual clob; begin --Act select * bulk collect into l_results - from table(ut3.ut.run('check_junit_reporting',ut3.ut_junit_reporter())); - l_actual := ut3.ut_utils.table_to_clob(l_results); + from table(ut3_develop.ut.run('check_junit_reporting',ut3_develop.ut_junit_reporter())); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); --Assert ut.expect(l_actual).not_to_be_like('%%'); ut.expect(l_actual).to_be_like('%<tag>%'); + ut.expect(l_actual).to_be_like(q'/% ]]]]> +]]>%/'); end; procedure reports_only_failed_or_errored is - l_results ut3.ut_varchar2_list; + l_results ut3_develop.ut_varchar2_list; l_actual clob; begin --Act select * bulk collect into l_results - from table(ut3.ut.run('check_junit_reporting',ut3.ut_junit_reporter())); - l_actual := ut3.ut_utils.table_to_clob(l_results); + from table(ut3_develop.ut.run('check_junit_reporting',ut3_develop.ut_junit_reporter())); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); --Assert ut.expect(l_actual).not_to_be_like('%Actual: 1 (number) was expected to equal: 1 (number)%'); ut.expect(l_actual).to_be_like('%Actual: 1 (number) was expected to equal: 2 (number)%'); end; procedure reports_xunit_only_fail_or_err is - l_results ut3.ut_varchar2_list; + l_results ut3_develop.ut_varchar2_list; l_actual clob; begin --Act select * bulk collect into l_results - from table(ut3.ut.run('check_junit_reporting',ut3.ut_xunit_reporter())); - l_actual := ut3.ut_utils.table_to_clob(l_results); + from table(ut3_develop.ut.run('check_junit_reporting',ut3_develop.ut_xunit_reporter())); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); --Assert ut.expect(l_actual).not_to_be_like('%Actual: 1 (number) was expected to equal: 1 (number)%'); ut.expect(l_actual).to_be_like('%Actual: 1 (number) was expected to equal: 2 (number)%'); end; - procedure reports_failed_line is - l_results ut3.ut_varchar2_list; - l_actual clob; - begin - --Act - select * - bulk collect into l_results - from table(ut3.ut.run('check_junit_reporting',ut3.ut_junit_reporter())); - l_actual := ut3.ut_utils.table_to_clob(l_results); - --Assert - ut.expect(l_actual).to_be_like('%at "%.CHECK_JUNIT_REPORTING%", line %'); - end; - procedure check_classname_suite is - l_results ut3.ut_varchar2_list; + l_results ut3_develop.ut_varchar2_list; l_actual clob; begin --Act select * bulk collect into l_results - from table(ut3.ut.run('check_junit_reporting',ut3.ut_junit_reporter())); - l_actual := ut3.ut_utils.table_to_clob(l_results); + from table(ut3_develop.ut.run('check_junit_reporting',ut3_develop.ut_junit_reporter())); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); --Assert ut.expect(l_actual).to_be_like('%testcase classname="check_junit_reporting" assertions="%" name="%"%'); end; procedure check_nls_number_formatting is - l_results ut3.ut_varchar2_list; + l_results ut3_develop.ut_varchar2_list; l_actual clob; l_nls_numeric_characters varchar2(30); begin --Arrange - select nsp.value into l_nls_numeric_characters + select replace(nsp.value,'''','''''') into l_nls_numeric_characters from nls_session_parameters nsp where parameter = 'NLS_NUMERIC_CHARACTERS'; execute immediate q'[alter session set NLS_NUMERIC_CHARACTERS=', ']'; --Act select * bulk collect into l_results - from table(ut3.ut.run('check_junit_reporting', ut3.ut_junit_reporter())); - l_actual := ut3.ut_utils.table_to_clob(l_results); + from table(ut3_develop.ut.run('check_junit_reporting', ut3_develop.ut_junit_reporter())); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); --Assert ut.expect(l_actual).to_match('time="[0-9]*\.[0-9]{3,6}"'); --Cleanup @@ -182,20 +155,20 @@ create or replace package body test_junit_reporter as end; procedure check_classname_suitepath is - l_results ut3.ut_varchar2_list; + l_results ut3_develop.ut_varchar2_list; l_actual clob; begin --Act select * bulk collect into l_results - from table(ut3.ut.run('check_junit_rep_suitepath',ut3.ut_junit_reporter())); - l_actual := ut3.ut_utils.table_to_clob(l_results); + from table(ut3_develop.ut.run('check_junit_rep_suitepath',ut3_develop.ut_junit_reporter())); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); --Assert ut.expect(l_actual).to_be_like('%testcase classname="core.check_junit_rep_suitepath" assertions="%" name="%"%'); end; procedure report_test_without_desc is - l_results ut3.ut_varchar2_list; + l_results ut3_develop.ut_varchar2_list; l_actual clob; l_expected varchar2(32767):= q'[ @@ -215,13 +188,13 @@ create or replace package body test_junit_reporter as begin select * bulk collect into l_results - from table(ut3.ut.run('tst_package_junit_nodesc',ut3.ut_junit_reporter())); - l_actual := ut3.ut_utils.table_to_clob(l_results); + from table(ut3_develop.ut.run('tst_package_junit_nodesc',ut3_develop.ut_junit_reporter())); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); ut.expect(l_actual).to_be_like(l_expected); end; procedure report_suite_without_desc is - l_results ut3.ut_varchar2_list; + l_results ut3_develop.ut_varchar2_list; l_actual clob; l_expected varchar2(32767):= q'[ @@ -237,21 +210,21 @@ create or replace package body test_junit_reporter as begin select * bulk collect into l_results - from table(ut3.ut.run('tst_package_junit_nosuite',ut3.ut_junit_reporter())); - l_actual := ut3.ut_utils.table_to_clob(l_results); + from table(ut3_develop.ut.run('tst_package_junit_nosuite',ut3_develop.ut_junit_reporter())); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); ut.expect(l_actual).to_be_like(l_expected); end; procedure reporort_produces_expected_out is - l_results ut3.ut_varchar2_list; + l_results ut3_develop.ut_varchar2_list; l_actual clob; l_expected varchar2(32767):=q'[ - - - - - - + + + + + + % @@ -276,6 +249,13 @@ create or replace package body test_junit_reporter as + + + + + + + @@ -293,26 +273,20 @@ create or replace package body test_junit_reporter as begin select * bulk collect into l_results - from table(ut3.ut.run('test_reporters',ut3.ut_junit_reporter())); - l_actual := ut3.ut_utils.table_to_clob(l_results); + from table(ut3_develop.ut.run('test_reporters',ut3_develop.ut_junit_reporter())); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); ut.expect(l_actual).to_be_like(l_expected); end; procedure check_failure_escaped is - l_results ut3.ut_varchar2_list; + l_results ut3_develop.ut_varchar2_list; l_actual clob; begin - --Act - select * - bulk collect into l_results - from table(ut3.ut.run('check_fail_escape',ut3.ut_junit_reporter())); - l_actual := ut3.ut_utils.table_to_clob(l_results); - --Assert - ut.expect(l_actual).to_be_like('%Actual: 'test' (varchar2) was expected to equal: '<![CDATA[some stuff]]>' (varchar2)%'); + reporters.check_xml_failure_escaped(ut3_develop.ut_junit_reporter()); end; procedure check_classname_is_populated is - l_results ut3.ut_varchar2_list; + l_results ut3_develop.ut_varchar2_list; l_actual clob; l_expected varchar2(32767):= q'[ @@ -328,14 +302,14 @@ create or replace package body test_junit_reporter as begin select * bulk collect into l_results - from table(ut3.ut.run('Tst_Fix_Case_Sensitive',ut3.ut_junit_reporter())); - l_actual := ut3.ut_utils.table_to_clob(l_results); + from table(ut3_develop.ut.run('Tst_Fix_Case_Sensitive',ut3_develop.ut_junit_reporter())); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); ut.expect(l_actual).to_be_like(l_expected); end; procedure check_encoding_included is begin - reporters.check_xml_encoding_included(ut3.ut_junit_reporter(), 'UTF-8'); + reporters.check_xml_encoding_included(ut3_develop.ut_junit_reporter(), 'UTF-8'); end; procedure remove_test_package is @@ -345,7 +319,6 @@ create or replace package body test_junit_reporter as execute immediate 'drop package check_junit_rep_suitepath'; execute immediate 'drop package tst_package_junit_nodesc'; execute immediate 'drop package tst_package_junit_nosuite'; - execute immediate 'drop package check_fail_escape'; execute immediate 'drop package Tst_Fix_Case_Sensitive'; end; diff --git a/test/core/reporters/test_junit_reporter.pks b/test/ut3_user/reporters/test_junit_reporter.pks similarity index 92% rename from test/core/reporters/test_junit_reporter.pks rename to test/ut3_user/reporters/test_junit_reporter.pks index b39c5ff03..71443c180 100644 --- a/test/core/reporters/test_junit_reporter.pks +++ b/test/ut3_user/reporters/test_junit_reporter.pks @@ -1,7 +1,7 @@ create or replace package test_junit_reporter as --%suite(ut_junit_reporter) - --%suitepath(utplsql.core.reporters) + --%suitepath(utplsql.test_user.reporters) --%beforeall procedure create_a_test_package; @@ -15,9 +15,6 @@ create or replace package test_junit_reporter as --%test(Xunit Backward Compatibility - Reports only failed expectations and exceptions) procedure reports_xunit_only_fail_or_err; - --%test(Reports failed line of test) - procedure reports_failed_line; - --%test(Check that classname is returned correct suite) procedure check_classname_suite; diff --git a/test/ut3_user/reporters/test_realtime_reporter.pkb b/test/ut3_user/reporters/test_realtime_reporter.pkb new file mode 100644 index 000000000..84053c3c9 --- /dev/null +++ b/test/ut3_user/reporters/test_realtime_reporter.pkb @@ -0,0 +1,536 @@ +create or replace package body test_realtime_reporter as + + g_events ut3_tester_helper.test_event_list := ut3_tester_helper.test_event_list(); + + procedure create_test_suites_and_run is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package check_realtime_reporting1 is + --%suite(suite ) + --%suitepath(realtime_reporting) + + --%context + --%name(test_context) + + --%test(test 1 - OK) + procedure test_1_ok; + + --%test(test 2 - NOK) + procedure test_2_nok; + + --%endcontext + end;]'; + execute immediate q'[create or replace package body check_realtime_reporting1 is + procedure test_1_ok is + begin + ut3_develop.ut.expect(1).to_equal(1); + end; + + procedure test_2_nok is + begin + ut3_develop.ut.expect(1).to_equal(2); + end; + end;]'; + + execute immediate q'[create or replace package check_realtime_reporting2 is + --%suite + --%suitepath(realtime_reporting) + + --%test + procedure test_3_ok; + + --%test + procedure test_4_nok; + + --%test + --%disabled + procedure test_5; + + --%test + --%disabled(Cannot run this item at this time runtime > 10 mins.) + procedure test_6_disabled_reason; + end;]'; + execute immediate q'[create or replace package body check_realtime_reporting2 is + procedure test_3_ok is + begin + ut3_develop.ut.expect(2).to_equal(2); + end; + + procedure test_4_nok is + begin + ut3_develop.ut.expect(2).to_equal(3); + ut3_develop.ut.expect(2).to_equal(4); + end; + + procedure test_5 is + begin + null; + end; + + procedure test_6_disabled_reason is + begin + null; + end; + end;]'; + + execute immediate q'[create or replace package check_realtime_reporting3 is + --%suite + --%suitepath(realtime_reporting) + + --%test + procedure test_6_with_runtime_error; + + --%test + procedure test_7_with_serveroutput; + + --%afterall + procedure print_and_raise; + end;]'; + execute immediate q'[create or replace package body check_realtime_reporting3 is + procedure test_6_with_runtime_error is + l_actual integer; + begin + execute immediate 'select 6 from non_existing_table' into l_actual; + ut3_develop.ut.expect(6).to_equal(l_actual); + end; + + procedure test_7_with_serveroutput is + begin + dbms_output.put_line('before test 7'); + ut3_develop.ut.expect(7).to_equal(7); + dbms_output.put_line('after test 7'); + end; + + procedure print_and_raise is + begin + dbms_output.put_line('Now, a no_data_found exception is raised'); + dbms_output.put_line('dbms_output and error stack is reported for this suite.'); + dbms_output.put_line('A runtime error in afterall is counted as a warning.'); + raise no_data_found; + end; + end;]'; + + execute immediate q'[create or replace package check_realtime_reporting4 is + --%suite + --%suitepath(realtime_reporting) + /* tag annotation without parameter will raise a warning */ + --%tags + + --%test + procedure test_8_with_warning; + end;]'; + execute immediate q'[create or replace package body check_realtime_reporting4 is + procedure test_8_with_warning is + begin + commit; -- this will raise a warning + ut3_develop.ut.expect(8).to_equal(8); + end; + end;]'; + + execute immediate q'[create or replace package check_realtime_reporting5 is + --%suite + --%suitepath(realtime_reporting_bufix) + + --%test(test XML with nested CDATA) + procedure test_nested_cdata; + end;]'; + + execute immediate q'[create or replace package body check_realtime_reporting5 is + procedure test_nested_cdata is + begin + dbms_output.put_line('nested cdata block: , to be handled.'); + ut.expect(1).to_equal(1); + end; + end;]'; + + <> + declare + l_reporter ut3_develop.ut_realtime_reporter := ut3_develop.ut_realtime_reporter(); + begin + -- produce + ut3_develop.ut_runner.run( + a_paths => ut3_develop.ut_varchar2_list(':realtime_reporting'), + a_reporters => ut3_develop.ut_reporters(l_reporter) + ); + -- consume + select ut3_tester_helper.test_event_object(item_type, xmltype(text)) + bulk collect into g_events + from table(l_reporter.get_lines()) + where trim(text) is not null and item_type is not null; + end run_report_and_cache_result; + end create_test_suites_and_run; + + procedure xml_report_structure is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + open l_actual for + select t.event_doc.extract('/event/@type').getstringval() as event_type, + t.event_doc.extract('/event/suite/@id|/event/test/@id').getstringval() as item_id + from table(g_events) t; + open l_expected for + select 'pre-run' as event_type, null as item_id from dual union all + select 'pre-suite' as event_type, 'realtime_reporting' as item_id from dual union all + select 'pre-suite' as event_type, 'realtime_reporting.check_realtime_reporting4' as item_id from dual union all + select 'pre-test' as event_type, 'realtime_reporting.check_realtime_reporting4.test_8_with_warning' as item_id from dual union all + select 'post-test' as event_type, 'realtime_reporting.check_realtime_reporting4.test_8_with_warning' as item_id from dual union all + select 'post-suite' as event_type, 'realtime_reporting.check_realtime_reporting4' as item_id from dual union all + select 'pre-suite' as event_type, 'realtime_reporting.check_realtime_reporting3' as item_id from dual union all + select 'pre-test' as event_type, 'realtime_reporting.check_realtime_reporting3.test_6_with_runtime_error' as item_id from dual union all + select 'post-test' as event_type, 'realtime_reporting.check_realtime_reporting3.test_6_with_runtime_error' as item_id from dual union all + select 'pre-test' as event_type, 'realtime_reporting.check_realtime_reporting3.test_7_with_serveroutput' as item_id from dual union all + select 'post-test' as event_type, 'realtime_reporting.check_realtime_reporting3.test_7_with_serveroutput' as item_id from dual union all + select 'post-suite' as event_type, 'realtime_reporting.check_realtime_reporting3' as item_id from dual union all + select 'pre-suite' as event_type, 'realtime_reporting.check_realtime_reporting2' as item_id from dual union all + select 'pre-test' as event_type, 'realtime_reporting.check_realtime_reporting2.test_3_ok' as item_id from dual union all + select 'post-test' as event_type, 'realtime_reporting.check_realtime_reporting2.test_3_ok' as item_id from dual union all + select 'pre-test' as event_type, 'realtime_reporting.check_realtime_reporting2.test_4_nok' as item_id from dual union all + select 'post-test' as event_type, 'realtime_reporting.check_realtime_reporting2.test_4_nok' as item_id from dual union all + select 'pre-test' as event_type, 'realtime_reporting.check_realtime_reporting2.test_5' as item_id from dual union all + select 'post-test' as event_type, 'realtime_reporting.check_realtime_reporting2.test_5' as item_id from dual union all + select 'pre-test' as event_type, 'realtime_reporting.check_realtime_reporting2.test_6_disabled_reason' as item_id from dual union all + select 'post-test' as event_type, 'realtime_reporting.check_realtime_reporting2.test_6_disabled_reason' as item_id from dual union all + select 'post-suite' as event_type, 'realtime_reporting.check_realtime_reporting2' as item_id from dual union all + select 'pre-suite' as event_type, 'realtime_reporting.check_realtime_reporting1' as item_id from dual union all + select 'pre-suite' as event_type, 'realtime_reporting.check_realtime_reporting1.test_context' as item_id from dual union all + select 'pre-test' as event_type, 'realtime_reporting.check_realtime_reporting1.test_context.test_1_ok' as item_id from dual union all + select 'post-test' as event_type, 'realtime_reporting.check_realtime_reporting1.test_context.test_1_ok' as item_id from dual union all + select 'pre-test' as event_type, 'realtime_reporting.check_realtime_reporting1.test_context.test_2_nok' as item_id from dual union all + select 'post-test' as event_type, 'realtime_reporting.check_realtime_reporting1.test_context.test_2_nok' as item_id from dual union all + select 'post-suite' as event_type, 'realtime_reporting.check_realtime_reporting1.test_context' as item_id from dual union all + select 'post-suite' as event_type, 'realtime_reporting.check_realtime_reporting1' as item_id from dual union all + select 'post-suite' as event_type, 'realtime_reporting' as item_id from dual union all + select 'post-run' as event_type, null as item_id from dual; + ut.expect(l_actual).to_equal(l_expected); + end xml_report_structure; + + procedure pre_run_composite_nodes is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + open l_actual for + select x.node_path + from table(g_events) t, + xmltable( + q'[ + for $i in //(event|items|suite|test) + return {$i/string-join(ancestor-or-self::*/name(.), '/')} + ]' + passing t.event_doc + columns node_path varchar2(128) path '.' + ) x + where event_type = 'pre-run'; + open l_expected for + select 'event' as node_path from dual union all + select 'event/items' as node_path from dual union all + select 'event/items/suite' as node_path from dual union all + select 'event/items/suite/items' as node_path from dual union all + select 'event/items/suite/items/suite' as node_path from dual union all + select 'event/items/suite/items/suite/items' as node_path from dual union all + select 'event/items/suite/items/suite/items/test' as node_path from dual union all + select 'event/items/suite/items/suite' as node_path from dual union all + select 'event/items/suite/items/suite/items' as node_path from dual union all + select 'event/items/suite/items/suite/items/test' as node_path from dual union all + select 'event/items/suite/items/suite/items/test' as node_path from dual union all + select 'event/items/suite/items/suite' as node_path from dual union all + select 'event/items/suite/items/suite/items' as node_path from dual union all + select 'event/items/suite/items/suite/items/test' as node_path from dual union all + select 'event/items/suite/items/suite/items/test' as node_path from dual union all + select 'event/items/suite/items/suite/items/test' as node_path from dual union all + select 'event/items/suite/items/suite/items/test' as node_path from dual union all + select 'event/items/suite/items/suite' as node_path from dual union all + select 'event/items/suite/items/suite/items' as node_path from dual union all + select 'event/items/suite/items/suite/items/suite' as node_path from dual union all + select 'event/items/suite/items/suite/items/suite/items' as node_path from dual union all + select 'event/items/suite/items/suite/items/suite/items/test' as node_path from dual union all + select 'event/items/suite/items/suite/items/suite/items/test' as node_path from dual; + ut.expect(l_actual).to_equal(l_expected); + end pre_run_composite_nodes; + + procedure total_number_of_tests is + l_actual integer; + l_expected integer := 9; + begin + select t.event_doc.extract('/event/totalNumberOfTests/text()').getnumberval() + into l_actual + from table(g_events) t + where t.event_type = 'pre-run'; + ut.expect(l_actual).to_equal(l_expected); + end total_number_of_tests; + + procedure execution_time_of_run is + l_actual number; + begin + select t.event_doc.extract('/event/run/executionTime/text()').getnumberval() + into l_actual + from table(g_events) t + where t.event_type = 'post-run'; + ut.expect(l_actual).to_be_not_null; + end execution_time_of_run; + + procedure escaped_characters is + l_actual varchar2(32767); + l_expected varchar2(20) := 'suite <A>'; + begin + select t.event_doc.extract( + '//suite[@id="realtime_reporting.check_realtime_reporting1"]/description/text()' + ).getstringval() + into l_actual + from table(g_events) t + where t.event_type = 'pre-run'; + ut.expect(l_actual).to_equal(l_expected); + end escaped_characters; + + procedure pre_test_nodes is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + open l_actual for + select t.event_doc.extract('//test/testNumber/text()') + .getnumberval() as test_number, + t.event_doc.extract('//test/totalNumberOfTests/text()') + .getnumberval() as total_number_of_tests + from table(g_events) t + where t.event_type = 'pre-test' + and t.event_doc.extract('//test/@id').getstringval() is not null; + open l_expected for + select level as test_number, + 9 as total_number_of_tests + from dual + connect by level <= 9; + ut.expect(l_actual).to_equal(l_expected).unordered; + end pre_test_nodes; + + procedure post_test_nodes is + l_actual sys_refcursor; + l_expected sys_refcursor; + begin + open l_actual for + select t.event_doc.extract('//test/testNumber/text()') + .getnumberval() as test_number, + t.event_doc.extract('//test/totalNumberOfTests/text()') + .getnumberval() as total_number_of_tests + from table(g_events) t + where t.event_type = 'post-test' + and t.event_doc.extract('//test/@id').getstringval() is not null + and t.event_doc.extract('//test/startTime/text()').getstringval() is not null + and t.event_doc.extract('//test/endTime/text()').getstringval() is not null + and t.event_doc.extract('//test/executionTime/text()').getnumberval() is not null + and t.event_doc.extract('//test/counter/disabled/text()').getnumberval() is not null + and t.event_doc.extract('//test/counter/success/text()').getnumberval() is not null + and t.event_doc.extract('//test/counter/failure/text()').getnumberval() is not null + and t.event_doc.extract('//test/counter/error/text()').getnumberval() is not null + and t.event_doc.extract('//test/counter/warning/text()').getnumberval() is not null; + open l_expected for + select level as test_number, + 9 as total_number_of_tests + from dual + connect by level <= 9; + ut.expect(l_actual).to_equal(l_expected).unordered; + end post_test_nodes; + + procedure single_failed_message is + l_actual varchar2(32767); + l_expected varchar2(80) := ''; + begin + select t.event_doc.extract( + '/event/test/failedExpectations/expectation[1]/message/text()' + ).getstringval() + into l_actual + from table(g_events) t + where t.event_doc.extract('/event[@type="post-test"]/test/@id').getstringval() + = 'realtime_reporting.check_realtime_reporting1.test_context.test_2_nok'; + ut.expect(l_actual).to_equal(l_expected); + end single_failed_message; + + procedure multiple_failed_messages is + l_actual integer; + l_expected integer := 2; + begin + select count(*) + into l_actual + from table(g_events) t, + xmltable( + '/event/test/failedExpectations/expectation' + passing t.event_doc + columns message clob path 'message', + caller clob path 'caller' + ) x + where t.event_doc.extract('/event[@type="post-test"]/test/@id').getstringval() + = 'realtime_reporting.check_realtime_reporting2.test_4_nok' + and x.message is not null + and x.caller is not null; + ut.expect(l_actual).to_equal(l_expected); + end multiple_failed_messages; + + procedure serveroutput_of_test is + l_actual clob; + l_expected_list ut3_develop.ut_varchar2_list; + l_expected clob; + begin + select t.event_doc.extract('//event/test/serverOutput/text()').getstringval() + into l_actual + from table(g_events) t + where t.event_doc.extract('/event[@type="post-test"]/test/@id').getstringval() + = 'realtime_reporting.check_realtime_reporting3.test_7_with_serveroutput'; + ut3_tester_helper.main_helper.append_to_list(l_expected_list, ''); + l_expected := ut3_tester_helper.main_helper.table_to_clob(l_expected_list); + ut.expect(l_actual).to_equal(l_expected); + end serveroutput_of_test; + + procedure serveroutput_of_testsuite is + l_actual clob; + l_expected_list ut3_develop.ut_varchar2_list; + l_expected clob; + begin + select t.event_doc.extract('//event/suite/serverOutput/text()').getstringval() + into l_actual + from table(g_events) t + where t.event_doc.extract('/event[@type="post-suite"]/suite/@id').getstringval() + = 'realtime_reporting.check_realtime_reporting3'; + ut3_tester_helper.main_helper.append_to_list(l_expected_list, ''); + l_expected := ut3_tester_helper.main_helper.table_to_clob(l_expected_list); + ut.expect(l_actual).to_equal(l_expected); + end serveroutput_of_testsuite; + + procedure error_stack_of_test is + l_actual clob; + l_expected_list ut3_develop.ut_varchar2_list; + l_expected clob; + begin + select t.event_doc.extract('//event/test/errorStack/text()').getstringval() + into l_actual + from table(g_events) t + where t.event_doc.extract('/event[@type="post-test"]/test/@id').getstringval() + = 'realtime_reporting.check_realtime_reporting3.test_6_with_runtime_error'; + ut3_tester_helper.main_helper.append_to_list(l_expected_list, ''); + l_expected := ut3_tester_helper.main_helper.table_to_clob(l_expected_list); + ut.expect(l_actual).to_be_like(l_expected); + end error_stack_of_test; + + procedure error_stack_of_testsuite is + l_actual clob; + l_expected_list ut3_develop.ut_varchar2_list; + l_expected clob; + begin + select t.event_doc.extract('//event/suite/errorStack/text()').getstringval() + into l_actual + from table(g_events) t + where t.event_doc.extract('/event[@type="post-suite"]/suite/@id').getstringval() + = 'realtime_reporting.check_realtime_reporting3'; + ut3_tester_helper.main_helper.append_to_list(l_expected_list, ''); + l_expected := ut3_tester_helper.main_helper.table_to_clob(l_expected_list); + ut.expect(l_actual).to_be_like(l_expected); + end error_stack_of_testsuite; + + procedure warnings_of_test is + l_actual clob; + l_expected_list ut3_develop.ut_varchar2_list; + l_expected clob; + begin + select t.event_doc.extract('//event/test/warnings/text()').getstringval() + into l_actual + from table(g_events) t + where t.event_doc.extract('/event[@type="post-test"]/test/@id').getstringval() + = 'realtime_reporting.check_realtime_reporting4.test_8_with_warning'; + ut3_tester_helper.main_helper.append_to_list(l_expected_list, ''); + l_expected := ut3_tester_helper.main_helper.table_to_clob(l_expected_list); + ut.expect(l_actual).to_be_like(l_expected); + end warnings_of_test; + + procedure warnings_of_testsuite is + l_actual clob; + l_expected_list ut3_develop.ut_varchar2_list; + l_expected clob; + begin + select t.event_doc.extract('//event/suite/warnings/text()').getstringval() + into l_actual + from table(g_events) t + where t.event_doc.extract('/event[@type="post-suite"]/suite/@id').getstringval() + = 'realtime_reporting.check_realtime_reporting4'; + ut3_tester_helper.main_helper.append_to_list(l_expected_list, ''); + l_expected := ut3_tester_helper.main_helper.table_to_clob(l_expected_list); + ut.expect(l_actual).to_be_like(l_expected); + end warnings_of_testsuite; + + procedure get_description is + l_reporter ut3_develop.ut_realtime_reporter; + l_actual varchar2(4000); + l_expected varchar2(80) := '%SQL Developer%'; + begin + l_reporter := ut3_develop.ut_realtime_reporter(); + l_actual := l_reporter.get_description(); + ut.expect(l_actual).to_be_like(l_expected); + end get_description; + + procedure nested_cdata_output is + l_text varchar2(4000); + l_xml xmltype; + -- + function produce_and_consume return varchar2 is + pragma autonomous_transaction; + l_reporter ut3_develop.ut_realtime_reporter := ut3_develop.ut_realtime_reporter(); + l_text varchar2(4000); + begin + -- produce + ut3_develop.ut_runner.run( + a_paths => ut3_develop.ut_varchar2_list(':realtime_reporting_bufix'), + a_reporters => ut3_develop.ut_reporters(l_reporter) + ); + -- consume + select text + into l_text + from table(l_reporter.get_lines()) + where item_type = 'post-test'; + return l_text; + end produce_and_consume; + begin + l_text := produce_and_consume(); + ut.expect(l_text).to_be_not_null(); + -- this fails, if l_text is not a valid XML + l_xml := xmltype(l_text); + ut.expect(l_xml is not null).to_be_true(); + end; + + procedure disabled_reason is + l_actual varchar2(32767); + l_expected varchar2(80) := dbms_xmlgen.convert('Cannot run this item at this time runtime > 10 mins.'); + begin + select t.event_doc.extract( + '//test/disabledReason/text()' + ).getstringval() + into l_actual + from table(g_events) t + where xmlexists( + '/event[@type="pre-run"]/*//test[@id="realtime_reporting.check_realtime_reporting2.test_6_disabled_reason"]' + passing t.event_doc + ); + ut.expect(l_actual).to_equal(l_expected); + end; + + procedure remove_test_suites is + pragma autonomous_transaction; + begin + execute immediate 'drop package check_realtime_reporting1'; + execute immediate 'drop package check_realtime_reporting2'; + execute immediate 'drop package check_realtime_reporting3'; + execute immediate 'drop package check_realtime_reporting4'; + execute immediate 'drop package check_realtime_reporting5'; + end remove_test_suites; + +end test_realtime_reporter; +/ diff --git a/test/ut3_user/reporters/test_realtime_reporter.pks b/test/ut3_user/reporters/test_realtime_reporter.pks new file mode 100644 index 000000000..087713f79 --- /dev/null +++ b/test/ut3_user/reporters/test_realtime_reporter.pks @@ -0,0 +1,67 @@ +create or replace package test_realtime_reporter as + + --%suite(ut_realtime_reporter) + --%suitepath(utplsql.test_user.reporters) + + --%beforeall + procedure create_test_suites_and_run; + + --%test(Provide a report structure with pre-run information and event based messages per suite and per test) + procedure xml_report_structure; + + --%test(Provide the total number of tests as part of the pre-run information structure) + procedure total_number_of_tests; + + --%test(Provide composite structure for items, an item is either a suite or a test, suites may have nested items) + procedure pre_run_composite_nodes; + + --%test(Provide the execution time as part of the post-run information structure) + procedure execution_time_of_run; + + --%test(Escape special characters in data such as the test suite description) + procedure escaped_characters; + + --%test(Provide a node before starting a test with testNumber and totalNumberOfTests) + procedure pre_test_nodes; + + --%test(Provide a node after completion of a test with test results) + procedure post_test_nodes; + + --%test(Provide expectation message for a failed test) + procedure single_failed_message; + + --%test(Provide expectation messages for each failed assertion of a failed test) + procedure multiple_failed_messages; + + --%test(Provide dbms_output produced in a test) + procedure serveroutput_of_test; + + --%test(Provide dbms_output produced in a testsuite) + procedure serveroutput_of_testsuite; + + --%test(Provide the error stack of a test) + procedure error_stack_of_test; + + --%test(Provide the error stack of a testsuite) + procedure error_stack_of_testsuite; + + --%test(Provide warnings of a test) + procedure warnings_of_test; + + --%test(Provide warnings of a testsuite) + procedure warnings_of_testsuite; + + --%test(Provide a description of the reporter explaining the use for SQL Developer) + procedure get_description; + + --%test(Escape nested CDATA sections in test output) + procedure nested_cdata_output; + + --%test(Provide reason disabled test) + procedure disabled_reason; + + --%afterall + procedure remove_test_suites; + +end test_realtime_reporter; +/ diff --git a/test/core/reporters/test_sonar_test_reporter.pkb b/test/ut3_user/reporters/test_sonar_test_reporter.pkb similarity index 53% rename from test/core/reporters/test_sonar_test_reporter.pkb rename to test/ut3_user/reporters/test_sonar_test_reporter.pkb index 9cf38ea91..7c30fd91d 100644 --- a/test/core/reporters/test_sonar_test_reporter.pkb +++ b/test/ut3_user/reporters/test_sonar_test_reporter.pkb @@ -1,7 +1,7 @@ create or replace package body test_sonar_test_reporter as procedure report_produces_expected_out is - l_results ut3.ut_varchar2_list; + l_results ut3_develop.ut_varchar2_list; l_actual clob; l_expected varchar2(32767):=q'[ @@ -9,7 +9,8 @@ create or replace package body test_sonar_test_reporter as % %%% %%% -%% +%% +%% ]'; @@ -17,19 +18,24 @@ create or replace package body test_sonar_test_reporter as select * bulk collect into l_results from table( - ut3.ut.run( + ut3_develop.ut.run( 'test_reporters', - ut3.ut_sonar_test_reporter(), - a_test_file_mappings => ut3.ut_file_mapper.build_file_mappings( user, ut3.ut_varchar2_list('tests/helpers/test_reporters.pkb')) + ut3_develop.ut_sonar_test_reporter(), + a_test_file_mappings => ut3_develop.ut_file_mapper.build_file_mappings( sys_context('USERENV', 'CURRENT_USER'), ut3_develop.ut_varchar2_list('tests/helpers/test_reporters.pkb')) ) ); - l_actual := ut3.ut_utils.table_to_clob(l_results); + l_actual :=ut3_tester_helper.main_helper.table_to_clob(l_results); ut.expect(l_actual).to_be_like(l_expected); end; procedure check_encoding_included is begin - reporters.check_xml_encoding_included(ut3.ut_sonar_test_reporter(), 'UTF-8'); + reporters.check_xml_encoding_included(ut3_develop.ut_sonar_test_reporter(), 'UTF-8'); + end; + + procedure check_failure_escaped is + begin + reporters.check_xml_failure_escaped(ut3_develop.ut_sonar_test_reporter()); end; end; diff --git a/test/core/reporters/test_sonar_test_reporter.pks b/test/ut3_user/reporters/test_sonar_test_reporter.pks similarity index 67% rename from test/core/reporters/test_sonar_test_reporter.pks rename to test/ut3_user/reporters/test_sonar_test_reporter.pks index ab4776c38..ade449dba 100644 --- a/test/core/reporters/test_sonar_test_reporter.pks +++ b/test/ut3_user/reporters/test_sonar_test_reporter.pks @@ -1,7 +1,7 @@ create or replace package test_sonar_test_reporter as --%suite(ut_sonar_test_reporter) - --%suitepath(utplsql.core.reporters) + --%suitepath(utplsql.test_user.reporters) --%test(Report produces expected output) procedure report_produces_expected_out; @@ -9,5 +9,8 @@ create or replace package test_sonar_test_reporter as --%test(Includes XML header with encoding when encoding provided) procedure check_encoding_included; + --%test( Validate that fail with special char are escaped ) + procedure check_failure_escaped; + end; / diff --git a/test/ut3_user/reporters/test_teamcity_reporter.pkb b/test/ut3_user/reporters/test_teamcity_reporter.pkb new file mode 100644 index 000000000..517ddc037 --- /dev/null +++ b/test/ut3_user/reporters/test_teamcity_reporter.pkb @@ -0,0 +1,197 @@ +create or replace package body test_teamcity_reporter as + + procedure create_a_test_package is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package check_escape_special_chars is + --%suite(A suite with 'quote') + + --%test(A test with 'quote') + procedure test_do_stuff; + + end;]'; + execute immediate q'[create or replace package body check_escape_special_chars is + procedure test_do_stuff is + begin + ut3_develop.ut.expect(' [ ' || chr(13) || chr(10) || ' ] ' ).to_be_null; + end; + + end;]'; + + execute immediate q'[create or replace package check_trims_long_output is + --%suite + + --%test + procedure long_output; + end;]'; + execute immediate q'[create or replace package body check_trims_long_output is + procedure long_output is + begin + ut3_develop.ut.expect(rpad('aVarchar',4000,'a')).to_be_null; + end; + end;]'; + + execute immediate q'[create or replace package check_multiple_failures is + --%suite + + --%test + procedure multi_failure; + + --%test + procedure multi_failure_on_error; + end;]'; + execute immediate q'[create or replace package body check_multiple_failures is + procedure multi_failure is + begin + ut3_develop.ut.expect(1).to_be_null; + ut3_develop.ut.expect(2).to_equal(1); + ut3_develop.ut.expect('Bad').to_equal('Good'); + end; + procedure multi_failure_on_error is + l_integer_variable integer; + begin + ut3_develop.ut.expect(1).to_be_null; + ut3_develop.ut.expect(2).to_equal(1); + ut3_develop.ut.expect('Bad').to_equal('Good'); + l_integer_variable := 'a string'; + end; + end;]'; + + end; + + + procedure report_produces_expected_out is + l_output_data ut3_develop.ut_varchar2_list; + l_expected varchar2(32767); + begin + l_expected := q'{%##teamcity[testSuiteStarted timestamp='%' name='org'] +%##teamcity[testSuiteStarted timestamp='%' name='org.utplsql'] +%##teamcity[testSuiteStarted timestamp='%' name='org.utplsql.tests'] +%##teamcity[testSuiteStarted timestamp='%' name='org.utplsql.tests.helpers'] +%##teamcity[testSuiteStarted timestamp='%' name='A suite for testing different outcomes from reporters'] +%##teamcity[testSuiteStarted timestamp='%' name='A description of some context'] +%##teamcity[testStarted timestamp='%' captureStandardOutput='true' name='ut3_user.test_reporters.passing_test'] + + + + + +%##teamcity[testFinished timestamp='%' duration='%' name='ut3_user.test_reporters.passing_test'] +%##teamcity[testSuiteFinished timestamp='%' name='A description of some context'] +%##teamcity[testStarted timestamp='%' captureStandardOutput='true' name='ut3_user.test_reporters.failing_test'] + + + +%##teamcity[testFailed timestamp='%' details='Actual: |'number |[1|] |' (varchar2) was expected to equal: |'number |[2|] |' (varchar2)' message='Fails as values are different' name='ut3_user.test_reporters.failing_test'] +%##teamcity[testFinished timestamp='%' duration='%' name='ut3_user.test_reporters.failing_test'] +%##teamcity[testStarted timestamp='%' captureStandardOutput='true' name='ut3_user.test_reporters.erroring_test'] + + + +%##teamcity[testStdErr timestamp='%' name='ut3_user.test_reporters.erroring_test' out='Test exception:|nORA-06502: PL/SQL: %: character to number conversion error|nORA-06512: at "UT3_USER.TEST_REPORTERS", line %|nORA-06512: at %|n'] +%##teamcity[testFailed timestamp='%' details='Test exception:|nORA-06502: PL/SQL: %: character to number conversion error|nORA-06512: at "UT3_USER.TEST_REPORTERS", line %|nORA-06512: at %|n' message='Error occured' name='ut3_user.test_reporters.erroring_test'] +%##teamcity[testFinished timestamp='%' duration='%' name='ut3_user.test_reporters.erroring_test'] +%##teamcity[testStarted timestamp='%' captureStandardOutput='true' name='ut3_user.test_reporters.disabled_test'] +%##teamcity[testIgnored timestamp='%' name='ut3_user.test_reporters.disabled_test'] +%##teamcity[testSuiteFinished timestamp='%' name='A suite for testing different outcomes from reporters'] +%##teamcity[testSuiteFinished timestamp='%' name='org.utplsql.tests.helpers'] +%##teamcity[testSuiteFinished timestamp='%' name='org.utplsql.tests'] +%##teamcity[testSuiteFinished timestamp='%' name='org.utplsql'] +%##teamcity[testSuiteFinished timestamp='%' name='org']}'; + --act + select * + bulk collect into l_output_data + from table(ut3_develop.ut.run('test_reporters',ut3_develop.ut_teamcity_reporter())); + + --assert + ut.expect(ut3_tester_helper.main_helper.table_to_clob(l_output_data)).to_be_like(l_expected); + end; + + procedure escape_special_chars is + l_output_data ut3_develop.ut_varchar2_list; + l_expected varchar2(32767); + begin + l_expected := q'{%##teamcity[testSuiteStarted timestamp='%' name='A suite with |'quote|''] +%##teamcity[testStarted timestamp='%' captureStandardOutput='true' name='ut3_user.check_escape_special_chars.test_do_stuff'] +%##teamcity[testFailed timestamp='%' details='Actual: (varchar2)|n |' |[ |r|n |] |'|n was expected to be null' name='ut3_user.check_escape_special_chars.test_do_stuff'] +%##teamcity[testFinished timestamp='%' duration='%' name='ut3_user.check_escape_special_chars.test_do_stuff'] +%##teamcity[testSuiteFinished timestamp='%' name='A suite with |'quote|'']}'; + --act + select * + bulk collect into l_output_data + from table(ut3_develop.ut.run('check_escape_special_chars',ut3_develop.ut_teamcity_reporter())); + + --assert + ut.expect(ut3_tester_helper.main_helper.table_to_clob(l_output_data)).to_be_like(l_expected); + end; + + procedure trims_long_output is + l_output_data ut3_develop.ut_varchar2_list; + l_expected varchar2(32767); + begin + l_expected := q'{%##teamcity[testSuiteStarted timestamp='%' name='check_trims_long_output'] +%##teamcity[testStarted timestamp='%' captureStandardOutput='true' name='ut3_user.check_trims_long_output.long_output'] +%##teamcity[testFailed timestamp='%' details='Actual: (varchar2)|n |'aVarcharaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|[...|]' name='ut3_user.check_trims_long_output.long_output'] +%##teamcity[testFinished timestamp='%' duration='%' name='ut3_user.check_trims_long_output.long_output'] +%##teamcity[testSuiteFinished timestamp='%' name='check_trims_long_output']}'; + --act + select * + bulk collect into l_output_data + from table(ut3_develop.ut.run('check_trims_long_output',ut3_develop.ut_teamcity_reporter())); + + --assert + ut.expect(ut3_tester_helper.main_helper.table_to_clob(l_output_data)).to_be_like(l_expected); + end; + + procedure report_multiple_expectations is + l_output_data ut3_develop.ut_varchar2_list; + l_expected varchar2(32767); + begin + l_expected := q'{%##teamcity[testSuiteStarted timestamp='%' name='check_multiple_failures'] +%##teamcity[testStarted timestamp='%' captureStandardOutput='true' name='ut3_user.check_multiple_failures.multi_failure'] +%##teamcity[testFailed timestamp='%' details='Actual: 1 (number) was expected to be null' name='ut3_user.check_multiple_failures.multi_failure'] +%##teamcity[testFailed timestamp='%' details='Actual: 2 (number) was expected to equal: 1 (number)' name='ut3_user.check_multiple_failures.multi_failure'] +%##teamcity[testFailed timestamp='%' details='Actual: |'Bad|' (varchar2) was expected to equal: |'Good|' (varchar2)' name='ut3_user.check_multiple_failures.multi_failure'] +%##teamcity[testFinished timestamp='%' duration='%' name='ut3_user.check_multiple_failures.multi_failure'] +%##teamcity[testSuiteFinished timestamp='%' name='check_multiple_failures']}'; + --act + select * + bulk collect into l_output_data + from table(ut3_develop.ut.run('check_multiple_failures.multi_failure',ut3_develop.ut_teamcity_reporter())); + + --assert + ut.expect(ut3_tester_helper.main_helper.table_to_clob(l_output_data)).to_be_like(l_expected); + end; + + procedure report_multiple_expect_on_err is + l_output_data ut3_develop.ut_varchar2_list; + l_expected varchar2(32767); + begin + l_expected := q'{%##teamcity[testSuiteStarted timestamp='%' name='check_multiple_failures'] +%##teamcity[testStarted timestamp='%' captureStandardOutput='true' name='ut3_user.check_multiple_failures.multi_failure_on_error'] +%##teamcity[testStdErr timestamp='%' name='ut3_user.check_multiple_failures.multi_failure_on_error' out='Test exception:|nORA-06502: PL/SQL: %: character to number conversion error|nORA-06512: at "UT3_USER.CHECK_MULTIPLE_FAILURES", line %|nORA-06512: at %|n'] +%##teamcity[testFailed timestamp='%' details='Test exception:|nORA-06502: PL/SQL: %: character to number conversion error|nORA-06512: at "UT3_USER.CHECK_MULTIPLE_FAILURES", line %|nORA-06512: at %|n' message='Error occured' name='ut3_user.check_multiple_failures.multi_failure_on_error'] +%##teamcity[testFailed timestamp='%' details='Actual: 1 (number) was expected to be null' name='ut3_user.check_multiple_failures.multi_failure_on_error'] +%##teamcity[testFailed timestamp='%' details='Actual: 2 (number) was expected to equal: 1 (number)' name='ut3_user.check_multiple_failures.multi_failure_on_error'] +%##teamcity[testFailed timestamp='%' details='Actual: |'Bad|' (varchar2) was expected to equal: |'Good|' (varchar2)' name='ut3_user.check_multiple_failures.multi_failure_on_error'] +%##teamcity[testFinished timestamp='%' duration='%' name='ut3_user.check_multiple_failures.multi_failure_on_error'] +%##teamcity[testSuiteFinished timestamp='%' name='check_multiple_failures']}'; + --act + select * + bulk collect into l_output_data + from table(ut3_develop.ut.run('check_multiple_failures.multi_failure_on_error',ut3_develop.ut_teamcity_reporter())); + + --assert + ut.expect(ut3_tester_helper.main_helper.table_to_clob(l_output_data)).to_be_like(l_expected); + end; + + procedure remove_test_package is + pragma autonomous_transaction; + begin + execute immediate 'drop package check_escape_special_chars'; + execute immediate 'drop package check_trims_long_output'; + execute immediate 'drop package check_multiple_failures'; + end; + +end; +/ diff --git a/test/core/reporters/test_teamcity_reporter.pks b/test/ut3_user/reporters/test_teamcity_reporter.pks similarity index 64% rename from test/core/reporters/test_teamcity_reporter.pks rename to test/ut3_user/reporters/test_teamcity_reporter.pks index ef474b225..1b9277e7a 100644 --- a/test/core/reporters/test_teamcity_reporter.pks +++ b/test/ut3_user/reporters/test_teamcity_reporter.pks @@ -1,7 +1,7 @@ create or replace package test_teamcity_reporter as --%suite(ut_teamcity_reporter) - --%suitepath(utplsql.core.reporters) + --%suitepath(utplsql.test_user.reporters) --%beforeall procedure create_a_test_package; @@ -15,6 +15,12 @@ create or replace package test_teamcity_reporter as --%test(Trims output so it fits into 4000 chars) procedure trims_long_output; + --%test(Reports failures on multiple expectations) + procedure report_multiple_expectations; + + --%test(Reports failures on multiple expectations) + procedure report_multiple_expect_on_err; + --%afterall procedure remove_test_package; diff --git a/test/ut3_user/reporters/test_tfs_junit_reporter.pkb b/test/ut3_user/reporters/test_tfs_junit_reporter.pkb new file mode 100644 index 000000000..1036be2ba --- /dev/null +++ b/test/ut3_user/reporters/test_tfs_junit_reporter.pkb @@ -0,0 +1,312 @@ +create or replace package body test_tfs_junit_reporter as + + procedure crate_a_test_package is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package check_junit_reporting is + --%suite(A suite with ) + + --%test(A test with ) + procedure test_do_stuff; + + end;]'; + execute immediate q'[create or replace package body check_junit_reporting is + procedure test_do_stuff is + begin + ut3_develop.ut.expect(1).to_equal(1); + ut3_develop.ut.expect(1).to_equal(2); + end; + + end;]'; + + execute immediate q'[create or replace package check_junit_rep_suitepath is + --%suitepath(core) + --%suite(check_junit_rep_suitepath) + --%displayname(Check JUNIT Get path for suitepath) + + --%test(check_junit_rep_suitepath) + --%displayname(Check JUNIT Get path for suitepath) + procedure check_junit_rep_suitepath; + end;]'; + execute immediate q'[create or replace package body check_junit_rep_suitepath is + procedure check_junit_rep_suitepath is + begin + ut3_develop.ut.expect(1).to_equal(1); + end; + end;]'; + + execute immediate q'[create or replace package check_junit_flat_suitepath is + --%suitepath(core.check_junit_rep_suitepath) + --%suite(flatsuitepath) + + --%beforeall + procedure donuffin; + end;]'; + execute immediate q'[create or replace package body check_junit_flat_suitepath is + procedure donuffin is + begin + null; + end; + end;]'; + + execute immediate q'[create or replace package check_junit_in_context is + --%suitepath(core.check_junit_rep_suitepath) + --%suite(inctxsuite) + --%displayname(JUNIT test are inside context) + + -- %context(incontext) + -- %name(incontext) + + --%test(incontext) + --%displayname(Check JUNIT Get path incontext) + procedure check_junit_rep_incontext; + + -- %endcontext + end;]'; + execute immediate q'[create or replace package body check_junit_in_context is + procedure check_junit_rep_incontext is + begin + ut3_develop.ut.expect(1).to_equal(1); + end; + end;]'; + + execute immediate q'[create or replace package check_junit_out_context is + --%suitepath(core) + --%suite(outctxsuite) + --%displayname(JUNIT test are outside context) + + -- %context(outcontext) + -- %name(outcontext) + + -- %endcontext + + + --%test(outctx) + --%displayname(outctx) + procedure outctx; + + + end;]'; + execute immediate q'[create or replace package body check_junit_out_context is + procedure outctx is + begin + ut3_develop.ut.expect(1).to_equal(1); + end; + end;]'; + + execute immediate q'[create or replace package check_junit_inout_context is + --%suitepath(core) + --%suite(inoutcontext) + --%displayname(Test in and out of context) + + -- %context(incontext) + -- %name(ProductincontextFeatures) + + --%test(inctx) + --%displayname(inctx) + procedure inctx; + + -- %endcontext + + + --%test(outctx) + --%displayname(outctx) + procedure outctx; + + + end;]'; + execute immediate q'[create or replace package body check_junit_inout_context is + procedure inctx is + begin + ut3_develop.ut.expect(1).to_equal(1); + end; + + procedure outctx is + begin + ut3_develop.ut.expect(1).to_equal(1); + end; + end;]'; + + end; + + procedure escapes_special_chars is + l_results ut3_develop.ut_varchar2_list; + l_actual clob; + begin + --Act + select * + bulk collect into l_results + from table(ut3_develop.ut.run('check_junit_reporting',ut3_develop.ut_tfs_junit_reporter())); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + --Assert + ut.expect(l_actual).not_to_be_like('%%'); + ut.expect(l_actual).to_be_like('%<tag>%'); + end; + + procedure reports_only_failed_or_errored is + l_results ut3_develop.ut_varchar2_list; + l_actual clob; + begin + --Act + select * + bulk collect into l_results + from table(ut3_develop.ut.run('check_junit_reporting',ut3_develop.ut_tfs_junit_reporter())); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + --Assert + ut.expect(l_actual).not_to_be_like('%Actual: 1 (number) was expected to equal: 1 (number)%'); + ut.expect(l_actual).to_be_like('%Actual: 1 (number) was expected to equal: 2 (number)%'); + end; + + procedure check_classname_suite is + l_results ut3_develop.ut_varchar2_list; + l_actual clob; + begin + --Act + select * + bulk collect into l_results + from table(ut3_develop.ut.run('check_junit_reporting',ut3_develop.ut_tfs_junit_reporter())); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + --Assert + ut.expect(l_actual).to_be_like('%testcase classname="check_junit_reporting"%'); + end; + + procedure check_flatten_nested_suites is + l_results ut3_develop.ut_varchar2_list; + l_actual clob; + begin + --Act + select * + bulk collect into l_results + from table(ut3_develop.ut.run('check_junit_flat_suitepath',ut3_develop.ut_tfs_junit_reporter())); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + --Assert + ut.expect(l_actual).to_be_like(' + + + + + +%'); + end; + + procedure check_nls_number_formatting is + l_results ut3_develop.ut_varchar2_list; + l_actual clob; + l_nls_numeric_characters varchar2(30); + begin + --Arrange + select replace(nsp.value,'''','''''') into l_nls_numeric_characters + from nls_session_parameters nsp + where parameter = 'NLS_NUMERIC_CHARACTERS'; + execute immediate q'[alter session set NLS_NUMERIC_CHARACTERS=', ']'; + --Act + select * + bulk collect into l_results + from table(ut3_develop.ut.run('check_junit_reporting', ut3_develop.ut_tfs_junit_reporter())); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + --Assert + ut.expect(l_actual).to_match('time="[0-9]*\.[0-9]{3,6}"'); + --Cleanup + execute immediate 'alter session set NLS_NUMERIC_CHARACTERS='''||l_nls_numeric_characters||''''; + end; + + procedure check_failure_escaped is + begin + reporters.check_xml_failure_escaped(ut3_develop.ut_tfs_junit_reporter()); + end; + + procedure check_classname_suitepath is + l_results ut3_develop.ut_varchar2_list; + l_actual clob; + begin + --Act + select * + bulk collect into l_results + from table(ut3_develop.ut.run('check_junit_rep_suitepath',ut3_develop.ut_tfs_junit_reporter())); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + --Assert + ut.expect(l_actual).to_be_like('%testcase classname="core.check_junit_rep_suitepath"%'); + end; + procedure remove_test_package is + pragma autonomous_transaction; + begin + execute immediate 'drop package check_junit_reporting'; + execute immediate 'drop package check_junit_rep_suitepath'; + execute immediate 'drop package check_junit_flat_suitepath'; + end; + + procedure check_encoding_included is + begin + reporters.check_xml_encoding_included(ut3_develop.ut_tfs_junit_reporter(), 'UTF-8'); + end; + + procedure reports_only_test_in_ctx is + l_results ut3_develop.ut_varchar2_list; + l_actual clob; + begin + --Act + select * + bulk collect into l_results + from table(ut3_develop.ut.run('check_junit_in_context',ut3_develop.ut_tfs_junit_reporter())); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + --Assert + ut.expect(l_actual).to_be_like(' + + + + + + + + +%'); + end; + + procedure reports_only_test_out_ctx is + l_results ut3_develop.ut_varchar2_list; + l_actual clob; + begin + --Act + select * + bulk collect into l_results + from table(ut3_develop.ut.run('check_junit_out_context',ut3_develop.ut_tfs_junit_reporter())); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + --Assert + ut.expect(l_actual).to_be_like(' + + + + + + + + +%'); + end; + + procedure reports_only_test_inout_ctx is + l_results ut3_develop.ut_varchar2_list; + l_actual clob; + begin + --Act + select * + bulk collect into l_results + from table(ut3_develop.ut.run('check_junit_inout_context',ut3_develop.ut_tfs_junit_reporter())); + l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); + --Assert + ut.expect(l_actual).to_be_like(' + + + + + + + + + + +%'); + end; + +end; +/ \ No newline at end of file diff --git a/test/core/reporters/test_tfs_junit_reporter.pks b/test/ut3_user/reporters/test_tfs_junit_reporter.pks similarity index 69% rename from test/core/reporters/test_tfs_junit_reporter.pks rename to test/ut3_user/reporters/test_tfs_junit_reporter.pks index cc589be1b..70f78e334 100644 --- a/test/core/reporters/test_tfs_junit_reporter.pks +++ b/test/ut3_user/reporters/test_tfs_junit_reporter.pks @@ -1,7 +1,7 @@ create or replace package test_tfs_junit_reporter as --%suite(ut_tfs_junit_reporter) - --%suitepath(utplsql.core.reporters) + --%suitepath(utplsql.test_user.reporters) --%beforeall procedure crate_a_test_package; @@ -12,9 +12,6 @@ create or replace package test_tfs_junit_reporter as --%test(Reports only failed expectations and exceptions) procedure reports_only_failed_or_errored; - --%test(Reports failed line of test) - procedure reports_failed_line; - --%test(Check that classname is returned correct suite) procedure check_classname_suite; @@ -33,6 +30,15 @@ create or replace package test_tfs_junit_reporter as --%test(Includes XML header with encoding when encoding provided) procedure check_encoding_included; + --%test(Reports only testsuites where there are any testcases, all tests are in context) + procedure reports_only_test_in_ctx; + + --%test(Reports only testsuites where there are any testcases, all tests are outside context) + procedure reports_only_test_out_ctx; + + --%test(Reports only testsuites where there are any testcases, one test in ctx one test outside) + procedure reports_only_test_inout_ctx; + --%afterall procedure remove_test_package; end; diff --git a/test/ut3_user/test_user.pkb b/test/ut3_user/test_user.pkb new file mode 100644 index 000000000..9fec79d96 --- /dev/null +++ b/test/ut3_user/test_user.pkb @@ -0,0 +1,11 @@ +create or replace package body test_user is + + procedure global_setup is + begin + ut3_tester_helper.coverage_helper.set_develop_mode(); + --improve performance of test execution by disabling all compiler optimizations + ut3_tester_helper.main_helper.execute_autonomous('ALTER SESSION SET PLSQL_OPTIMIZE_LEVEL=0'); + end; + +end; +/ diff --git a/test/ut3_user/test_user.pks b/test/ut3_user/test_user.pks new file mode 100644 index 000000000..ea0435efd --- /dev/null +++ b/test/ut3_user/test_user.pks @@ -0,0 +1,10 @@ +create or replace package test_user is + + --%suite + --%suitepath(utplsql) + + --%beforeall + procedure global_setup; + +end; +/