Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Promote broken values instead of ignoring them #11777

Merged
merged 30 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
1c2d007
Currently a DataflowError may get lost in a middle of block statements
JaroslavTulach Dec 5, 2024
49c628e
Propagate Error ASAP instead of ignoring it
JaroslavTulach Dec 5, 2024
91f7497
check for dataflow error in should_equal rhs and report it - this is …
radeusgd Dec 5, 2024
1ed8505
add error check in remaining should_equal overrides
radeusgd Dec 5, 2024
7373304
align behaviour of find across range/vector
radeusgd Dec 6, 2024
00516f5
Merge remote-tracking branch 'origin/develop' into wip/jtulach/Propag…
JaroslavTulach Dec 9, 2024
b0f71f8
Fix Decimal test and `Array_Like_Helpers.find` (#11883)
GregoryTravis Dec 17, 2024
ee7c81e
Merge remote-tracking branch 'origin/develop' into wip/jtulach/Propag…
JaroslavTulach Dec 17, 2024
d703496
Space before dot
JaroslavTulach Dec 17, 2024
7901a25
fix mistake in should_equal check
radeusgd Dec 17, 2024
ba16c47
fix frame offsets
radeusgd Dec 17, 2024
6e0928a
fixing more offsets
radeusgd Dec 17, 2024
bed6609
fix invalid tests
radeusgd Dec 17, 2024
1647c53
remove unnecessary Not_Found type (clashing with another existing one)
radeusgd Dec 17, 2024
ef80339
remove check that was actually too strict
radeusgd Dec 17, 2024
a8571c4
fix cloud test cleanup
radeusgd Dec 17, 2024
6551756
fix a test which was propagating error and crashing suite builder
radeusgd Dec 17, 2024
09fb17f
fixing other tests that break Table Tests progress
radeusgd Dec 17, 2024
3b8c089
fixing more issues in Table tests
radeusgd Dec 17, 2024
434ba8a
enable Context to fix lazy init issue
radeusgd Dec 17, 2024
777c38b
Merging with latest develop
JaroslavTulach Dec 18, 2024
8748349
Speculate on statements returning Nothing
JaroslavTulach Dec 18, 2024
b7430cb
Code style issues found in CHANGELOG.md file
JaroslavTulach Dec 18, 2024
fe5b9e1
duplicate rhs_error_check and make it imperative to avoid nesting
radeusgd Dec 18, 2024
3ce19c7
fix offsets and finally add tests for this
radeusgd Dec 18, 2024
afedc71
Documenting propagation of _broken values_
JaroslavTulach Dec 19, 2024
bda76cf
Renaming to Errors & Panics
JaroslavTulach Dec 19, 2024
0130601
Merge remote-tracking branch 'origin/develop' into wip/jtulach/Propag…
JaroslavTulach Dec 19, 2024
5916204
Reorganizing changelog
JaroslavTulach Dec 19, 2024
5bfe082
Merge branch 'develop' into wip/jtulach/PropagateDataflowError5430
mergify[bot] Dec 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

#### Enso Language & Runtime

- [Propagate Error ASAP instead of ignoring it][11777].

[11777]: https://github.com/enso-org/enso/pull/11777
- [Intersection types & type checks][11600]
- A constructor or type definition with a single inline argument definition was
previously allowed to use spaces in the argument definition without
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,8 @@ take_helper length at single_slice slice_ranges range:(Index_Sub_Range | Range |
Index_Sub_Range.First count -> single_slice 0 (length.min count)
Index_Sub_Range.Last count -> single_slice length-count length
Index_Sub_Range.While predicate ->
end = 0.up_to length . find i-> (predicate (at i)).not
true_end = if end.is_nothing then length else end
single_slice 0 true_end
end = 0.up_to length . find (i-> (predicate (at i)).not) if_missing=length
single_slice 0 end
Index_Sub_Range.By_Index one_or_many_descriptors -> Panic.recover [Index_Out_Of_Bounds, Illegal_Argument] <|
indices = case one_or_many_descriptors of
_ : Vector -> one_or_many_descriptors
Expand Down Expand Up @@ -255,9 +254,8 @@ drop_helper length at single_slice slice_ranges range:(Index_Sub_Range | Range |
Index_Sub_Range.First count -> single_slice count length
Index_Sub_Range.Last count -> single_slice 0 length-count
Index_Sub_Range.While predicate ->
end = 0.up_to length . find i-> (predicate (at i)).not
true_end = if end.is_nothing then length else end
single_slice true_end length
end = 0.up_to length . find (i-> (predicate (at i)).not) if_missing=length
single_slice end length
Index_Sub_Range.By_Index one_or_many_descriptors -> Panic.recover [Index_Out_Of_Bounds, Illegal_Argument] <|
indices = case one_or_many_descriptors of
_ : Vector -> one_or_many_descriptors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import project.Data.Text.Text
import project.Data.Vector.Vector
import project.Error.Error
import project.Errors.Common.Index_Out_Of_Bounds
import project.Errors.Common.Not_Found
import project.Errors.Empty_Error.Empty_Error
import project.Errors.Illegal_Argument.Illegal_Argument
import project.Errors.Illegal_State.Illegal_State
Expand Down Expand Up @@ -397,7 +398,7 @@ type Range
@condition range_default_filter_condition_widget
any : (Filter_Condition | (Integer -> Boolean)) -> Boolean
any self (condition : Filter_Condition | (Integer -> Boolean)) =
self.find condition . is_nothing . not
self.find condition if_missing=Nothing . is_nothing . not

## GROUP Selections
ICON find
Expand All @@ -422,7 +423,7 @@ type Range
1.up_to 100 . find (..Greater than=10)
@condition range_default_filter_condition_widget
find : (Filter_Condition | (Integer -> Boolean)) -> Integer -> Any -> Any
find self (condition : Filter_Condition | (Integer -> Boolean)) (start : Integer = 0) ~if_missing=Nothing =
find self (condition : Filter_Condition | (Integer -> Boolean)) (start : Integer = 0) ~if_missing=(Error.throw Not_Found) =
predicate = unify_condition_or_predicate condition
check_start_valid start self used_start->
result = find_internal self used_start predicate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import project.Data.Time.Period.Period
import project.Data.Vector.Vector
import project.Error.Error
import project.Errors.Common.Index_Out_Of_Bounds
import project.Errors.Common.Not_Found
import project.Errors.Empty_Error.Empty_Error
import project.Errors.Illegal_Argument.Illegal_Argument
import project.Function.Function
Expand Down Expand Up @@ -418,7 +419,7 @@ type Date_Range
@condition date_range_default_filter_condition_widget
any : (Filter_Condition | (Date -> Boolean)) -> Boolean
any self (condition : Filter_Condition | (Date -> Boolean)) =
self.find condition . is_nothing . not
self.find condition if_missing=Nothing . is_nothing . not

## GROUP Selections
ICON find
Expand All @@ -438,7 +439,7 @@ type Date_Range
(Date.new 2020 10 01).up_to (Date.new 2020 10 31) . find (d-> d.day_of_week == Day_Of_Week.Monday)
@condition date_range_default_filter_condition_widget
find : (Filter_Condition | (Date -> Boolean)) -> Integer -> Any -> Any
find self (condition : Filter_Condition | (Date -> Boolean)) (start : Integer = 0) ~if_missing=Nothing =
find self (condition : Filter_Condition | (Date -> Boolean)) (start : Integer = 0) ~if_missing=(Error.throw Not_Found) =
predicate = unify_condition_or_predicate condition
index = self.index_of predicate start
case index of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ find vector condition start ~if_missing =
predicate = unify_condition_or_predicate condition
self_len = vector.length
check_start_valid start self_len used_start->
found = used_start.up_to self_len . find (idx -> (predicate (vector.at idx)))
found = used_start.up_to self_len . find (idx -> (predicate (vector.at idx))) if_missing=Nothing
if found.is_nothing then if_missing else vector.at found

transpose vec_of_vecs =
Expand Down
148 changes: 80 additions & 68 deletions distribution/lib/Standard/Test/0.0.0-dev/src/Extensions.enso
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from Standard.Base import all
import Standard.Base.Errors.Common.Incomparable_Values
import Standard.Base.Errors.Common.No_Such_Method
import Standard.Base.Errors.Illegal_Argument.Illegal_Argument

import project.Spec_Result.Spec_Result
import project.Test.Test
from project.Extensions_Helpers import rhs_error_check

## Expect a function to fail with the provided dataflow error.

Expand Down Expand Up @@ -70,23 +72,24 @@ Error.should_fail_with self matcher frames_to_skip=0 unwrap_errors=True =

example_should_equal = Examples.add_1_to 1 . should_equal 2
Any.should_equal : Any -> Integer -> Spec_Result
Any.should_equal self that frames_to_skip=0 = case self == that of
True -> Spec_Result.Success
False ->
loc = Meta.get_source_location 2+frames_to_skip
additional_comment = case self of
_ : Vector -> case that of
_ : Vector ->
case self.length == that.length of
True ->
diff = self.zip that . index_of p->
p.first != p.second
"; first difference at index " + diff.to_text + " "
False -> "; lengths differ (" + self.length.to_text + " != " + that.length.to_text + ") "
Any.should_equal self that frames_to_skip=0 = rhs_error_check that <|
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finally I see it. This wraps the original code in rhs_error_check helper function. It doesn't change API of Any.should_equal (it is not easy to see that when argument definition is mixed with code on the same line). As a result of the additional function call, the frames shift and thus 4+frame_to_skip. The rest remains unchanged.

loc = Meta.get_source_location 4+frames_to_skip
case self == that of
True -> Spec_Result.Success
False ->
additional_comment = case self of
_ : Vector -> case that of
_ : Vector ->
case self.length == that.length of
True ->
diff = self.zip that . index_of p->
p.first != p.second
"; first difference at index " + diff.to_text + " "
False -> "; lengths differ (" + self.length.to_text + " != " + that.length.to_text + ") "
_ -> ""
_ -> ""
_ -> ""
msg = self.pretty + " did not equal " + that.pretty + additional_comment + " (at " + loc + ")."
Test.fail msg
msg = self.pretty + " did not equal " + that.pretty + additional_comment + " (at " + loc + ")."
Test.fail msg

## Asserts that `self` value is equal to the expected type value.

Expand Down Expand Up @@ -130,12 +133,13 @@ Error.should_equal_type self that frames_to_skip=0 =

example_should_not_equal = Examples.add_1_to 1 . should_not_equal 2
Any.should_not_equal : Any -> Integer -> Spec_Result
Any.should_not_equal self that frames_to_skip=0 = case self != that of
True -> Spec_Result.Success
False ->
loc = Meta.get_source_location 2+frames_to_skip
msg = self.to_text + " did equal " + that.to_text + " (at " + loc + ")."
Test.fail msg
Any.should_not_equal self that frames_to_skip=0 = if that.is_error then (Panic.throw (Illegal_Argument.Error "Expected value provided as `that` for `should_not_equal` cannot be an error, but got: "+that.to_display_text)) else
loc = Meta.get_source_location 2+frames_to_skip
case self != that of
True -> Spec_Result.Success
False ->
msg = self.to_text + " did equal " + that.to_text + " (at " + loc + ")."
Test.fail msg

## Added so that dataflow errors are not silently lost.
Error.should_not_equal self that frames_to_skip=0 =
Expand Down Expand Up @@ -183,15 +187,15 @@ Error.should_not_equal_type self that frames_to_skip=0 =

example_should_start_with = "Hello World!" . should_start_with "Hello"
Any.should_start_with : Text -> Integer -> Spec_Result
Any.should_start_with self that frames_to_skip=0 = case self of
_ : Text -> if self.starts_with that then Spec_Result.Success else
loc = Meta.get_source_location 3+frames_to_skip
msg = self.to_text + " does not start with " + that.to_text + " (at " + loc + ")."
Test.fail msg
_ ->
loc = Meta.get_source_location 2+frames_to_skip
msg = self.to_text + " is not a `Text` value (at " + loc + ")."
Test.fail msg
Any.should_start_with self that frames_to_skip=0 =
loc = Meta.get_source_location 1+frames_to_skip
rhs_error_check that <| case self of
_ : Text -> if self.starts_with that then Spec_Result.Success else
msg = self.to_text + " does not start with " + that.to_text + " (at " + loc + ")."
Test.fail msg
_ ->
msg = self.to_text + " is not a `Text` value (at " + loc + ")."
Test.fail msg

## Asserts that `self` value is a Text value and ends with `that`.

Expand All @@ -207,15 +211,15 @@ Any.should_start_with self that frames_to_skip=0 = case self of

example_should_end_with = "Hello World!" . should_end_with "ld!"
Any.should_end_with : Text -> Integer -> Spec_Result
Any.should_end_with self that frames_to_skip=0 = case self of
_ : Text -> if self.ends_with that then Spec_Result.Success else
loc = Meta.get_source_location 3+frames_to_skip
msg = self.to_text + " does not end with " + that.to_text + " (at " + loc + ")."
Test.fail msg
_ ->
loc = Meta.get_source_location 2+frames_to_skip
msg = self.to_text + " is not a `Text` value (at " + loc + ")."
Test.fail msg
Any.should_end_with self that frames_to_skip=0 =
loc = Meta.get_source_location 1+frames_to_skip
rhs_error_check that <| case self of
_ : Text -> if self.ends_with that then Spec_Result.Success else
msg = self.to_text + " does not end with " + that.to_text + " (at " + loc + ")."
Test.fail msg
_ ->
msg = self.to_text + " is not a `Text` value (at " + loc + ")."
Test.fail msg

## Asserts that `self` value is a Text value and starts with `that`.

Expand Down Expand Up @@ -266,9 +270,8 @@ Error.should_end_with self that frames_to_skip=0 =

example_should_equal = Examples.add_1_to 1 . should_equal 2
Error.should_equal : Any -> Integer -> Spec_Result
Error.should_equal self that frames_to_skip=0 =
_ = [that]
Test.fail_match_on_unexpected_error self 1+frames_to_skip
Error.should_equal self that frames_to_skip=0 = rhs_error_check that <|
Test.fail_match_on_unexpected_error self 4+frames_to_skip

## Asserts that `self` is within `epsilon` from `that`.

Expand All @@ -294,15 +297,20 @@ Error.should_equal self that frames_to_skip=0 =
1.00000001 . should_equal 1.00000002 epsilon=0.0001
Number.should_equal : Float -> Float -> Integer -> Spec_Result
Number.should_equal self that epsilon=0 frames_to_skip=0 =
matches = case that of
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is way easier of parse, we the function signature clearly stays unaffected.

n : Number -> self.equals n epsilon
_ -> self==that
case matches of
True -> Spec_Result.Success
False ->
loc = Meta.get_source_location 2+frames_to_skip
msg = self.to_text + " did not equal " + that.to_text + " (at " + loc + ")."
Test.fail msg
loc = Meta.get_source_location 1+frames_to_skip
rhs_error_check that <|
matches = case that of
n : Number -> self.equals n epsilon . catch Incomparable_Values _->
## Incomparable_Values is thrown if one of the values is NaN.
We fallback to is_same_object_as,
because in tests we actually NaN.should_equal NaN to succeed.
self.is_same_object_as n
_ -> self==that
case matches of
True -> Spec_Result.Success
False ->
msg = self.to_text + " did not equal " + that.to_text + " (at " + loc + ")."
Test.fail msg

## Asserts that `self` is within `epsilon` from `that`.

Expand All @@ -312,8 +320,8 @@ Number.should_equal self that epsilon=0 frames_to_skip=0 =
- frames_to_skip (optional, advanced): used to alter the location which is
displayed as the source of this error.
Decimal.should_equal : Number -> Float-> Float -> Integer -> Spec_Result
Decimal.should_equal self that epsilon=0 frames_to_skip=0 =
self.to_float . should_equal that.to_float epsilon frames_to_skip+1
Decimal.should_equal self that epsilon=0 frames_to_skip=0 = rhs_error_check that <|
self.to_float . should_equal that.to_float epsilon frames_to_skip+4

## Asserts that `self` value is not an error.

Expand Down Expand Up @@ -427,7 +435,7 @@ Any.should_be_a self typ =
fail_on_wrong_arg_type =
Panic.throw <|
Illegal_Argument.Error "typ ("+typ.to_display_text+") must either be a type or a constructor. Use `should_equal` for value equality test instead."
case Meta.meta typ of
rhs_error_check typ <| case Meta.meta typ of
c : Meta.Constructor -> case Meta.meta self of
a : Meta.Atom ->
if a.constructor == c then Spec_Result.Success else
Expand Down Expand Up @@ -490,6 +498,8 @@ Any.should_be_a self typ =
Any.should_equal_ignoring_order : Any -> Integer -> Spec_Result
Any.should_equal_ignoring_order self that frames_to_skip=0 =
loc = Meta.get_source_location 1+frames_to_skip
if that.is_a Vector . not then
Panic.throw (Illegal_Argument.Error "Expected a Vector, but got a "+that.to_display_text+" (at "+loc+").")
that.each element->
if self.contains element . not then
msg = "The collection (" + self.to_text + ") did not contain " + element.to_text + " (at " + loc + ")."
Expand Down Expand Up @@ -557,7 +567,7 @@ Error.should_equal_ignoring_order self that frames_to_skip=0 =
Any.should_only_contain_elements_in : Any -> Integer -> Spec_Result
Any.should_only_contain_elements_in self that frames_to_skip=0 =
loc = Meta.get_source_location 1+frames_to_skip
self.each element->
rhs_error_check that <| self.each element->
if that.contains element . not then
msg = "The collection contained an element ("+element.to_text+") which was not expected (at " + loc + ")."
Test.fail msg
Expand Down Expand Up @@ -610,13 +620,14 @@ Error.should_only_contain_elements_in self that frames_to_skip=0 =
Any.should_contain : Any -> Integer -> Spec_Result
Any.should_contain self element frames_to_skip=0 =
loc = Meta.get_source_location 1+frames_to_skip
contains_result = Panic.catch No_Such_Method (self.contains element) caught_panic->
if caught_panic.payload.method_name != "contains" then Panic.throw caught_panic else
msg = "The value (" + self.to_text + ") does not support the method `contains` (at " + loc + ")."
rhs_error_check element <|
contains_result = Panic.catch No_Such_Method (self.contains element) caught_panic->
if caught_panic.payload.method_name != "contains" then Panic.throw caught_panic else
msg = "The value (" + self.to_text + ") does not support the method `contains` (at " + loc + ")."
Test.fail msg
if contains_result then Spec_Result.Success else
msg = "The value (" + self.to_text + ") did not contain the element (" + element.to_text + ") (at " + loc + ")."
Test.fail msg
if contains_result then Spec_Result.Success else
msg = "The value (" + self.to_text + ") did not contain the element (" + element.to_text + ") (at " + loc + ")."
Test.fail msg

## Asserts that `self` value contains an element.

Expand Down Expand Up @@ -653,13 +664,14 @@ Error.should_contain self element frames_to_skip=0 =
Any.should_not_contain : Any -> Integer -> Spec_Result
Any.should_not_contain self element frames_to_skip=0 =
loc = Meta.get_source_location 1+frames_to_skip
contains_result = Panic.catch No_Such_Method (self.contains element) caught_panic->
if caught_panic.payload.method_name != "contains" then Panic.throw caught_panic else
msg = "The value (" + self.to_text + ") does not support the method `contains` (at " + loc + ")."
rhs_error_check element <|
contains_result = Panic.catch No_Such_Method (self.contains element) caught_panic->
if caught_panic.payload.method_name != "contains" then Panic.throw caught_panic else
msg = "The value (" + self.to_text + ") does not support the method `contains` (at " + loc + ")."
Test.fail msg
if contains_result.not then Spec_Result.Success else
msg = "The value (" + self.to_text + ") contained the element (" + element.to_text + "), but it was expected to not contain it (at " + loc + ")."
Test.fail msg
if contains_result.not then Spec_Result.Success else
msg = "The value (" + self.to_text + ") contained the element (" + element.to_text + "), but it was expected to not contain it (at " + loc + ")."
Test.fail msg

## Asserts that `self` value does not contain an element.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from Standard.Base import all
radeusgd marked this conversation as resolved.
Show resolved Hide resolved
import Standard.Base.Errors.Illegal_Argument.Illegal_Argument

## PRIVATE
A helper that ensures that the expected value provided in some of the Test
operations is not an error.
The left-hand side may be an error and that will cause a test failure.
But the right-hand side being an error is bad test design and should be fixed.
rhs_error_check that ~action =
case that.is_error of
False -> action
True ->
msg = "Dataflow error ("+that.to_display_text+") provided as expected value. Use `should_fail_with` or change the test."+ ' Error stack trace was:\n'+that.get_stack_trace_text
Panic.throw (Illegal_Argument.Error msg)
Loading
Loading