GeezerVison is showing github.com — Add be_within 'fuzzy' matcher · Issue #77 · utPLSQL/utPLSQL
Add be_within 'fuzzy' matcher #77DescriptionFor numbers we should allow a comparison with a percent_off deviation.
The syntax:
ut.expect( a_actual =>1.23 ).to_( be_within( a_pct => 1, a_expected => 1.23456789 ) )
should give success
ut.expect( a_actual =>1.2 ).to_( be_within( a_pct => 1, a_expected => 1.23456789 ) )
should give success
Calculation logic.
a_actual between (a_expected - ((a_expected * a_pct)/100) ) and (a_expected + ((a_expected * a_pct)/100) ) Activityadded this to the This milestone has been deleted milestone on Oct 17, 2016jgebal commented on Nov 21, 2016 Similar should be available for dates, timestamps and intevals (once suported) modified the milestones: This milestone has been deleted, This milestone has been deleted on Dec 7, 2016Pazus commented on Dec 7, 2016 Rescheduled to version 3.1 proldan commented on Mar 22, 2017 What should pct mean in dates and intervals? Should it be a percentage of a day for dates? Shoelace commented on Mar 23, 2017 that may not make a whole lot of sense..
more useful for dates would be if it meant "number of seconds difference"
ie so 1-jan-2017 10:12:13 would match 1-jan-2017 10:12:14
i guess you could say 50% would mean +/- 12hours jgebal commented on May 15, 2017 I think that for dates, timestamps and intervals we should not think of within in terms of PCT.
For those data-types we should use interval as a measure of allowed deviation.
so the syntax woule be like:
ut.expect(sysdate).to_( be_within( interval '1' day, to_date( '20170515', 'yyyy-mm-dd' ) ) ); PhilippSalvisberg commented on Jun 15, 2020 The definition of the INTERVAL DAY TO SECOND Data Type is
INTERVAL DAY TO SECOND stores a period of time in terms of days, hours, minutes, and seconds. This data type is useful for representing the precise difference between two datetime values.
I like the Interval literals to express an interval in a human readable way. This helps especially for this use case. A comparison/assert with a tolerance. As @lwasylow I'd prefer a syntax as follows:
ut.expect(l_actual_interval).to_be(l_expected_interval).with_tolerance(interval '5' minute);
and for the second example
ut.expect(l_actual_date).to_be(timestamp '2020-06-14 22:11.34').with_tolerance(interval '5' minute);
It's a well know equal comparison with an optional tolerance.
The tolerance can be an interval (year to month or day to second) or a number. Tolerance is applicable for datetime, timestamp, number comparisons. In case of datetime/timestamp a number tolerance is interpreted in days. This would be consistent with the datetime arithmetic of the Oracle Database. jgebal commented on Jun 16, 2020 I think there are two aspects here
- should we allow for interval/interval/interval as acual/expexted/tolerance
- what syntax shoul be used for this expectation?
Seems like you're supportive of the firts but suggest to use alternative syntax to (...).to_be_within(...).of_(...) PhilippSalvisberg commented on Jun 16, 2020
should we allow for interval/interval/interval as acual/expexted/tolerance
Yes.
what syntax shoul be used for this expectation?
I favor (...).to_be(...).with_tolerance(...) over (...).to_be_within(...).of_(...). For me it is clearer which is the "tolerance" and which the value to compare to. However, there might be other things to consider like the return type of a method (making a fluent API harder or easier) and the consistency to other methods. I have not looked at these aspects. lwasylow commented on Jun 16, 2020 For me a tolerance feel a better being second as for first part of name this can probably be modified there are multiple options like:
nearly_equal or approx_equal instead of to_be
I think with_tolerance also is a much clearer expresion and falls into a format as we passing expected first and then a modifier of that comparision whether is a join by or a distance. jgebal commented on Jun 16, 2020 One more:
ut.expect(...).to_be_close_to(...).with_tolerance(...); PhilippSalvisberg commented on Jun 16, 2020 Why change the first part and not keep the existing variant to_be? I see with_tolerance optional because the default is a tolerance of zero. lwasylow commented on Jun 16, 2020 We need to change first part as currently we bene looking on to be within(3).of_(5) where 3 was a distance and 5 was a point from distance was measured. PhilippSalvisberg commented on Jun 17, 2020 @lwasylow you were suggesting nearly_equal or approx_equal and @jgebal to_be_close_to instead of to_be. So, my question was why? Just because you like it more or is there some limitation regarding overloading of to_be? lwasylow commented on Jun 17, 2020 @PhilippSalvisberg, apologies I misread your post. For some reason I assumed you reffered to to_be_within. There is no restriction in to_be. As for syntax I personally think to_be is not descriptive and can be be easily misunderstood with equal. Personally I would prefer something more descriptive as well as distance being mandatory value positive, with zero is just a worse version of equal.
Hope that makes sense and clears. PhilippSalvisberg commented on Jun 17, 2020 @lwasylow no problem.
As for syntax I personally think to_be is not descriptive and can be be easily misunderstood with equal
Actually that's what I like. Standalone to_be really means "to be equal to ... with zero tolerance". You can express it explicitly like this
ut.expect(l_actual).to_be(l_expected).with_tolerance(0);
or like this
ut.expect(l_actual).to_be(l_expected);
And it feels right. And also with non-default values for tolerance like this:
ut.expect(l_actual).to_be(l_expected).with_tolerance(0.5);
I am therefore voting against the introduction of additional keywords. Because I think it unnecessarily bloats the syntax of utPLSQL.
We don't have to agree . Do whatever you and @jgebal think is best. jgebal commented on Jun 21, 2020 @PhilippSalvisberg, @lwasylow
Keep in mind that utPSLQL suppoers two flavors of syntax for expectations:
- shortcut syntax:
ut.expect(l_actual).to_**matcher(...)[.options(...)...]**;
- passing matcher to expectation:
ut.expect(l_actual).to_( matcher(...)[.options(...)...] );
So for fuzzy matcher we would need to name it be / ut_be.
That way we would end up with syntax like:
ut.expect( 1 ).to_( be( 2 ).with_tolerance( 1 ) );
ut.expect( 1 ).not_to( be( 2 ).with_tolerance( 1 ) );
ut.expect( 1 ).to_be( 2 ).with_tolerance( 1 );
ut.expect( 1 ).not_to_be( 2 ).with_tolerance( 1 );
The be in OOP it s used to represent equal identity in sense of "the same object instance" not "the same value" or "identical object".
I think that be is too strong for this matcher and actually in PL/SQL it is quite impossible for two variables to point to (represent) the same object instance as assignments in PLSQL are done by deep copy of a variable.
We could have used be for equality but since we have decided to use to_equal I se no value in changing it now.
Overloading to_equal to support tolerance would also cause trouble with support for non-scalar data-types.
It will not be possible to apply with_tolerance to cursor, object type, nested table.
So we would need to add safety net for invalid syntax like:
ut.expect( l_actual_cursor ).to_be( l_expected_cursor ).with_tolerance( 1 );
The be_within is described as part of RSpec, which was as a reference for Domain Specific Language specification in utPLSQL expectations:
https://relishapp.com/rspec/rspec-expectations/v/3-9/docs/built-in-matchers/be-within-matcher
Thanks for all the inputs.
I'm in favor of the following:
begin
ut.expect(interval).to_be_within(interval).of_(interval);
ut.expect(date).to_be_within(interval).of_(interval);
ut.expect(timestamp).to_be_within(interval).of_(timestamp);
ut.expect(timestamp_tz).to_be_within(interval).of_(timestamp_tz);
ut.expect(timestamp_ltz).to_be_within(interval).of_(timestamp_ltz);
ut.expect(number).to_be_within(number).of_(number);
ut.expect(number).to_be_within_pct(number).of_(number);
end; Reacted by Philipp Salvisberg, Lukasz Wasylow, Samuel Nitsche and David Pyke PhilippSalvisberg commented on Jun 21, 2020 Thank you, @jgebal for the detailed answer. You got me with the link to RSpec (and because utPLSQL is based on that) and the explanation regarding the technical issues.
So, I support your approach. pesse commented on Jun 22, 2020 @jgebal 's comments - as always a treasure of knowledge! ❤
MetadataMetadataDevelopmentNo branches or pull requestsIssue actions
|