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

Prop.filter (==>) executes property even if condition does not hold #653

Closed
isberg opened this issue Jan 15, 2024 · 4 comments
Closed

Prop.filter (==>) executes property even if condition does not hold #653

isberg opened this issue Jan 15, 2024 · 4 comments

Comments

@isberg
Copy link

isberg commented Jan 15, 2024

I ran into a confusing situation regarding the ==> operator (which uses Prop.filter: Prop.filter condition assertion). I was expecting the assertion should not be executed if the condition was false, but code like this will blow up (when the list is empty):

open FsCheck
open FsCheck.FSharp
open FsCheck.Xunit

[<Property>]
let ``take the head, then put it back`` (xs : int list) : Property = 
    (List.length xs > 0) ==> 
        (List.head xs :: List.tail xs = xs)

I get it that functional code is a lot safer when pure, but considering that assertion is stated to be 'Testable, which if I understand it correctly means either bool or unit, then it seems to be expected that the assertion can have side-effects.

Am I missing something, is there a more appropriate way to this?

@kurtschelfthout
Copy link
Member

Due to F#’s eagerness, the right hand side is always executed. There is no practical way I know of FsCheck can avoid this without user intervention. You can wrap the right hand side in Lazy to avoid this.

@kurtschelfthout
Copy link
Member

@isberg
Copy link
Author

isberg commented Jan 16, 2024

Thanks @kurtschelfthout! That was exactly what I needed to know. :-)

The following code show what I really was trying to achieve: getting FsCheck and Unquote to be friends.

open FsCheck
open FsCheck.FSharp
open Swensen.Unquote

let lazy_test : Quotations.Expr<bool> -> Lazy<unit> = fun expr -> lazy test expr

type ListProperties =
  static member ``explicit lazy`` (xs : int list) : Property =
    (List.length xs > 0) ==>
        lazy test <@ List.head xs::List.tail xs = xs @>
        
  static member ``implizit lazy`` (xs : int list) : Property =
    (List.length xs > 0) ==>
        lazy_test <@ List.head xs::List.tail xs = xs @>

Check.QuickAll<ListProperties> ()

@isberg isberg closed this as completed Jan 16, 2024
@isberg
Copy link
Author

isberg commented Jan 16, 2024

This issue relates to issue #130 and above code might be relevant for that issue also.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants