FsCheck, I am not getting `Prop.forAll` to work (F#) - f#

I am not coming right with FsCheck, when I try and use Prop.forAll.
I have created two tests to demonstrate what I am doing, expecting them both to fail.
type Data = { value: int }
type NeverAOne =
static member Data () =
Arb.generate<int>
|> Gen.filter (fun x -> x <> 1)
|> Gen.map (fun x -> { value = x })
|> Arb.fromGen
[<Property(Arbitrary = [| typeof<NeverAOne> |] )>] (* Fails *)
let ``Test One`` (x: Data) =
x.value = 1
[<Fact>]
let ``Test Two`` () = (* Passes *)
Prop.forAll (NeverAOne.Data ()) (fun x -> x.value = 1)
In this sample, Test Two passes. If I add breakpoints, I can see it is because no data is generated, so it iterates through 0 samples, which means none fail.
I am convinced that I am using Prop.forAll wrong, but though everything I have read through, I cannot find it.

If you mark the test as a plain Xunit Fact (rather than as a FsCheck Property), you have to explicitly check the property:
[<Fact>]
let ``Test Two`` () =
let prop = Prop.forAll (NeverAOne.Data ()) (fun x -> x.value = 1)
Check.QuickThrowOnFailure prop
The result I get is then:
System.Exception : Falsifiable, after 1 test (0 shrinks) (StdGen (74764374, 296947750)):
Original:
{ value = -2 }
Or you can just mark the test as a Property, of course:
[<Property>]
let ``Test Three`` () =
Prop.forAll (NeverAOne.Data ()) (fun x -> x.value = 1)

Related

F# Type Provider Set Optional Field With Required Parameter, Getting a "Specified Method is not supported" error

I'm trying to build a type provider for Bloomberg (they provide schema xml files that describe the types). I'm able to generate types that look like the following class:
type Example(x: option<int>) as self =
[<DefaultValue>] val mutable X: option<int>
do
self.X <- x
member this.GetX with get() = self.X
The problem is that this requires you to instantiate the example type as follows:
Example(Some 1)
Ideally I would prefer to instantiate it as like the XmlProvider choice type:
type Example(x: int) as self =
[<DefaultValue>] val mutable X: option<int>
do
self.X <- Some x
member this.GetX with get() = self.X
let example = Example(1)
When I attempt doing this:
let some =
FSharpType.GetUnionCases(field.FieldType)
|> Array.filter (fun x -> x.Name = "Some")
|> Array.exactlyOne
let arg' = Expr.NewUnionCase(some, arg)
let setValue = Expr.FieldSet(this, field, arg')
I get the following error:
"Specified method is not supported."
I can successfully generate the first type using this:'
let setValue = Expr.FieldSet(this, field, arg)
The full source code is available here: https://github.com/alphaarchitect/BloombergProvider/blob/main/src/BloombergProvider.DesignTime/BloombergProvider.DesignTime.fs#L457
Any ideas?
///Edit
The entire code block is from this:
es
|> Result.mapError (fun xs -> ChoiceError.Element(c.Name, xs))
|> Result.map (fun xs ->
xs
|> List.iter (fun (_, field) ->
let parameter = ProvidedParameter(field.Name, field.FieldType)
providedChoiceType.AddMember
<| ProvidedConstructor(
[parameter],
invokeCode =
fun args ->
match args with
| this :: [arg] ->
let setValue = Expr.FieldSet(this, field, arg)
let enumField = Expr.FieldSet(this, enumField, Expr.FieldGet(enum.GetField(field.Name)))
Expr.Sequential(enumField, setValue)
| _ -> failwith "wrong ctor parameters"))
{
Enum = enum
Object = providedChoiceType
}))
to this:
es
|> Result.mapError (fun xs -> ChoiceError.Element(c.Name, xs))
|> Result.map (fun xs ->
xs
|> List.iter (fun (type', field) ->
let parameter = ProvidedParameter(field.Name, type')
providedChoiceType.AddMember
<| ProvidedConstructor(
[parameter],
invokeCode =
fun args ->
match args with
| this :: [arg] ->
let some =
FSharpType.GetUnionCases(field.FieldType)
|> Array.filter (fun x -> x.Name = "Some")
|> Array.exactlyOne
let arg' = Expr.NewUnionCase(some, arg)
let setValue = Expr.FieldSet(this, field, arg')
let enumField = Expr.FieldSet(this, enumField, Expr.FieldGet(enum.GetField(field.Name)))
Expr.Sequential(enumField, setValue)
| _ -> failwith "wrong ctor parameters"))
{
Enum = enum
Object = providedChoiceType
}))
The error occurs when you try to instantiate the type provider.
Running and evaluating the code works correctly in the quotation evaluator.
This is not a direct answer to the question, but it may help you if you cannot figure out how to get this to work. In general, I think that building type providers is easier if you do not try to do a "lot of coding" in the provided methods and constructors.
In your approach, you have a type that inherits from obj and so you have to generate a lot of code to store data in fields. In contrast, the JSON provider types inherit from JsonValue which does all the storing for them - so they have to do relatively little. For example, say you want to generate something like:
type Example(x: int, y:string) as self =
[<DefaultValue>] val mutable X: option<int>
[<DefaultValue>] val mutable Y: option<string>
do
self.X <- Some x
self.Y <- Some y
member this.GetX = self.X
member this.GetY = self.Y
It may be easier to define a base class which is essentially a dictionary an then generate a class inheriting from this:
type DataClass() =
let d = System.Collections.Generic.Dictionary<_, _>()
member x.SetSome(s, v) = d.[s] <- Some v
member x.Get<'T>(s) = d.[s] |> Option.map (fun v -> unbox<'T> v)
type Example(x: int, y:string) =
inherit DataClass()
do
base.SetSome("x", box x)
base.SetSome("y", box y)
member this.GetX = base.Get<int>("x")
member this.GetY = base.Get<string>("y")
This way, the only kind of provided code that you have to write is method calls, which is generally easier to do - and possibly less error-prone.

FsUnit.Xunit list should contain an x such that f x

I am not sure how to write my test in FsUnit.Xunit.
I want to check that at least one element in my list satisfies a predicate. I know how to write this using should be True, but usually you can get better error messages by using the specialized functions.
Hopefully this code makes it clear what I am trying to achieve:
open Xunit
open FsUnit.Xunit
type Foo =
{
X : int
}
[<Fact>]
let ``squares`` () =
let xs =
[ { X = 1 }; { X = 2 }; { X = 3 } ]
|> List.map (fun foo -> { X = foo.X * foo.X })
actual
|> should exists (satisfies (fun foo -> foo.X = 9)) // Not real code
I would do this:
xs
|> Seq.map (fun foo -> foo.X)
|> should contain 9
Error output is useful:
Expected: Contains 8
Actual: seq [1; 4; 9]
If you want more context, you can do this instead:
open FsUnit.CustomMatchers
...
xs |> should containf (fun foo -> foo.X = 9)
Error output is:
Expected: Contains <fun:squares#21-1>
Actual: [{ X = 1 }; { X = 4 }; { X = 9 }]
The only downside of this approach is that the "Expected" message no longer displays the specific value you're looking for.

Using F# Custom Operator Caused FS0002 Compile Error

I defined some custom pipeline operators for Async and Task objects, but get compile error FS0002.
[<AutoOpen>]
module AsyncOperators =
type AsyncOperatorHelper = AsyncOperatorHelper with
static member (=>) (computation, AsyncOperatorHelper) =
fun cont ->
async.Bind(computation, cont)
static member (=>) (computation: Task<'a>, AsyncOperatorHelper) =
fun cont ->
async.Bind(computation |> Async.AwaitTask, cont)
static member (=>) (computation: Task, AsyncOperatorHelper) =
fun cont ->
async.Bind(computation |> Async.AwaitTask, cont)
static member (=->) (cont: 'a -> Task<'b>, AsyncOperatorHelper) =
cont >> Async.AwaitTask
static member (=->) (cont: 'a -> Task, AsyncOperatorHelper) =
cont >> Async.AwaitTask
static member (=->) (cont: 'a -> Async<'t>, AsyncOperatorHelper) =
cont
let inline (|~>) a b = (a => AsyncOperatorHelper) (b =-> AsyncOperatorHelper)
let inline (>~>) a b x = x |> (a =-> AsyncOperatorHelper) |~> (b =-> AsyncOperatorHelper)
let _test () =
let x = async.Return 0
let add1 = fun (s: int) -> (async.Return(s + 1))
// COMPILE OK !!
let y = x |~> add1
// But if I expand add1 in the expression:
// error FS0002: This function takes too many arguments, or is used in a context where a function is not expected
let z = x |~> (fun (s: int) -> (async.Return(s + 1)))
()
The two expressions look the same, but why the second one get FS0002 error? How can I fix the problem?

Property-based test continues to pass when I expect it to fail

I'm sure this is trivial. However, the following test will always pass:
let transform number =
match number % 3, number % 5 with
| 0, 0 -> "FizzBuzz"
| _, 0 -> "Buzz"
| 0, _ -> "Fizz"
| _ -> number.ToString()
[<Fact>]
let ``FizzBuzz.transform returns FizzBuzz`` () =
let fiveAndThrees = Arb.generate<int> |> Gen.map ((*) (3 * 5))
|> Arb.fromGen
Prop.forAll fiveAndThrees <| fun number ->
let actual = transform number
let expected = "jbdhjsdhjdsjhsdglsdjlljh"
expected = actual
I've also tried:
Check.QuickThrowOnFailure <| (expected = actual)
Specifically, why does this test continue to pass when it should obviously fail?
You're creating the property, but never actually checking it. It just sits there, never executed once.
To check the property, you need to pass it to one of the Check.* methods:
[<Fact>]
let ``FizzBuzz.transform returns FizzBuzz`` () =
let fiveAndThrees = Arb.generate<int> |> Gen.map ((*) (3 * 5))
|> Arb.fromGen
let myProperty = Prop.forAll fiveAndThrees <| fun number ->
let actual = transform number
let expected = "jbdhjsdhjdsjhsdglsdjlljh"
expected = actual
Check.QuickThrowOnFailure myProperty
You can also use FsCheck.Xunit and its [<Property>] attribute:
[<Property(QuietOnSuccess = true)>]
let ``FizzBuzz.transform returns FizzBuzz`` () =
let fiveAndThrees =
Arb.generate<int> |> Gen.map ((*) (3 * 5)) |> Arb.fromGen
Prop.forAll fiveAndThrees <| fun number ->
let actual = FizzBuzz.transform number
let expected = "FizzBuzz"
expected = actual

F# - Reverse Pipeline order

How come that I can do:
let printTeams x : unit =
let rnd = new Random()
Seq.toList x |> List.sortBy (fun x -> rnd.Next()) |> printTeams'
but not:
let printTeams x : unit =
let rnd = new Random()
printTeamsRec' <| Seq.toList x <| List.sortBy(fun x -> rnd.Next())
I'm just getting an error on the last one, which says:
Type mismatch. Expecting a string
list -> 'a -> 'b but given a
string list -> unit The type ''a
-> 'b' does not match the type 'unit'
The error occures on the third line at printTeamsRec'
Any help would be appreciate.
Two things: the translation of the forward pipe to backwards pipe is incorrect, and precedence is different.
let printTeams x : unit =
let rnd = new Random()
printTeamsRec' <| (List.sortBy(fun x -> rnd.Next()) <| Seq.toList x)

Resources