diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 87d577554..8703e24d9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -92,7 +92,7 @@ jobs: - 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_HEAD_REF:-$CI_REF_NAME} https://github.com/utPLSQL/utPLSQL.git $UTPLSQL_DIR + 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} diff --git a/docs/userguide/expectations.md b/docs/userguide/expectations.md index c07f3782e..a74e2576e 100644 --- a/docs/userguide/expectations.md +++ b/docs/userguide/expectations.md @@ -316,24 +316,25 @@ Since NULL is neither *true* nor *false*, both expectations will report failure. 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 | - +| 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 @@ -1093,6 +1094,111 @@ SUCCESS DEF ``` +## to_be_within of + +Determines wheter 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 +begin + ut.expect(3).to_be_within(1).of_(4); +end; +/ +``` + +**Example 2.** +```sql +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 +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 wheter 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 +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 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/core/ut_expectation_processor.pkb b/source/core/ut_expectation_processor.pkb index a03a28965..77b734b30 100644 --- a/source/core/ut_expectation_processor.pkb +++ b/source/core/ut_expectation_processor.pkb @@ -159,7 +159,7 @@ create or replace package body ut_expectation_processor as -- when 11g and 12c reports only package name function cut_header_and_expectations( a_stack varchar2 ) return varchar2 is begin - return regexp_substr( a_stack, '(.*\.(UT_EXPECTATION[A-Z0-9#_$]*|UT|UTASSERT2?)(\.[A-Z0-9#_$]+)?\s+)+((.|\s)*)', 1, 1, 'm', 4); + return regexp_substr( a_stack, '(.*\.(UT_EQUAL|UT_BE_WITHIN[A-Z0-9#_$]*|UT_EXPECTATION[A-Z0-9#_$]*|UT|UTASSERT2?)(\.[A-Z0-9#_$]+)?\s+)+((.|\s)*)', 1, 1, 'm', 4); end; function cut_address_columns( a_stack varchar2 ) return varchar2 is begin diff --git a/source/core/ut_utils.pkb b/source/core/ut_utils.pkb index 81a610a0c..655b20d3d 100644 --- a/source/core/ut_utils.pkb +++ b/source/core/ut_utils.pkb @@ -899,5 +899,63 @@ create or replace package body ut_utils is 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; + + end ut_utils; / diff --git a/source/core/ut_utils.pks b/source/core/ut_utils.pks index c7d20ad0c..4c8b14e3d 100644 --- a/source/core/ut_utils.pks +++ b/source/core/ut_utils.pks @@ -127,9 +127,9 @@ create or replace package ut_utils authid definer is gc_more_data_string constant varchar2(5) := '[...]'; 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'; @@ -457,6 +457,16 @@ create or replace package ut_utils authid definer is * 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; + end ut_utils; / diff --git a/source/create_grants.sql b/source/create_grants.sql index f7f37a662..6401b1522 100644 --- a/source/create_grants.sql +++ b/source/create_grants.sql @@ -88,6 +88,8 @@ 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; diff --git a/source/create_synonyms.sql b/source/create_synonyms.sql index a4f06c228..fa1c1dc45 100644 --- a/source/create_synonyms.sql +++ b/source/create_synonyms.sql @@ -104,6 +104,8 @@ 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; diff --git a/source/expectations/data_values/ut_data_value.tps b/source/expectations/data_values/ut_data_value.tps index 6864bc52e..beda3d911 100644 --- a/source/expectations/data_values/ut_data_value.tps +++ b/source/expectations/data_values/ut_data_value.tps @@ -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, diff --git a/source/expectations/data_values/ut_data_value_blob.tpb b/source/expectations/data_values/ut_data_value_blob.tpb index a7b5fbeca..e145a8d4f 100644 --- a/source/expectations/data_values/ut_data_value_blob.tpb +++ b/source/expectations/data_values/ut_data_value_blob.tpb @@ -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_boolean.tpb b/source/expectations/data_values/ut_data_value_boolean.tpb index 798222e30..867c3c19c 100644 --- a/source/expectations/data_values/ut_data_value_boolean.tpb +++ b/source/expectations/data_values/ut_data_value_boolean.tpb @@ -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_clob.tpb b/source/expectations/data_values/ut_data_value_clob.tpb index 9cfe9b283..f8a53a035 100644 --- a/source/expectations/data_values/ut_data_value_clob.tpb +++ b/source/expectations/data_values/ut_data_value_clob.tpb @@ -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_date.tpb b/source/expectations/data_values/ut_data_value_date.tpb index 5b5b1d387..20424d193 100644 --- a/source/expectations/data_values/ut_data_value_date.tpb +++ b/source/expectations/data_values/ut_data_value_date.tpb @@ -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_dsinterval.tpb b/source/expectations/data_values/ut_data_value_dsinterval.tpb index f81f35974..026d4970f 100644 --- a/source/expectations/data_values/ut_data_value_dsinterval.tpb +++ b/source/expectations/data_values/ut_data_value_dsinterval.tpb @@ -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 a047ead48..6f5cb708c 100644 --- a/source/expectations/data_values/ut_data_value_dsinterval.tps +++ b/source/expectations/data_values/ut_data_value_dsinterval.tps @@ -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_number.tpb b/source/expectations/data_values/ut_data_value_number.tpb index c5c4fe2c3..382e6e9aa 100644 --- a/source/expectations/data_values/ut_data_value_number.tpb +++ b/source/expectations/data_values/ut_data_value_number.tpb @@ -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_refcursor.tpb b/source/expectations/data_values/ut_data_value_refcursor.tpb index 2715614c4..a4f0cf7a0 100644 --- a/source/expectations/data_values/ut_data_value_refcursor.tpb +++ b/source/expectations/data_values/ut_data_value_refcursor.tpb @@ -81,6 +81,7 @@ create or replace type body ut_data_value_refcursor as self.self_type := $$plsql_unit; self.data_id := sys_guid(); self.data_type := 'refcursor'; + self.data_type_plsql := 'sys_refcursor'; self.compound_type := 'refcursor'; self.extract_path := '/*'; ut_compound_data_helper.cleanup_diff; diff --git a/source/expectations/data_values/ut_data_value_timestamp.tpb b/source/expectations/data_values/ut_data_value_timestamp.tpb index 79facae4a..318f799a3 100644 --- a/source/expectations/data_values/ut_data_value_timestamp.tpb +++ b/source/expectations/data_values/ut_data_value_timestamp.tpb @@ -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_ltz.tpb b/source/expectations/data_values/ut_data_value_timestamp_ltz.tpb index f2c5cddbd..6127de5f1 100644 --- a/source/expectations/data_values/ut_data_value_timestamp_ltz.tpb +++ b/source/expectations/data_values/ut_data_value_timestamp_ltz.tpb @@ -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_tz.tpb b/source/expectations/data_values/ut_data_value_timestamp_tz.tpb index 0991e9e9f..d5d5cdd13 100644 --- a/source/expectations/data_values/ut_data_value_timestamp_tz.tpb +++ b/source/expectations/data_values/ut_data_value_timestamp_tz.tpb @@ -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_varchar2.tpb b/source/expectations/data_values/ut_data_value_varchar2.tpb index 307ca583d..d04398697 100644 --- a/source/expectations/data_values/ut_data_value_varchar2.tpb +++ b/source/expectations/data_values/ut_data_value_varchar2.tpb @@ -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_xmltype.tpb b/source/expectations/data_values/ut_data_value_xmltype.tpb index d17896492..4b21a8937 100644 --- a/source/expectations/data_values/ut_data_value_xmltype.tpb +++ b/source/expectations/data_values/ut_data_value_xmltype.tpb @@ -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_yminterval.tpb b/source/expectations/data_values/ut_data_value_yminterval.tpb index 7de3e58cd..a3a1e7a2f 100644 --- a/source/expectations/data_values/ut_data_value_yminterval.tpb +++ b/source/expectations/data_values/ut_data_value_yminterval.tpb @@ -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 278a2f803..c9ad2e776 100644 --- a/source/expectations/data_values/ut_data_value_yminterval.tps +++ b/source/expectations/data_values/ut_data_value_yminterval.tps @@ -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/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_equal.tpb b/source/expectations/matchers/ut_equal.tpb index 05caf3b09..b08e8af75 100644 --- a/source/expectations/matchers/ut_equal.tpb +++ b/source/expectations/matchers/ut_equal.tpb @@ -172,6 +172,18 @@ create or replace type body ut_equal as 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 @@ -186,6 +198,18 @@ create or replace type body ut_equal as 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 @@ -193,6 +217,13 @@ create or replace type body ut_equal as 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 @@ -209,18 +240,43 @@ create or replace type body ut_equal as return l_result; end; - member function uc return ut_equal is + member procedure join_by(self in ut_equal, a_columns varchar2) is begin - return unordered_columns; + join_by( ut_varchar2_list( a_columns ) ); end; + member procedure join_by(self in ut_equal, a_columns ut_varchar2_list) is + l_result ut_equal := self; + begin + 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 procedure unordered_columns(self in ut_equal) is + l_result ut_equal := self; + begin + l_result.options.unordered_columns(); + l_result.expectation.to_(l_result ); + end; + + member function uc return ut_equal is + begin + return unordered_columns; + end; + member procedure uc(self in ut_equal) is + begin + unordered_columns; + end; + overriding member function run_matcher(self in out nocopy ut_equal, a_actual ut_data_value) return boolean is l_result boolean; begin diff --git a/source/expectations/matchers/ut_equal.tps b/source/expectations/matchers/ut_equal.tps index eecbe8c1d..6ae03226e 100644 --- a/source/expectations/matchers/ut_equal.tps +++ b/source/expectations/matchers/ut_equal.tps @@ -43,17 +43,26 @@ create or replace type ut_equal force under ut_comparison_matcher( 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, 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 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, member function unordered_columns return ut_equal, - member function uc 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_matcher.tpb b/source/expectations/matchers/ut_matcher.tpb index c64b6d246..6b5b98465 100644 --- a/source/expectations/matchers/ut_matcher.tpb +++ b/source/expectations/matchers/ut_matcher.tpb @@ -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; diff --git a/source/expectations/matchers/ut_matcher.tps b/source/expectations/matchers/ut_matcher.tps index ba8bb7e85..a034e4ed2 100644 --- a/source/expectations/matchers/ut_matcher.tps +++ b/source/expectations/matchers/ut_matcher.tps @@ -1,4 +1,4 @@ -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 - 2021 utPLSQL Project @@ -15,10 +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 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/ut_expectation.tpb b/source/expectations/ut_expectation.tpb index dfad630a6..dabe8fbff 100644 --- a/source/expectations/ut_expectation.tpb +++ b/source/expectations/ut_expectation.tpb @@ -15,31 +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 - if a_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, a_matcher ut_matcher) is - l_expectation_result boolean; - l_matcher ut_matcher := a_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; member procedure to_be_null(self in ut_expectation) is begin @@ -719,5 +694,70 @@ create or replace type body ut_expectation as self.not_to( ut_contain(a_expected).negated() ); 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 45d768200..86edc9cee 100644 --- a/source/expectations/ut_expectation.tps +++ b/source/expectations/ut_expectation.tps @@ -1,4 +1,4 @@ -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 - 2021 utPLSQL Project @@ -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), @@ -168,8 +162,16 @@ create or replace type ut_expectation authid current_user as object( 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 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 9dfd78e3e..6fc2e2647 100644 --- a/source/expectations/ut_expectation_compound.tpb +++ b/source/expectations/ut_expectation_compound.tpb @@ -34,162 +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; + 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).negated(); - 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; - begin - l_result.matcher := ut_equal(a_expected, a_nulls_are_equal); - return l_result; - 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; - begin - l_result.matcher := ut_equal(a_expected, a_nulls_are_equal).negated(); - return l_result; - end; - - member function to_contain(a_expected sys_refcursor) return ut_expectation_compound is - l_result ut_expectation_compound := self; - begin - l_result.matcher := ut_contain(a_expected); - return l_result; - end; - - member function not_to_contain(a_expected sys_refcursor) return ut_expectation_compound is - l_result ut_expectation_compound := self; - begin - l_result.matcher := ut_contain(a_expected).negated(); - return l_result; - end; - - member function to_contain(a_expected anydata) return ut_expectation_compound is - l_result ut_expectation_compound := self; - begin - l_result.matcher := ut_contain(a_expected); - 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_contain(a_expected anydata) 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_contain(a_expected).negated(); + 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 + member function not_to_equal(a_expected sys_refcursor, a_nulls_are_equal boolean := null) return ut_equal is + l_result ut_matcher; begin - return include( ut_varchar2_list( a_items ) ); + 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 := self; + member function to_contain(a_expected sys_refcursor) return ut_contain is + l_result ut_contain; begin - 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 - begin - include( ut_varchar2_list( a_items ) ); - end; - - member procedure include(self in ut_expectation_compound, a_items ut_varchar2_list) is + member function not_to_contain(a_expected sys_refcursor) return ut_contain is + l_result ut_matcher; begin - self.to_( treat(matcher as ut_equal).include(a_items) ); + l_result := ut_contain(a_expected).negated(); + l_result.expectation := self; + return treat(l_result as ut_contain); end; - - member function exclude(a_items varchar2) return ut_expectation_compound is - begin - return exclude( ut_varchar2_list( a_items ) ); - end; - - member function exclude(a_items ut_varchar2_list) return ut_expectation_compound is - l_result ut_expectation_compound := self; + + member function to_contain(a_expected anydata) return ut_contain is + l_result ut_contain; begin - l_result.matcher := treat(l_result.matcher as ut_equal).exclude(a_items); + l_result := ut_contain(a_expected); + l_result.expectation := self; return l_result; end; - member procedure exclude(self in ut_expectation_compound, a_items varchar2) is - begin - exclude( ut_varchar2_list( a_items ) ); - end; - - member procedure exclude(self in ut_expectation_compound, a_items ut_varchar2_list) is - begin - self.to_( treat(matcher as ut_equal).exclude(a_items) ); - end; - - member function unordered return ut_expectation_compound is - l_result ut_expectation_compound := self; - begin - l_result.matcher := treat(l_result.matcher as ut_equal).unordered(); - return l_result; - end; - - member procedure unordered(self in ut_expectation_compound) is - begin - self.to_( treat(matcher as ut_equal).unordered() ); - end; - - member function join_by(a_columns varchar2) return ut_expectation_compound is - begin - return join_by( ut_varchar2_list( a_columns ) ); - 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 - join_by( ut_varchar2_list( a_columns ) ); - end; - - member procedure join_by(self in ut_expectation_compound, a_columns ut_varchar2_list) is - begin - self.to_( treat(matcher as ut_equal).join_by(a_columns) ); - end; - - member function unordered_columns 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_columns; - return l_result; - end; - - member procedure unordered_columns(self in ut_expectation_compound) is - begin - self.to_( treat(matcher as ut_equal).unordered_columns ); - end; - - member function uc return ut_expectation_compound is - begin - return unordered_columns; - end; - - member procedure uc(self in ut_expectation_compound) is + member function not_to_contain(a_expected anydata) return ut_contain is + l_result ut_matcher; begin - unordered_columns; + 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 ab320cae0..46da23fea 100644 --- a/source/expectations/ut_expectation_compound.tps +++ b/source/expectations/ut_expectation_compound.tps @@ -1,4 +1,4 @@ -create or replace type ut_expectation_compound force under ut_expectation( +create or replace type ut_expectation_compound under ut_expectation( /* utPLSQL - Version 3 Copyright 2016 - 2021 utPLSQL Project @@ -22,33 +22,15 @@ create or replace type ut_expectation_compound force under ut_expectation( 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 not_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 sys_refcursor, a_nulls_are_equal boolean := null) return ut_expectation_compound, - member function to_contain(a_expected sys_refcursor) return ut_expectation_compound, - member function not_to_contain(a_expected sys_refcursor) return ut_expectation_compound, - member function to_contain(a_expected anydata) return ut_expectation_compound, - member function not_to_contain(a_expected anydata) 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 unordered_columns return ut_expectation_compound, - member procedure unordered_columns(self in ut_expectation_compound), - member function uc return ut_expectation_compound, - member procedure uc(self in ut_expectation_compound) + 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 ) / + + diff --git a/source/install.sql b/source/install.sql index 9f91297b2..cda057bdf 100644 --- a/source/install.sql +++ b/source/install.sql @@ -235,8 +235,14 @@ prompt Installing DBMSPLSQL Tables objects into &&ut3_owner schema @@install_component.sql 'expectations/data_values/ut_data_value_xmltype.tps' @@install_component.sql 'expectations/data_values/ut_compound_data_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' @@ -252,7 +258,6 @@ prompt Installing DBMSPLSQL Tables objects into &&ut3_owner schema @@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' @@ -292,11 +297,15 @@ 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' @@ -354,6 +363,8 @@ 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' diff --git a/source/reporters/ut_documentation_reporter.tpb b/source/reporters/ut_documentation_reporter.tpb index 8b92d447f..30ab8f856 100644 --- a/source/reporters/ut_documentation_reporter.tpb +++ b/source/reporters/ut_documentation_reporter.tpb @@ -198,7 +198,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, ' diff --git a/source/uninstall_objects.sql b/source/uninstall_objects.sql index 230e394ee..bc41cb63a 100644 --- a/source/uninstall_objects.sql +++ b/source/uninstall_objects.sql @@ -54,6 +54,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; @@ -142,6 +146,12 @@ 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; diff --git a/test/install_ut3_user_tests.sql b/test/install_ut3_user_tests.sql index e790293c8..ad7f014bc 100644 --- a/test/install_ut3_user_tests.sql +++ b/test/install_ut3_user_tests.sql @@ -25,6 +25,8 @@ prompt Install user tests @@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 @@ -66,6 +68,8 @@ set define off @@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 diff --git a/test/ut3_tester/core/test_ut_utils.pkb b/test/ut3_tester/core/test_ut_utils.pkb index a3ed605f9..4ed718777 100644 --- a/test/ut3_tester/core/test_ut_utils.pkb +++ b/test/ut3_tester/core/test_ut_utils.pkb @@ -159,28 +159,28 @@ end;]' using p_expected_list; 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_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_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_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_develop.ut_data_value_timestamp_tz(l_value).to_string()).to_equal(l_expected); end; @@ -432,5 +432,62 @@ end; --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; + end test_ut_utils; / diff --git a/test/ut3_tester/core/test_ut_utils.pks b/test/ut3_tester/core/test_ut_utils.pks index d8fca3b60..4d83b5042 100644 --- a/test/ut3_tester/core/test_ut_utils.pks +++ b/test/ut3_tester/core/test_ut_utils.pks @@ -128,5 +128,34 @@ 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 + end test_ut_utils; / diff --git a/test/ut3_tester_helper/coverage_helper.pkb b/test/ut3_tester_helper/coverage_helper.pkb index e9385d7d9..0abe10a4f 100644 --- a/test/ut3_tester_helper/coverage_helper.pkb +++ b/test/ut3_tester_helper/coverage_helper.pkb @@ -173,7 +173,7 @@ create or replace package body coverage_helper is auto_drop => TRUE, comments => 'one-time-job' ); - while (l_status is null or l_status not in ('SUCCEEDED','FAILED')) and i < 30 loop + while (l_status is null or l_status not in ('SUCCEEDED','FAILED')) and i < 150 loop l_status := get_job_status( l_job_name, l_timestamp ); sleep(0.1); i := i + 1; diff --git a/test/ut3_user/api/test_ut_run.pkb b/test/ut3_user/api/test_ut_run.pkb index e3af7c5ad..8ec19f6d8 100644 --- a/test/ut3_user/api/test_ut_run.pkb +++ b/test/ut3_user/api/test_ut_run.pkb @@ -6,6 +6,7 @@ create or replace package body test_ut_run is gc_client_info constant varchar2(32767) := 'test client info'; g_context_test_results clob; + g_timestamp timestamp; procedure clear_expectations is begin @@ -1260,6 +1261,7 @@ Failures:% 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; @@ -1272,7 +1274,7 @@ Failures:% ||'%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(current_timestamp,'yyyy-mm-dd"T"hh24:mi') + ||'%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%' @@ -1287,14 +1289,14 @@ Failures:% '%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(current_timestamp,'yyyy-mm-dd"T"hh24:mi') + ||'%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(current_timestamp,'yyyy-mm-dd"T"hh24:mi') + ||'%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%' @@ -1308,17 +1310,17 @@ Failures:% '%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(current_timestamp,'yyyy-mm-dd"T"hh24:mi') + ||'%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(current_timestamp,'yyyy-mm-dd"T"hh24:mi') + ||'%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(current_timestamp,'yyyy-mm-dd"T"hh24:mi') + ||'%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%' @@ -1331,17 +1333,17 @@ Failures:% '%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(current_timestamp,'yyyy-mm-dd"T"hh24:mi') + ||'%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(current_timestamp,'yyyy-mm-dd"T"hh24:mi') + ||'%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(current_timestamp,'yyyy-mm-dd"T"hh24:mi') + ||'%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%' @@ -1354,17 +1356,17 @@ Failures:% '%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(current_timestamp,'yyyy-mm-dd"T"hh24:mi') + ||'%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(current_timestamp,'yyyy-mm-dd"T"hh24:mi') + ||'%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(current_timestamp,'yyyy-mm-dd"T"hh24:mi') + ||'%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%' @@ -1377,17 +1379,17 @@ Failures:% '%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(current_timestamp,'yyyy-mm-dd"T"hh24:mi') + ||'%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(current_timestamp,'yyyy-mm-dd"T"hh24:mi') + ||'%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(current_timestamp,'yyyy-mm-dd"T"hh24:mi') + ||'%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%' @@ -1400,17 +1402,17 @@ Failures:% '%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(current_timestamp,'yyyy-mm-dd"T"hh24:mi') + ||'%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(current_timestamp,'yyyy-mm-dd"T"hh24:mi') + ||'%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(current_timestamp,'yyyy-mm-dd"T"hh24:mi') + ||'%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%' @@ -1423,14 +1425,14 @@ Failures:% '%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(current_timestamp,'yyyy-mm-dd"T"hh24:mi') + ||'%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(current_timestamp,'yyyy-mm-dd"T"hh24:mi') + ||'%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%' @@ -1447,7 +1449,7 @@ Failures:% ||'%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(current_timestamp,'yyyy-mm-dd"T"hh24:mi') + ||'%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%' 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..d490a8280 --- /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+ 45); + --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_expectations_cursor.pkb b/test/ut3_user/expectations/test_expectations_cursor.pkb index f06132009..409c81ace 100644 --- a/test/ut3_user/expectations/test_expectations_cursor.pkb +++ b/test/ut3_user/expectations/test_expectations_cursor.pkb @@ -336,7 +336,7 @@ create or replace package body test_expectations_cursor is 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 ).unordered_columns; + 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; @@ -350,7 +350,7 @@ create or replace package body test_expectations_cursor is 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 ).uc; + 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; @@ -592,7 +592,7 @@ create or replace package body test_expectations_cursor is 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).include('/ROW/RN|//A_Column|//SOME_COL'); + 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; diff --git a/test/ut3_user/expectations/test_expectations_json.pkb b/test/ut3_user/expectations/test_expectations_json.pkb index 9516ecb04..afc7198a2 100644 --- a/test/ut3_user/expectations/test_expectations_json.pkb +++ b/test/ut3_user/expectations/test_expectations_json.pkb @@ -49,7 +49,7 @@ create or replace package body test_expectations_json is }'); --Act - ut3_develop.ut.expect( l_actual ).to_equal( l_actual ); + 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; diff --git a/test/ut3_user/reporters/test_debug_reporter.pkb b/test/ut3_user/reporters/test_debug_reporter.pkb index ed7e14fcf..a022b5af8 100644 --- a/test/ut3_user/reporters/test_debug_reporter.pkb +++ b/test/ut3_user/reporters/test_debug_reporter.pkb @@ -21,7 +21,7 @@ create or replace package body test_debug_reporter as begin l_expected := '\s+' || '(\s+' || - '[0-9\-]+T[0-9:\.]+<\/TIMESTAMP>\s+' || + ' [0-9\-]+T[0-9:\.]+<\/TIMESTAMP>\s+' || '[0-9 \+:\.]+<\/TIME_FROM_START>\s+' || '[0-9 \+:\.]+<\/TIME_FROM_PREVIOUS>\s+' || '\w+<\/EVENT_NAME>\s+' ||