-
Notifications
You must be signed in to change notification settings - Fork 25
UserGuide
Unquote has builds targeting .NET 4.0, .NET 4.5, and Portable Profile 259 and is fully supported on Mono.
To use Unquote within an F# unit testing project, you must obtain and add a reference to Unquote.dll. There are two ways to obtain Unquote:
- Install the latest version of the Unquote NuGet package to your unit testing project, this will automatically add the correct reference to Unquote.dll according to your project type.
- Download and unzip the featured release of Unquote from the Downloads page and then locate and add a reference to Unquote.dll via the Visual Studio Add Reference dialog. The .NET 4.0 builds are located in the net40 folder, the .NET 4.5 builds are located in the net45 folder, and the Portable Profile 259 builds are located in the profile259 folder.
To use Unquote in a project targeting FSharp.Core 4.4.0.0 or greater, you will need to use a binding redirect (NuGet will add the binding redirect automatically if installed from there).
You must also obtain and install your unit testing framework of choice (NUnit, xUnit.net, and Fuchu have been given special support, but any exception-based unit testing framework including MSTest is supported as well).
To use Unquote within FSI, locate and add a reference to Unquote.dll using the #r
directive (use the .NET 4.0 or .NET 4.5 build).
Support for Silverlight 4 has been dropped.
The '?' suffixed operators have all been replaced with equivalent '!' suffixed operators in Unquote 3.0.0 in order to avoid conflicts with Nullable operators introduced by F# 3.0. You may open the package Swensen.Unquote.Assertions.Obsolete
to continue using the now obsolete '?' suffixed operators.
The signature of Swensen.Unquote.Operators.unquote
has been changed from Quotations.Expr -> unit
to Quotations.Expr -> UnquotedExpression
.
The Swensen.Unquote
namespace contains three AutoOpen
modules: Assertions
, Operators
, and Extensions
. Therefore you may choose to bring all of Unquote's features into top-level scope simply by opening Swensen.Unquote
or you may choose to open individual modules or even alias individual modules for a finer level of control.
The Swensen.Unquote.Assertions
module contains all functions used for performing unit testing assertions. These include test
, raises
, and a series of '!' suffixed binary infix operators. All of these operators can be used within a unit test enabled project or FSI.
Unquote chooses its output source as follows
- if loaded in FSI then print to the console
- else if xUnit or NUnit loaded in currently executing assembly, then use appropriate test failed methods
- else throw a
Swensen.Unquote.Assertions.AssertionFailureException
with a message
The following is a reference of the functions available and some examples:
val inline test : Quotations.Expr<bool> -> unit
> test <@ (1+2)/3 = 1 @>;;
val it : unit = ()
> test <@ (1+2)/3 = 2 @>;;
Test failed:
(1 + 2) / 3 = 2
3 / 3 = 2
1 = 2
false
val it : unit = ()
val inline ( =! ) : 'a -> 'a -> unit when 'a : equality
> [1;2;3;4] =! [4;3;2;1];;
Test failed:
[1; 2; 3; 4] = [4; 3; 2; 1]
false
val it : unit = ()
val inline ( <! ) : 'a -> 'a -> unit when 'a : comparison
val inline ( >! ) : 'a -> 'a -> unit when 'a : comparison
val inline ( <=! ) : 'a -> 'a -> unit when 'a : comparison
val inline ( >=! ) : 'a -> 'a -> unit when 'a : comparison
val inline ( <>! ) : 'a -> 'a -> unit when 'a : equality
val inline raises<'a when 'a :> exn> : Quotations.Expr -> unit
> raises<exn> <@ (null:string).Length @>;;
val it : unit = ()
> raises<NullReferenceException> <@ (null:string).Length @>;;
val it : unit = ()
> raises<System.ArgumentException> <@ (null:string).Length @>;;
Test failed:
Expected exception of type 'ArgumentException', but 'NullReferenceException' was raised instead
null.Length
System.NullReferenceException: Object reference not set to an instance of an object.
at Swensen.Unquote.Evaluation.evalInstance@275(FSharpList`1 env, FSharpOption`1 expr)
at Swensen.Unquote.Evaluation.eval@133(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Evaluation.eval(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Evaluation.eval(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Reduction.reduce(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Reduction.loop@132(FSharpList`1 env, FSharpExpr expr, FSharpList`1 acc)
val it : unit = ()
> raises<exn> <@ 3 @>;;
Test failed:
Expected exception of type 'Exception', but no exception was raised
3
val it : unit = ()
val inline raisesWith : Expr -> (#exn -> Expr<bool>) -> unit
> raisesWith<System.NullReferenceException> <@ (null:string).Length @> (fun e -> <@ e.ToString() = null @>);;
Test failed:
The expected exception was raised, but the exception assertion failed:
Exception Assertion:
System.NullReferenceException: Object reference not set to an instance of an object.
at Swensen.Unquote.Evaluation.evalInstance@275(FSharpList`1 env, FSharpOption`1 expr)
at Swensen.Unquote.Evaluation.eval@133(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Evaluation.eval(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Evaluation.eval(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Reduction.reduce(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Reduction.loop@132(FSharpList`1 env, FSharpExpr expr, FSharpList`1 acc).ToString() = null
"System.NullReferenceException: Object reference not set to an instance of an object.
at Swensen.Unquote.Evaluation.evalInstance@275(FSharpList`1 env, FSharpOption`1 expr)
at Swensen.Unquote.Evaluation.eval@133(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Evaluation.eval(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Evaluation.eval(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Reduction.reduce(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Reduction.loop@132(FSharpList`1 env, FSharpExpr expr, FSharpList`1 acc)" = null
false
Test Expression:
null.Length
System.NullReferenceException: Object reference not set to an instance of an object.
at Swensen.Unquote.Evaluation.evalInstance@275(FSharpList`1 env, FSharpOption`1 expr)
at Swensen.Unquote.Evaluation.eval@133(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Evaluation.eval(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Evaluation.eval(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Reduction.reduce(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Reduction.loop@132(FSharpList`1 env, FSharpExpr expr, FSharpList`1 acc)
val it : unit = ()
The Swensen.Unquote.Operators
module contains additional functions for decompiling, evaluating, and reducing quotation expressions. The following is a reference of the functions available and some examples:
val inline decompile : Quotations.Expr -> string
> decompile <@ (1+2)/3 @>;;
val it : string = "(1 + 2) / 3"
val inline eval : Quotations.Expr<'a> -> 'a
> eval <@ "Hello World".Length + 20 @>;;
val it : int = 31
val inline evalRaw : Quotations.Expr -> 'a
> evalRaw<int> <@@ "Hello World".Length + 20 @@>;;
val it : int = 31
val inline reduce : Quotations.Expr -> Quotations.Expr
> <@ (1+2)/3 @> |> reduce |> decompile;;
val it : string = "3 / 3"
val inline reduceFully : Quotations.Expr -> Quotations.Expr list
> <@ (1+2)/3 @> |> reduceFully |> List.map decompile;;
val it : string list = ["(1 + 2) / 3"; "3 / 3"; "1"]
val inline isReduced : Quotations.Expr -> bool
> <@ (1+2)/3 @> |> isReduced;;
val it : bool = false
> <@ 1 @> |> isReduced;;
val it : bool = true
val inline unquote : Quotations.Expr -> UnquotedExpression
> unquote <@ (1+2)/3 @>;;
val it : UnquotedExpression =
(1 + 2) / 3
3 / 3
1
val it : unit = ()
The following are functions which accept a variable environment for processing synthetic expressions with unbound variables:
val inline evalWith : Map<Var,obj> -> Quotations.Expr<'a> -> 'a
val inline evalRawWith : Map<Var,obj> -> Expr -> 'a
val inline reduceWith : Map<Var,obj> -> Quotations.Expr<'a> -> Quotations.Expr
val inline reduceFullyWith : Map<Var,obj> -> Quotations.Expr<'a> -> Quotations.Expr list
The Swensen.Unquote.Extensions
module duplicates functions in the Swensen.Unquote.Operators
as instance type extensions on Quotations.Expr
and Quotations.Expr<'a>
. But it also includes an instance property extension on System.Type
, FSharpName
, which returns the F#-style signature of a type:
> typeof<int>.FSharpName;;
val it : string = "int"
> typeof<int[]>.FSharpName;;
val it : string = "int[]"
> typeof<int[,,,]>.FSharpName;;
val it : string = "int[,,,]"
> typeof<System.Collections.Generic.Dictionary<string, float>>.FSharpName;;
val it : string = "Dictionary<string, float>"
> typeof<unit -> int -> string>.FSharpName;;
val it : string = "unit -> int -> string"
> typeof<unit -> (float -> int) -> string>.FSharpName;;
val it : string = "unit -> (float -> int) -> string"
> typeof<int * float * string>.FSharpName;;
val it : string = "int * float * string"
> typeof<int * (bool * float) * string>.FSharpName;;
val it : string = "int * (bool * float) * string"
> typeof<int -> (list<(int * (int -> string))[]> * string[,,])>.FSharpName;;
val it : string = "int -> list<(int * (int -> string))[]> * string[,,]"
> typedefof<int -> int>.FSharpName;;
val it : string = "'T -> 'TResult"