FsUnit assert exception message - f#

How to assert on exception message in FsUnit? Something like this from NUnit:
[<Test>]
let ShouldThrowExceptionAndLog() =
Assert.That
((fun () -> Calculator.Calculate "-1"),
Throws.Exception.With.Property("Message").EqualTo("Negatives not allowed: -1"))
EDIT: I don't care about the exception itself, I'd like to test the exception MESSAGE.

AFAIK there is no out-of-the-box matcher to do what you want, but it's easy enough to create one yourself:
open NHamcrest
let throwAnyWithMessage m =
CustomMatcher<obj>(m,
fun f -> match f with
| :? (unit -> unit) as testFunc ->
try
testFunc()
false
with
| ex -> ex.Message = m
| _ -> false )
usage:
(fun () -> raise <| Exception("Foo") |> ignore) |> should throwAnyWithMessage "Foo" // pass
(fun () -> raise <| Exception("Bar") |> ignore) |> should throwAnyWithMessage "Foo" // fail

Related

How to use bind and map in place of nested matches

F# 6.0.3
I have seen some solutions on Google that are close to what I need; but being a Newbie I can't quite get how to use bind and map to get the solution.
I have many working procedures of the following format:
Example #1:
let saveAllDiagnosis =
let savealldiagnosis = match m.Encounter with
| None -> failwith "No encounter found"
| Some e -> match e.EncounterId with
| None -> failwith "No Encounter id found"
| Some id -> m.AllDiagnosisList
|> List.iter ( fun dx -> match dx.Key with
| None -> ()
| Some k -> Async.RunSynchronously (editAllDiagnosisInPreviousEncountersAsync id dx))
savealldiagnosis
Example #2
let saveEncounterDiagnosis =
let savedx = match m.Encounter with
| None -> failwith "No encounter found"
| Some e -> match e.EncounterId with
| None -> failwith "No Encounter id found"
| Some id -> m.BillingDiagnosisList |> List.iter ( fun dx -> Async.RunSynchronously (saveDxAsync id dx))
savedx
As can be seen, these are nested methods with almost identical behavior--differing only in the async procedure being called and the initializing list. What I would like to do is something along the lines of:
let runProcedures (fn: Model->Async) Model = ????
That is, a single procedue that encapsulates everything except the Async method and it's parameters but manages all the "None"s in a better way.
I hope my intent is clear.
TIA
If you are happy with using exceptions, then you do not even need railway-oriented programming (ROP). ROP is useful for more complex validation tasks, but I think exceptions are often perfectly reasonable and easy way of handling errors. In your case, you could define a helper that extracts a value of option<'T> or fails with a given error message:
let orFailWith msg opt =
match opt with
| Some v -> v
| None -> failwithf "%s" msg
Using this, you can then rewrite your code as follows:
let saveAllDiagnosis =
let e = m.Encounter |> orFailWith "No encounter found"
let id = e.EncounterId |> orFailWith "No Encounter id found"
for dx in m.AllDiagnosisList do
dx.Key |> Option.iter (fun k ->
editAllDiagnosisInPreviousEncountersAsync id dx |> Async.RunSynchronously)
let saveEncounterDiagnosis =
let e = m.Encounter |> orFailWith "No encounter found"
let id = e.EncounterId |> orFailWith "No Encounter id found"
for dx in m.BillingDiagnosisList do
saveDxAsync id dx |> Async.RunSynchronously
As I do not know the broader context of this, it is hard to say more - your code is imperative, but that may be perfectly fine if you are following the sandwich pattern.
Using mentioned ROP code can be rewritten as such. Result is used to track error and throw it at the end of pipeline. With current design is possible to avoid exceptions by just logging error instead of throwing at before last line.
type Encounter = { EncounterId : int option }
type Diagnostic = { Key : int option }
type Thing = {
Encounter : Encounter option
AllDiagnosisList : Diagnostic list
}
let editAllDiagnosisInPreviousEncountersAsync id diag = async { return () }
module Result =
let ofOption err opt =
match opt with
| Some v -> Ok v
| None -> Error err
let join res =
match res with
| Error v
| Ok v -> v
let saveAllDiagnosis m =
m.Encounter
|> Result.ofOption "No encounter found" // get value from option or log error
|> Result.map (fun e -> e.EncounterId)
|> Result.bind (Result.ofOption "No Encounter id found") // get EncounterId or log error
|> Result.map (fun id -> (
m.AllDiagnosisList
|> Seq.where (fun dx -> dx.Key.IsSome)
|> Seq.iter (fun dx -> Async.RunSynchronously (editAllDiagnosisInPreviousEncountersAsync id dx))
))
|> Result.mapError failwith // throw error
|> Result.join // Convert Result<unit, unit> into unit
The solutions posted above are very helpful to this newbie. But adding my own two cents worth, I going with this:
let _deleteDxFromEncounterAsync (encounterId:int) (dx:Diagnosis) : Async<unit> = deleteDxFromEncounterAsync encounterId dx.Description
let _deleteDxFromAllPreviousEncountersAsync (encounterId:int) (dx:Diagnosis) : Async<unit> = deleteDxFromAllPreviousEncountersAsync encounterId dx.Description
let _saveDxAsync (encounterId:int) (dx:Diagnosis) : Async<unit> = saveDxAsync encounterId dx
let _editAllDiagnosisInPreviousEncountersAsync (encounterId:int) (dx:Diagnosis) : Async<unit> = editAllDiagnosisInPreviousEncountersAsync encounterId dx
let listchk (dxs:Diagnosis list) : Diagnosis list option =
match dxs with
| [] -> None
| _ -> Some dxs
let _save (fn:int -> Diagnosis-> Async<unit>) (dxs:Diagnosis list) : unit =
match dxs |> listchk, m.Encounter |> Option.bind (fun v -> v.EncounterId) with
| Some dxs, Some id -> dxs |> List.iter (fun dx -> Async.RunSynchronously(fn id dx))
| _,_ -> failwith "Missing Encounter or EncounterId or Empty List"
m.DeletedBillingDiagnosis |>_save _deleteDxFromEncounterAsync
m.DeletedAllDiagnosis |>_save _deleteDxFromAllPreviousEncountersAsync
m.BillingDiagnosisList |>_save _saveDxAsync
m.AllDiagnosisList |> List.filter (fun dx -> dx.Key.IsSome) |>_save _editAllDiagnosisInPreviousEncountersAsync
For speed, in the future, I will probably have the Async functions act on the entire list at one time rather then one item; but for now, this code comes closest to my intent in asking the question. IMPROVEMENTS AND CRITISM IS GLADDLY APPRECIATED! F# is fun!
Thanks to all.

What does a # before a type name mean in F#?

What does a # before a type name mean in F#?
For example here:
let getTestData (inner : int [] -> #seq<int>) (outer : #seq<int> [] -> #seq<'U>) =
(testData |> Array.map inner) |> outer
The syntax #type is called a "flexible type" and it is a shortcut for saying that the type can be any type that implements the given interface. This is useful in cases where the user of a function may want to specify a concrete type (like an array or a list).
For a very simple example, let's look at this:
let printAll (f: unit -> seq<int>) =
for v in f () do printfn "%d" v
The caller has to call printAll with a lambda that returns a sequence:
printAll (fun () -> [1; 2; 3]) // Type error
printAll (fun () -> [1; 2; 3] :> seq<int>) // Works, but tedious to write!
If you use flexible type, the return type of the function can be any implementation of seq<int>:
let printAll (f: unit -> #seq<int>) =
for v in f () do printfn "%d" v
printAll (fun () -> [1; 2; 3]) // No problem!
In reality, the syntax #typ is just a shortcut for saying 'T when 'T :> typ, so you can rewrite the function in my example as:
let printAll<'T when 'T :> seq<int>> (f: unit -> 'T) =
for v in f () do printfn "%d" v

How to switch from error track back to success track in railway-oriented program in F#?

Using AsyncResult from Scott Wlashin and wondering how I can change from the error track to the success track.
Pseudo-code:
let orchestratorFunction() : AsyncResult<Customer, CustomerError> = asyncResult {
let! output1 = callFunction1 arg1 arg2 |> AsyncResult.MapError CustomerError.Val1
let! output2 = callFunction2 arg1 arg2 |> AsyncResult.MapError CustomerError.Val2
let! output3 = callFunction3 arg1 arg2 |> AsyncResult.MapError (fun e -> ********HERE I WANT TO GET BACK TO THE SUCCESS PATH AND RETURN output3*********)
}
or a more realistic example:
let createCustomer() : AsyncResult<Customer, CustomerError> = asyncResult {
let! customerDto = mapDtoFromHttpRequest arg1 arg2 |> AsyncResult.MapError CustomerError.Val1
let! validatedCustomer = validateCustomer arg1 arg2 |> AsyncResult.MapError CustomerError.Val2
let! validatedCustomer = insertCustomer arg1 arg2
|> AsyncResult.MapError (fun e ->
match e with
| DuplicateCustomer _ ->
loadCustomerById xx
|> (fun c ->
if c.LastCausationId = validatedCustomer.LastCausationId
then c
else e))
}
So basically I am trying to get out of the unhappy path, because this is an idempotent REST operation and any repetitive requests will be answered with 200 OK, as if they were the original request, so that the client can have a simple logic.
Based on the answer from #Gus to this question (AsyncResult and handling rollback) it seems that bindError is what I needed. I created a similar to his bindError bindExn, and it seems to work as well, so now both error and exns can be converted to Ok:
(From Gus):
/// Apply a monadic function to an AsyncResult error
let bindError (f: 'a -> AsyncResult<'b,'c>) (xAsyncResult : AsyncResult<_, _>) :AsyncResult<_,_> = async {
let! xResult = xAsyncResult
match xResult with
| Ok x -> return Ok x
| Error err -> return! f err
}
(My code):
let bindExn
(f: exn -> AsyncResult<'a,'b>)
(xAsyncResult:AsyncResult<_,_>)
: AsyncResult<'a,'b>
=
async {
let! res =
xAsyncResult
|> Async.Catch
|> Async.map(function
| Choice1Of2 res -> res |> AsyncResult.ofResult
| Choice2Of2 (ex:exn) ->
f ex
)
return! res
}

Parameterized exception type [duplicate]

How can I define an exception like the following?
exception CustomExn<'TMessage> of 'TMessage list
Maybe you can just inherit from System.Exception?
type CustomExn<'TMessage> (message:'TMessage list) =
inherit System.Exception ()
let test =
try
raise (CustomExn["string"] )
with
| :? CustomExn<string> -> "CustomExn of string"
| :? CustomExn<int> -> "CustomExn of int"
| _ -> "Everything else"
Not sure it is possible with F# Exception Definitions according to specs (page 164-165)
This one also NOT A GOOD SOLUTION because try with will only catch ExceptionList<string> in this case so there is no good way to make it generic
type ExceptionList<'a>(msgList: 'a list) =
inherit Exception()
member __.MessageList = msgList
let mock() =
raise <| ExceptionList(["failed"])
try
mock() //raises ExceptionList<string>
with
//this catch block won't fire, because it is not generic, it is ExceptionList<obj>
| :? ExceptionList<_> as exnList ->
exnList.MessageList
|> List.iter (printfn "%A")
The better way though: Result<'a,'b list>:
let mock'() =
if DateTime.Now.Ticks % 2L = 0L
then Ok()
else Error(["failed"])
let result = mock'()
match result with
| Ok _ -> printfn "Ok!"
| Error (msgList) ->
msgList
|> List.iter (printfn "%A")
Added There is a workaround with type loss:
type ExceptionList(msgList: obj list) =
inherit Exception()
member __.MessageList = msgList
// Here is F# exception definition
exception CustomException of ExceptionList
let failwithMany msgs =
raise <| CustomException (ExceptionList(msgs))
let mock() =
//zero type checking here
failwithMany[1;2;"a";[];"failed"]
try
mock()
with
// exnList is list of objects
| CustomException exnList ->
exnList.MessageList
|> List.iter (printfn "%A")

Quotations and pattern matching in F#

In a new console application, just pasting the following code leads to the exception "The parameter is not a recognized method name".
Does the following code work on your installation?
Joker: Do you know any reason why it would not work on mine?
// Learn more about F# at http://fsharp.net
// See the 'F# Tutorial' project for more help.
let somefunction1 arg = ()
let somefunction2 () = ()
open Quotations.DerivedPatterns
let test() =
let d = <# somefunction1() #>
let e = <# somefunction2() #>
match d with
| SpecificCall <# somefunction1() #> (a,b ,c) -> printfn "somefunction"
| _ -> printfn "something else"
match d with
| SpecificCall <# somefunction1 #> (a,b ,c) -> printfn "somefunction"
| _ -> printfn "something else"
match e with
| SpecificCall <# somefunction2() #> (a,b ,c) -> printfn "somefunction"
| _ -> printfn "something else"
//THIS FAILS HERE saying "The parameter is not a recognized method name"
match e with
| SpecificCall <# somefunction2 #> (a,b ,c) -> printfn "somefunction"
| _ -> printfn "something else"
[<EntryPoint>]
let main argv =
test()
printfn "%A" argv
0 // return an integer exit code
Looking at the definition of active pattern SpecificCall defined in the compiler I find:
[<CompiledName("SpecificCallPattern")>]
let (|SpecificCall|_|) templateParameter =
// Note: precomputation
match templateParameter with
| (Lambdas(_,Call(_,minfo1,_)) | Call(_,minfo1,_)) ->
let isg1 = minfo1.IsGenericMethod
let gmd = if isg1 then minfo1.GetGenericMethodDefinition() else null
// end-of-precomputation
(fun tm ->
match tm with
| Call(obj,minfo2,args)
#if FX_NO_REFLECTION_METADATA_TOKENS
when (minfo1.MethodHandle = minfo2.MethodHandle &&
#else
when (minfo1.MetadataToken = minfo2.MetadataToken &&
#endif
if isg1 then
minfo2.IsGenericMethod && gmd = minfo2.GetGenericMethodDefinition()
else
minfo1 = minfo2) ->
Some(obj,(minfo2.GetGenericArguments() |> Array.toList),args)
| _ -> None)
| _ ->
invalidArg "templateParameter" (SR.GetString(SR.QunrecognizedMethodCall))
Offhand, that looks okay to me... Is it possible that you've shadowed the original definition of var somehow? For instance, the following self-contained example works fine for me:
let var<'a>() = Unchecked.defaultof<'a>
match <# var<int>() #> with
| Quotations.DerivedPatterns.SpecificCall <# var #> (obj,_,[]) ->
printfn "var"
| _ -> printfn "something else"

Resources