Skip to content

Commit

Permalink
Disposable args get disposed
Browse files Browse the repository at this point in the history
  • Loading branch information
dharmaturtle committed Dec 30, 2020
1 parent b1424ab commit 576c5f8
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 11 deletions.
30 changes: 20 additions & 10 deletions src/Hedgehog.Xunit/PropertyAttribute.fs
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,17 @@ type {t.Name} =
:?> AutoGenConfig
config, tests

let dispose (o:obj) =
match o with
| :? IDisposable as d -> d.Dispose()
| _ -> ()

open System.Threading.Tasks
let report (testMethod:MethodInfo) testClass testClassInstance =
let config, tests = parseAttributes testMethod testClass
let testMethodParameters = testMethod.GetParameters()
let gens =
testMethod.GetParameters()
testMethodParameters
|> Array.mapi (fun i p ->
if p.ParameterType.ContainsGenericParameters then
invalidArg p.Name $"The parameter type '{p.ParameterType.Name}' at index {i} is generic, which is unsupported. Consider using a type annotation to make the parameter's type concrete."
Expand All @@ -121,17 +127,21 @@ type {t.Name} =
|> ArrayGen.toGenTuple
let invoke t =
let args =
match testMethod.GetParameters() with
match testMethodParameters with
| [||] -> [||]
| _ -> Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields t
testMethod.Invoke(testClassInstance, args)
|> function
| :? bool as b -> Property.ofBool b
| :? Task as t -> t.GetAwaiter().GetResult()
Property.success ()
| :? Async<unit> as a -> Async.RunSynchronously a
Property.success ()
| _ -> Property.success ()
try
testMethod.Invoke(testClassInstance, args)
|> function
| :? bool as b -> Property.ofBool b
| :? Task as t -> t.GetAwaiter().GetResult()
Property.success ()
| :? Async<unit> as a -> Async.RunSynchronously a
Property.success ()
| _ -> Property.success ()
finally
Array.iter dispose args

Property.forAll gens invoke |> Property.report' tests


Expand Down
31 changes: 30 additions & 1 deletion tests/Hedgehog.Xunit.Tests/PropertyTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module Common =

open Common


module ``Property module tests`` =

type private Marker = class end
Expand Down Expand Up @@ -111,6 +112,7 @@ module ``Property module tests`` =
let ``0 parameters passes`` () =
()


type ``Property class tests``(output: Xunit.Abstractions.ITestOutputHelper) =

[<Property>]
Expand All @@ -137,7 +139,6 @@ module ``Property module with AutoGenConfig tests`` =
let ``Uses custom Int gen with named arg`` i = i = 13

module FailingTests =

type private Marker = class end

type NonstaticProperty = member _.__ = GenX.defaults
Expand Down Expand Up @@ -204,6 +205,7 @@ module ``Module with <Properties> tests`` =
let _, tests = PropertyHelper.parseAttributes testMethod typeof<Marker>.DeclaringType
Assert.Equal(300<tests>, tests)


[<Properties(typeof<Int13>)>]
type ``Class with <Properties> tests``(output: Xunit.Abstractions.ITestOutputHelper) =

Expand All @@ -215,19 +217,22 @@ type ``Class with <Properties> tests``(output: Xunit.Abstractions.ITestOutputHel
let ``Class <Properties> is overriden by Method level <Property>`` (i: int) =
i = 2718


type PropertyInt13Attribute() = inherit PropertyAttribute(typeof<Int13>)
module ``Property inheritance tests`` =
[<PropertyInt13>]
let ``Property inheritance works`` (i: int) =
i = 13


type PropertiesInt13Attribute() = inherit PropertiesAttribute(typeof<Int13>)
[<PropertiesInt13>]
module ``Properties inheritance tests`` =
[<Property>]
let ``Properties inheritance works`` (i: int) =
i = 13


module ``Asynchronous tests`` =

type private Marker = class end
Expand Down Expand Up @@ -271,3 +276,27 @@ module ``Asynchronous tests`` =
[<Fact>]
let ``AsyncBuilder with exception shrinks`` () =
assertShrunk (nameof ``AsyncBuilder with exception shrinks, skipped``) "(11)"


module ``IDisposable test module`` =
let mutable runs = 0
let mutable disposes = 0

type DisposableImplementation() =
interface IDisposable with
member _.Dispose() =
disposes <- disposes + 1
let getMethod = typeof<DisposableImplementation>.DeclaringType.GetMethod

[<Property(skipReason)>]
let ``IDisposable arg get disposed even if exception thrown, skipped`` (_: DisposableImplementation) (i: int) =
runs <- runs + 1
if i > 10 then raise <| Exception()
[<Fact>]
let ``IDisposable arg get disposed even if exception thrown`` () =
let report = PropertyHelper.report (getMethod (nameof ``IDisposable arg get disposed even if exception thrown, skipped``)) typeof<DisposableImplementation>.DeclaringType null
match report.Status with
| Status.Failed _ ->
Assert.NotEqual(0, runs)
Assert.Equal(runs, disposes)
| _ -> failwith "impossible"

0 comments on commit 576c5f8

Please sign in to comment.