From 33f9c288794df6c0c0ac04522b99bb16e087120a Mon Sep 17 00:00:00 2001 From: Adam Becker Date: Thu, 3 Dec 2020 18:43:30 +0000 Subject: [PATCH 01/17] Implement C# Fluent API, along with LINQ --- src/Hedgehog/CSharp/Gen.fs | 268 ++++++++++++++++++++++++++++++++ src/Hedgehog/CSharp/Property.fs | 35 +++++ src/Hedgehog/CSharp/Range.fs | 16 ++ src/Hedgehog/Gen.fs | 91 +---------- src/Hedgehog/Hedgehog.fsproj | 4 +- src/Hedgehog/LinqSupport.fs | 72 --------- 6 files changed, 330 insertions(+), 156 deletions(-) create mode 100644 src/Hedgehog/CSharp/Gen.fs create mode 100644 src/Hedgehog/CSharp/Property.fs create mode 100644 src/Hedgehog/CSharp/Range.fs delete mode 100644 src/Hedgehog/LinqSupport.fs diff --git a/src/Hedgehog/CSharp/Gen.fs b/src/Hedgehog/CSharp/Gen.fs new file mode 100644 index 00000000..253d15c8 --- /dev/null +++ b/src/Hedgehog/CSharp/Gen.fs @@ -0,0 +1,268 @@ +namespace Hedgehog.CSharp + +#if !FABLE_COMPILER + +open System +open System.Runtime.CompilerServices +open Hedgehog + +module Gen = + + let FromValue value : Gen<'T> = + Gen.constant(value) + + let FromRandom random : Gen<'T> = + Gen.ofRandom(random) + + let Delay (func : Func<_>) : Gen<'T> = + Gen.delay func.Invoke + + let Create shrink random : Gen<'T> = + Gen.create shrink random + + let Sized (scaler : Func<_, _>) : Gen<'T> = + Gen.sized scaler.Invoke + + let inline Integral range : Gen<'T> = + Gen.integral range + + let Item sequence : Gen<'T> = + Gen.item sequence + + let Frequency gens : Gen<'T> = + Gen.frequency gens + + let Choice gens : Gen<'T> = + Gen.choice gens + + let ChoiceRecursive nonrecs recs = + Gen.choiceRec nonrecs recs + + let Char lo hi = + Gen.char lo hi + + let UnicodeAll = + Gen.unicodeAll + + let Digit = + Gen.digit + + let Lower = + Gen.lower + + let Upper = + Gen.upper + + let Ascii = + Gen.ascii + + let Latin1 = + Gen.latin1 + + let Unicode = + Gen.unicode + + let Alpha = + Gen.alpha + + let AlphaNumeric = + Gen.alphaNum + + let Bool = + Gen.bool + + let Byte range = + Gen.byte range + + let SByte range = + Gen.sbyte range + + let Int16 range = + Gen.int16 range + + let UInt16 range = + Gen.uint16 range + + let Int32 range = + Gen.int range + + let UInt32 range = + Gen.uint32 range + + let Int64 range = + Gen.int64 range + + let UInt64 (range : Range) = + Gen.uint64 range + + let Double range = + Gen.double range + + let Single (range : Range) = + Gen.float range + + let Guid = + Gen.guid + + let DateTime = + Gen.dateTime + +[] +type GenExtensions = + + [] + member _.Apply(mf : Gen>) ma = + Gen.apply (mf |> Gen.map (fun f -> f.Invoke)) ma + + [] + member _.Array(gen : Gen<'T>, range) = + Gen.array range gen + + [] + member _.Enumerable(gen : Gen<'T>, range) = + Gen.seq range gen + + [] + member _.GenerateTree(gen : Gen<'T>) = + Gen.generateTree gen + + [] + member _.List(gen : Gen<'T>, range) = + Gen.list range gen + + [] + member _.NoShrink gen : Gen<'T> = + Gen.noShrink gen + + [] + member _.Option(gen : Gen<'T>) = + Gen.option gen + + [] + member _.PrintSample(gen : Gen<'T>) = + Gen.printSample gen + + [] + member _.Resize(gen, size) : Gen<'T> = + Gen.resize size gen + + [] + member _.Sample(gen : Gen<'T>, size, count) = + Gen.sample size count gen + + [] + member _.SampleTree(gen : Gen<'T>, size, count) = + Gen.sampleTree size count gen + + [] + member _.Scale(gen : Gen<'T>, scaler: Func<_, _>) = + Gen.scale scaler.Invoke gen + + [] + member _.SelectMany(gen : Gen<'T>, f: Func<_, _>) : Gen<'U> = + Gen.bind gen f.Invoke + + [] + member _.SelectMany (g, f : Func<_, _>, proj : Func<'T, 'TCollection, 'TResult>) : Gen<'TResult> = + Gen.bind g (fun a -> + Gen.map (fun b -> proj.Invoke(a, b)) (f.Invoke(a)) + ) + + [] + member _.SelectRandom(gen : Gen<'T>, f: Func<_, _>) : Gen<'U> = + Gen.mapRandom f.Invoke gen + + [] + member _.SelectTree(gen : Gen<'T>, f: Func<_, _>) : Gen<'U> = + Gen.mapTree f.Invoke gen + + [] + member _.Select(gen : Gen<'T>, f: Func<_, _>) : Gen<'U> = + Gen.map f.Invoke gen + + [] + member _.Select2(genA, f: Func<'T, 'U, 'TResult>, genB) = + Gen.map2 (fun a b -> f.Invoke(a, b)) + genA + genB + + [] + member _.Select3(genA, f: Func<'T, 'U, 'V, 'TResult>, genB, genC) = + Gen.map3 (fun a b c -> f.Invoke(a, b, c)) + genA + genB + genC + + [] + member _.Select4(genA, f: Func<'T, 'U, 'V, 'W, 'TResult>, genB, genC, genD) = + Gen.map4 (fun a b c d -> f.Invoke(a, b, c, d)) + genA + genB + genC + genD + + [] + member _.Shrink(gen : Gen<'T>, f: Func<_, _>) = + Gen.shrink f.Invoke gen + + [] + member _.ShrinkLazy(gen : Gen<'T>, f: Func<_, _>) = + Gen.shrinkLazy f.Invoke gen + + [] + member _.Some(gen) : Gen<'T> = + Gen.some gen + + [] + member _.String gen range = + Gen.string range gen + + [] + member _.ToGen(random) : Gen<'T> = + Gen.ofRandom random + + [] + member _.ToRandom(gen : Gen<'T>) = + Gen.toRandom gen + + [] + member _.TryFinally(gen : Gen<'T>, after: Action) = + Gen.tryFinally gen after.Invoke + + [] + member _.TryWhere(gen : Gen<'T>, after: Func<_, _>) = + Gen.tryWith gen after.Invoke + + [] + member _.TryWith(gen : Gen<'T>, after: Func<_, _>) = + Gen.tryWith gen after.Invoke + + [] + member _.Tuple2(gen : Gen<'T>) = + Gen.tuple gen + + [] + member _.Tuple3(gen : Gen<'T>) = + Gen.tuple3 gen + + [] + member _.Tuple4(gen : Gen<'T>) = + Gen.tuple4 gen + + [] + member _.Where(gen : Gen<'T>, predicate: Func<_, _>) = + Gen.filter predicate.Invoke gen + + [] + member _.Zip(genA, genB) : Gen<'T * 'U> = + Gen.zip genA genB + + [] + member _.Zip3(genA, genB, genC) : Gen<'T * 'U * 'V> = + Gen.zip3 genA genB genC + + [] + member _.Zip4(genA, genB, genC, genD) : Gen<'T * 'U * 'V * 'W> = + Gen.zip4 genA genB genC genD + +#endif diff --git a/src/Hedgehog/CSharp/Property.fs b/src/Hedgehog/CSharp/Property.fs new file mode 100644 index 00000000..bbfaf27f --- /dev/null +++ b/src/Hedgehog/CSharp/Property.fs @@ -0,0 +1,35 @@ +namespace Hedgehog.CSharp + +#if !FABLE_COMPILER + +open System +open System.Runtime.CompilerServices +open Hedgehog + +[] +type PropertyExtensions = + + [] + member _.Where(prop, filter : Func<'T, _>) = + Property.filter filter.Invoke prop + + [] + member _.Select(property, mapper : Func<'T, 'U>) = + Property.map mapper.Invoke property + + [] + member _.Select(property, mapper : Action<'T>) = + Property.bind property (Property.fromThrowing mapper.Invoke) + + [] + member _.SelectMany(property, binder : Func<_, _>, projection : Func<'T, 'TCollection, 'TResult>) = + Property.bind property (fun a -> + Property.map (fun b -> projection.Invoke (a, b)) (binder.Invoke(a))) + + [] + member _.SelectMany(property, binder : Func<'T, Property<'U>>, projection : Action<_, _>) = + Property.bind property (fun a -> + Property.bind (binder.Invoke a) (fun b -> + Property.fromThrowing projection.Invoke (a, b))) + +#endif diff --git a/src/Hedgehog/CSharp/Range.fs b/src/Hedgehog/CSharp/Range.fs new file mode 100644 index 00000000..de49a826 --- /dev/null +++ b/src/Hedgehog/CSharp/Range.fs @@ -0,0 +1,16 @@ +namespace Hedgehog.CSharp + +#if !FABLE_COMPILER + +open System +open System.Runtime.CompilerServices +open Hedgehog + +[] +type RangeExtensions = + + [] + member _.Select(range, mapper : Func<'T, 'U>) = + Range.map mapper.Invoke range + +#endif diff --git a/src/Hedgehog/Gen.fs b/src/Hedgehog/Gen.fs index 81f30bd8..cf02290a 100644 --- a/src/Hedgehog/Gen.fs +++ b/src/Hedgehog/Gen.fs @@ -1,7 +1,6 @@ namespace Hedgehog open System -open Hedgehog.Numeric /// A generator for values and shrink trees of type 'a. [] @@ -9,31 +8,25 @@ type Gen<'a> = | Gen of Random> module Gen = - [] + let ofRandom (r : Random>) : Gen<'a> = Gen r - [] let toRandom (Gen r : Gen<'a>) : Random> = r - [] let delay (f : unit -> Gen<'a>) : Gen<'a> = Random.delay (toRandom << f) |> ofRandom - [] let tryFinally (m : Gen<'a>) (after : unit -> unit) : Gen<'a> = Random.tryFinally (toRandom m) after |> ofRandom - [] let tryWith (m : Gen<'a>) (k : exn -> Gen<'a>) : Gen<'a> = Random.tryWith (toRandom m) (toRandom << k) |> ofRandom - [] let create (shrink : 'a -> seq<'a>) (random : Random<'a>) : Gen<'a> = Random.map (Tree.unfold id shrink) random |> ofRandom - [] let constant (x : 'a) : Gen<'a> = Tree.singleton x |> Random.constant |> ofRandom @@ -47,48 +40,36 @@ module Gen = Tree.bind (run seed1 m) (run seed2 << k) - [] let bind (m0 : Gen<'a>) (k0 : 'a -> Gen<'b>) : Gen<'b> = bindRandom (toRandom m0) (toRandom << k0) |> ofRandom - [] + let bindFlipped (k0 : 'a -> Gen<'b>) (m0 : Gen<'a>) : Gen<'b> = + bindRandom (toRandom m0) (toRandom << k0) |> ofRandom + let apply (gf : Gen<'a -> 'b>) (gx : Gen<'a>) : Gen<'b> = bind gf <| fun f -> - bind gx <| fun x -> - constant (f x) + bind gx <| (f >> constant) - [] let mapRandom (f : Random> -> Random>) (g : Gen<'a>) : Gen<'b> = toRandom g |> f |> ofRandom - [] let mapTree (f : Tree<'a> -> Tree<'b>) (g : Gen<'a>) : Gen<'b> = mapRandom (Random.map f) g - [] let map (f : 'a -> 'b) (g : Gen<'a>) : Gen<'b> = mapTree (Tree.map f) g -#if !FABLE_COMPILER - [] -#endif let map2 (f : 'a -> 'b -> 'c) (gx : Gen<'a>) (gy : Gen<'b>) : Gen<'c> = bind gx <| fun x -> bind gy <| fun y -> constant (f x y) -#if !FABLE_COMPILER - [] -#endif let map3 (f : 'a -> 'b -> 'c -> 'd) (gx : Gen<'a>) (gy : Gen<'b>) (gz : Gen<'c>) : Gen<'d> = bind gx <| fun x -> bind gy <| fun y -> bind gz <| fun z -> constant (f x y z) -#if !FABLE_COMPILER - [] -#endif let map4 (f : 'a -> 'b -> 'c -> 'd -> 'e) (gx : Gen<'a>) (gy : Gen<'b>) (gz : Gen<'c>) (gw : Gen<'d>) : Gen<'e> = bind gx <| fun x -> bind gy <| fun y -> @@ -96,31 +77,21 @@ module Gen = bind gw <| fun w -> constant (f x y z w) - [] let zip (gx : Gen<'a>) (gy : Gen<'b>) : Gen<'a * 'b> = map2 (fun x y -> x, y) gx gy -#if !FABLE_COMPILER - [] -#endif let zip3 (gx : Gen<'a>) (gy : Gen<'b>) (gz : Gen<'c>) : Gen<'a * 'b * 'c> = map3 (fun x y z -> x, y, z) gx gy gz -#if !FABLE_COMPILER - [] -#endif let zip4 (gx : Gen<'a>) (gy : Gen<'b>) (gz : Gen<'c>) (gw : Gen<'d>) : Gen<'a * 'b * 'c * 'd> = map4 (fun x y z w -> x, y, z, w) gx gy gz gw - [] let tuple (g : Gen<'a>) : Gen<'a * 'a> = zip g g - [] let tuple3 (g : Gen<'a>) : Gen<'a * 'a * 'a> = zip3 g g g - [] let tuple4 (g : Gen<'a>) : Gen<'a * 'a * 'a * 'a> = zip4 g g g g @@ -157,19 +128,16 @@ module Gen = // /// Prevent a 'Gen' from shrinking. - [] let noShrink (g : Gen<'a>) : Gen<'a> = let drop (Node (x, _)) = Node (x, Seq.empty) mapTree drop g /// Apply an additional shrinker to all generated trees. - [] let shrinkLazy (f : 'a -> seq<'a>) (g : Gen<'a>) : Gen<'a> = mapTree (Tree.expand f) g /// Apply an additional shrinker to all generated trees. - [] let shrink (f : 'a -> List<'a>) (g : Gen<'a>) : Gen<'a> = shrinkLazy (Seq.ofList << f) g @@ -178,19 +146,16 @@ module Gen = // /// Used to construct generators that depend on the size parameter. - [] let sized (f : Size -> Gen<'a>) : Gen<'a> = Random.sized (toRandom << f) |> ofRandom /// Overrides the size parameter. Returns a generator which uses the /// given size instead of the runtime-size parameter. - [] let resize (n : int) (g : Gen<'a>) : Gen<'a> = mapRandom (Random.resize n) g /// Adjust the size parameter, by transforming it with the given /// function. - [] let scale (f : int -> int) (g : Gen<'a>) : Gen<'a> = sized <| fun n -> resize (f n) g @@ -200,7 +165,6 @@ module Gen = // /// Generates a random number in the given inclusive range. - [] let inline integral (range : Range<'a>) : Gen<'a> = create (Shrink.towards <| Range.origin range) (Random.integral range) @@ -213,7 +177,6 @@ module Gen = /// Randomly selects one of the values in the list. /// The input list must be non-empty. - [] let item (xs0 : seq<'a>) : Gen<'a> = gen { let xs = Array.ofSeq xs0 if Array.isEmpty xs then @@ -226,13 +189,12 @@ module Gen = /// Uses a weighted distribution to randomly select one of the gens in the list. /// This generator shrinks towards the first generator in the list. /// The input list must be non-empty. - [] let frequency (xs0 : seq>) : Gen<'a> = gen { let xs = List.ofSeq xs0 let total = - List.sum (List.map fst xs) + List.sumBy fst xs let rec pick n = function | [] -> @@ -249,7 +211,6 @@ module Gen = /// Randomly selects one of the gens in the list. /// The input list must be non-empty. - [] let choice (xs0 : seq>) : Gen<'a> = gen { let xs = Array.ofSeq xs0 if Array.isEmpty xs then @@ -264,7 +225,6 @@ module Gen = /// is halved. When the size gets to one or less, selections are no longer made /// from the recursive list. /// The first argument (i.e. the non-recursive input list) must be non-empty. - [] let choiceRec (nonrecs : seq>) (recs : seq>) : Gen<'a> = sized <| fun n -> if n <= 1 then @@ -294,7 +254,6 @@ module Gen = Random.sized (tryN 0 << max 1) /// Generates a value that satisfies a predicate. - [] let filter (p : 'a -> bool) (g : Gen<'a>) : Gen<'a> = let rec loop () = Random.bind (toRandom g |> tryFilterRandom p) <| function @@ -308,7 +267,6 @@ module Gen = |> ofRandom /// Tries to generate a value that satisfies a predicate. - [] let tryFilter (p : 'a -> bool) (g : Gen<'a>) : Gen<'a option> = ofRandom << Random.bind (toRandom g |> tryFilterRandom p) <| function | None -> @@ -317,7 +275,6 @@ module Gen = Tree.map Some x |> Random.constant /// Runs an option generator until it produces a 'Some'. - [] let some (g : Gen<'a option>) : Gen<'a> = bind (filter Option.isSome g) <| function | Some x -> @@ -330,7 +287,6 @@ module Gen = // /// Generates a 'None' part of the time. - [] let option (g : Gen<'a>) : Gen<'a option> = sized <| fun n -> frequency [ @@ -342,7 +298,6 @@ module Gen = (List.length xs) >= n /// Generates a list using a 'Range' to determine the length. - [] let list (range : Range) (g : Gen<'a>) : Gen> = ofRandom <| (Random.sized @@ -354,12 +309,10 @@ module Gen = }) /// Generates an array using a 'Range' to determine the length. - [] let array (range : Range) (g : Gen<'a>) : Gen> = list range g |> map Array.ofList /// Generates a sequence using a 'Range' to determine the length. - [] let seq (range : Range) (g : Gen<'a>) : Gen> = list range g |> map Seq.ofList @@ -367,48 +320,40 @@ module Gen = // Combinators - Characters // - [] // Generates a random character in the specified range. let char (lo : char) (hi : char) : Gen = integral <| Range.constant (int lo) (int hi) |> map char /// Generates a Unicode character, including invalid standalone surrogates: /// '\000'..'\65535' - [] let unicodeAll : Gen = let lo = System.Char.MinValue let hi = System.Char.MaxValue char lo hi // Generates a random digit. - [] let digit : Gen = char '0' '9' // Generates a random lowercase character. - [] let lower : Gen = char 'a' 'z' // Generates a random uppercase character. - [] let upper : Gen = char 'A' 'Z' /// Generates an ASCII character: '\000'..'\127' - [] let ascii : Gen = char '\000' '\127' /// Generates a Latin-1 character: '\000'..'\255' - [] let latin1 : Gen = char '\000' '\255' /// Generates a Unicode character, excluding noncharacters /// ('\65534', '\65535') and invalid standalone surrogates /// ('\000'..'\65535' excluding '\55296'..'\57343'). - [] let unicode : Gen = let isNoncharacter x = x = Operators.char 65534 @@ -418,18 +363,15 @@ module Gen = |> filter (not << System.Char.IsSurrogate) // Generates a random alpha character. - [] let alpha : Gen = choice [lower; upper] - [] // Generates a random alpha-numeric character. let alphaNum : Gen = choice [lower; upper; digit] /// Generates a random string using 'Range' to determine the length and the /// specified character generator. - [] let string (range : Range) (g : Gen) : Gen = sized <| fun size -> g |> array range @@ -440,57 +382,46 @@ module Gen = // /// Generates a random boolean. - [] let bool : Gen = item [false; true] /// Generates a random byte. - [] let byte (range : Range) : Gen = integral range /// Generates a random signed byte. - [] let sbyte (range : Range) : Gen = integral range /// Generates a random signed 16-bit integer. - [] let int16 (range : Range) : Gen = integral range /// Generates a random unsigned 16-bit integer. - [] let uint16 (range : Range) : Gen = integral range /// Generates a random signed 32-bit integer. - [] let int (range : Range) : Gen = integral range /// Generates a random unsigned 32-bit integer. - [] let uint32 (range : Range) : Gen = integral range /// Generates a random signed 64-bit integer. - [] let int64 (range : Range) : Gen = integral range /// Generates a random unsigned 64-bit integer. - [] let uint64 (range : Range) : Gen = integral range /// Generates a random 64-bit floating point number. - [] let double (range : Range) : Gen = create (Shrink.towardsDouble <| Range.origin range) (Random.double range) /// Generates a random 64-bit floating point number. - [] let float (range : Range) : Gen = (double range) |> map float @@ -509,7 +440,6 @@ module Gen = // /// Generates a random globally unique identifier. - [] let guid : Gen = gen { let! bs = array (Range.constant 16 16) (byte <| Range.constantBounded ()) return System.Guid bs @@ -521,7 +451,6 @@ module Gen = /// Range.constantFrom /// (System.DateTime (2000, 1, 1)) System.DateTime.MinValue System.DateTime.MaxValue /// Gen.dateTime range - [] let dateTime (range : Range) : Gen = gen { let! ticks = range |> Range.map (fun dt -> dt.Ticks) |> integral @@ -535,11 +464,11 @@ module Gen = let! ticks = range |> Range.map (fun dt -> dt.Ticks) |> integral // Ensure there is no overflow near the edges when adding the offset let minOffsetMinutes = - max + max (-14L * 60L) ((DateTimeOffset.MaxValue.Ticks - ticks) / TimeSpan.TicksPerMinute * -1L) let maxOffsetMinutes = - min + min (14L * 60L) ((ticks - DateTimeOffset.MinValue.Ticks) / TimeSpan.TicksPerMinute) let! offsetMinutes = int (Range.linearFrom 0 (Operators.int minOffsetMinutes) (Operators.int maxOffsetMinutes)) @@ -550,27 +479,23 @@ module Gen = // Sampling // - [] let sampleTree (size : Size) (count : int) (g : Gen<'a>) : List> = let seed = Seed.random () toRandom g |> Random.replicate count |> Random.run seed size - [] let sample (size : Size) (count : int) (g : Gen<'a>) : List<'a> = sampleTree size count g |> List.map Tree.outcome /// Run a generator. The size passed to the generator is always 30; /// if you want another size then you should explicitly use 'resize'. - [] let generateTree (g : Gen<'a>) : Tree<'a> = let seed = Seed.random () toRandom g |> Random.run seed 30 - [] let printSample (g : Gen<'a>) : unit = let forest = sampleTree 10 5 g for tree in forest do diff --git a/src/Hedgehog/Hedgehog.fsproj b/src/Hedgehog/Hedgehog.fsproj index 65aad5ef..e71996ee 100644 --- a/src/Hedgehog/Hedgehog.fsproj +++ b/src/Hedgehog/Hedgehog.fsproj @@ -32,7 +32,9 @@ https://github.com/hedgehogqa/fsharp-hedgehog/blob/master/doc/tutorial.md - + + + diff --git a/src/Hedgehog/LinqSupport.fs b/src/Hedgehog/LinqSupport.fs deleted file mode 100644 index 5e653168..00000000 --- a/src/Hedgehog/LinqSupport.fs +++ /dev/null @@ -1,72 +0,0 @@ -namespace Hedgehog - -open System -open System.Runtime.CompilerServices - -open Hedgehog - -[] -module GenLinqSupport = - - // Support for `where`: - [] - [] - let where (g : Gen<'a>) (f : Func<'a, bool>) : Gen<'a> = - Gen.filter (fun x -> f.Invoke x) g - - [] - [] - let select (g : Gen<'a>) (f : Func<'a, 'b>) : Gen<'b> = - Gen.map (fun x -> f.Invoke x) g - - [] - [] - let bind2 (g : Gen<'a>) (f : Func<'a, Gen<'b>>) (proj : Func<'a, 'b, 'c>) : Gen<'c> = - gen { - let! a = g - let! b = f.Invoke a - return proj.Invoke (a, b) - } - -[] -module PropertyLinqSupport = - - [] - [] - let where (p : Property<'a>) (f : Func<'a, bool>) : Property<'a> = - Property.filter (fun x -> f.Invoke x) p - - [] - [] - let select (p : Property<'a>) (f : Func<'a, 'b>) : Property<'b> = - Property.map (fun x -> f.Invoke x) p - - [] - [] - let bind2 (pa : Property<'a>) (f : Func<'a, Property<'b>>) (proj : Func<'a, 'b, 'c>) : Property<'c> = - Property.bind pa (fun a -> Property.bind (f.Invoke a) (fun b -> Property.success (proj.Invoke (a, b)))) - - // This supports simple assertions in `select`: - [] -#if !FABLE_COMPILER - [] -#endif - let selectUnit (p : Property<'a>) (f : Action<'a>) : Property = - Property.bind p (Property.fromThrowing f.Invoke) - - // This supports assertions as `select`: - [] -#if !FABLE_COMPILER - [] -#endif - let bind2Unit (pa : Property<'a>) (f : Func<'a, Property<'b>>) (proj : Action<'a, 'b>) : Property = - Property.bind pa (fun a -> - Property.bind (f.Invoke a) (fun b -> Property.fromThrowing proj.Invoke (a, b))) - -[] -module RangeLinqSupport = - - [] - [] - let select (r : Range<'a>) (f : Func<'a, 'b>) : Range<'b> = - Range.map (fun x -> f.Invoke x) r From e48a6afd7e93c17ec73b5c14198649ea55cac9a7 Mon Sep 17 00:00:00 2001 From: Adam Becker Date: Sun, 6 Dec 2020 23:03:03 +0000 Subject: [PATCH 02/17] Might help to write the extensions correctly --- src/Hedgehog/CSharp/Gen.fs | 74 ++++++++++++------------ src/Hedgehog/CSharp/Property.fs | 12 ++-- src/Hedgehog/CSharp/Range.fs | 4 +- src/Hedgehog/Property.fs | 5 +- tests/Hedgehog.CSharp.Tests/LinqTests.cs | 7 ++- tests/Hedgehog.CSharp.Tests/NameTests.cs | 3 +- 6 files changed, 55 insertions(+), 50 deletions(-) diff --git a/src/Hedgehog/CSharp/Gen.fs b/src/Hedgehog/CSharp/Gen.fs index 253d15c8..a7606582 100644 --- a/src/Hedgehog/CSharp/Gen.fs +++ b/src/Hedgehog/CSharp/Gen.fs @@ -111,90 +111,90 @@ module Gen = type GenExtensions = [] - member _.Apply(mf : Gen>) ma = + static member inline Apply(mf : Gen>) ma = Gen.apply (mf |> Gen.map (fun f -> f.Invoke)) ma [] - member _.Array(gen : Gen<'T>, range) = + static member inline Array(gen : Gen<'T>, range) = Gen.array range gen [] - member _.Enumerable(gen : Gen<'T>, range) = + static member inline Enumerable(gen : Gen<'T>, range) = Gen.seq range gen [] - member _.GenerateTree(gen : Gen<'T>) = + static member inline GenerateTree(gen : Gen<'T>) = Gen.generateTree gen [] - member _.List(gen : Gen<'T>, range) = + static member inline List(gen : Gen<'T>, range) = Gen.list range gen [] - member _.NoShrink gen : Gen<'T> = + static member inline NoShrink gen : Gen<'T> = Gen.noShrink gen [] - member _.Option(gen : Gen<'T>) = + static member inline Option(gen : Gen<'T>) = Gen.option gen [] - member _.PrintSample(gen : Gen<'T>) = + static member inline PrintSample(gen : Gen<'T>) = Gen.printSample gen [] - member _.Resize(gen, size) : Gen<'T> = + static member inline Resize(gen, size) : Gen<'T> = Gen.resize size gen [] - member _.Sample(gen : Gen<'T>, size, count) = + static member inline Sample(gen : Gen<'T>, size, count) = Gen.sample size count gen [] - member _.SampleTree(gen : Gen<'T>, size, count) = + static member inline SampleTree(gen : Gen<'T>, size, count) = Gen.sampleTree size count gen [] - member _.Scale(gen : Gen<'T>, scaler: Func<_, _>) = + static member inline Scale(gen : Gen<'T>, scaler: Func<_, _>) = Gen.scale scaler.Invoke gen [] - member _.SelectMany(gen : Gen<'T>, f: Func<_, _>) : Gen<'U> = + static member inline SelectMany(gen : Gen<'T>, f: Func<_, _>) : Gen<'U> = Gen.bind gen f.Invoke [] - member _.SelectMany (g, f : Func<_, _>, proj : Func<'T, 'TCollection, 'TResult>) : Gen<'TResult> = - Gen.bind g (fun a -> + static member inline SelectMany(gen, f : Func<_, _>, proj : Func<'T, 'TCollection, 'TResult>) : Gen<'TResult> = + Gen.bind gen (fun a -> Gen.map (fun b -> proj.Invoke(a, b)) (f.Invoke(a)) ) [] - member _.SelectRandom(gen : Gen<'T>, f: Func<_, _>) : Gen<'U> = + static member inline SelectRandom(gen : Gen<'T>, f: Func<_, _>) : Gen<'U> = Gen.mapRandom f.Invoke gen [] - member _.SelectTree(gen : Gen<'T>, f: Func<_, _>) : Gen<'U> = + static member inline SelectTree(gen : Gen<'T>, f: Func<_, _>) : Gen<'U> = Gen.mapTree f.Invoke gen [] - member _.Select(gen : Gen<'T>, f: Func<_, _>) : Gen<'U> = + static member inline Select(gen : Gen<'T>, f: Func<_, _>) : Gen<'U> = Gen.map f.Invoke gen [] - member _.Select2(genA, f: Func<'T, 'U, 'TResult>, genB) = + static member inline Select2(genA, f: Func<'T, 'U, 'TResult>, genB) = Gen.map2 (fun a b -> f.Invoke(a, b)) genA genB [] - member _.Select3(genA, f: Func<'T, 'U, 'V, 'TResult>, genB, genC) = + static member inline Select3(genA, f: Func<'T, 'U, 'V, 'TResult>, genB, genC) = Gen.map3 (fun a b c -> f.Invoke(a, b, c)) genA genB genC [] - member _.Select4(genA, f: Func<'T, 'U, 'V, 'W, 'TResult>, genB, genC, genD) = + static member inline Select4(genA, f: Func<'T, 'U, 'V, 'W, 'TResult>, genB, genC, genD) = Gen.map4 (fun a b c d -> f.Invoke(a, b, c, d)) genA genB @@ -202,67 +202,67 @@ type GenExtensions = genD [] - member _.Shrink(gen : Gen<'T>, f: Func<_, _>) = + static member inline Shrink(gen : Gen<'T>, f: Func<_, _>) = Gen.shrink f.Invoke gen [] - member _.ShrinkLazy(gen : Gen<'T>, f: Func<_, _>) = + static member inline ShrinkLazy(gen : Gen<'T>, f: Func<_, _>) = Gen.shrinkLazy f.Invoke gen [] - member _.Some(gen) : Gen<'T> = + static member inline Some(gen) : Gen<'T> = Gen.some gen [] - member _.String gen range = + static member inline String gen range = Gen.string range gen [] - member _.ToGen(random) : Gen<'T> = + static member inline ToGen(random) : Gen<'T> = Gen.ofRandom random [] - member _.ToRandom(gen : Gen<'T>) = + static member inline ToRandom(gen : Gen<'T>) = Gen.toRandom gen [] - member _.TryFinally(gen : Gen<'T>, after: Action) = + static member inline TryFinally(gen : Gen<'T>, after: Action) = Gen.tryFinally gen after.Invoke [] - member _.TryWhere(gen : Gen<'T>, after: Func<_, _>) = + static member inline TryWhere(gen : Gen<'T>, after: Func<_, _>) = Gen.tryWith gen after.Invoke [] - member _.TryWith(gen : Gen<'T>, after: Func<_, _>) = + static member inline TryWith(gen : Gen<'T>, after: Func<_, _>) = Gen.tryWith gen after.Invoke [] - member _.Tuple2(gen : Gen<'T>) = + static member inline Tuple2(gen : Gen<'T>) = Gen.tuple gen [] - member _.Tuple3(gen : Gen<'T>) = + static member inline Tuple3(gen : Gen<'T>) = Gen.tuple3 gen [] - member _.Tuple4(gen : Gen<'T>) = + static member inline Tuple4(gen : Gen<'T>) = Gen.tuple4 gen [] - member _.Where(gen : Gen<'T>, predicate: Func<_, _>) = + static member inline Where(gen : Gen<'T>, predicate: Func<_, _>) = Gen.filter predicate.Invoke gen [] - member _.Zip(genA, genB) : Gen<'T * 'U> = + static member inline Zip(genA, genB) : Gen<'T * 'U> = Gen.zip genA genB [] - member _.Zip3(genA, genB, genC) : Gen<'T * 'U * 'V> = + static member inline Zip3(genA, genB, genC) : Gen<'T * 'U * 'V> = Gen.zip3 genA genB genC [] - member _.Zip4(genA, genB, genC, genD) : Gen<'T * 'U * 'V * 'W> = + static member inline Zip4(genA, genB, genC, genD) : Gen<'T * 'U * 'V * 'W> = Gen.zip4 genA genB genC genD #endif diff --git a/src/Hedgehog/CSharp/Property.fs b/src/Hedgehog/CSharp/Property.fs index bbfaf27f..9550def0 100644 --- a/src/Hedgehog/CSharp/Property.fs +++ b/src/Hedgehog/CSharp/Property.fs @@ -10,24 +10,24 @@ open Hedgehog type PropertyExtensions = [] - member _.Where(prop, filter : Func<'T, _>) = - Property.filter filter.Invoke prop + static member inline Where(property, filter : Func<'T, _>) = + Property.filter filter.Invoke property [] - member _.Select(property, mapper : Func<'T, 'U>) = + static member inline Select(property, mapper : Func<'T, 'U>) = Property.map mapper.Invoke property [] - member _.Select(property, mapper : Action<'T>) = + static member inline Select(property, mapper : Action<'T>) = Property.bind property (Property.fromThrowing mapper.Invoke) [] - member _.SelectMany(property, binder : Func<_, _>, projection : Func<'T, 'TCollection, 'TResult>) = + static member inline SelectMany(property, binder : Func<_, _>, projection : Func<'T, 'TCollection, 'TResult>) = Property.bind property (fun a -> Property.map (fun b -> projection.Invoke (a, b)) (binder.Invoke(a))) [] - member _.SelectMany(property, binder : Func<'T, Property<'U>>, projection : Action<_, _>) = + static member inline SelectMany(property, binder : Func<'T, Property<'U>>, projection : Action<_, _>) = Property.bind property (fun a -> Property.bind (binder.Invoke a) (fun b -> Property.fromThrowing projection.Invoke (a, b))) diff --git a/src/Hedgehog/CSharp/Range.fs b/src/Hedgehog/CSharp/Range.fs index de49a826..b7518eb9 100644 --- a/src/Hedgehog/CSharp/Range.fs +++ b/src/Hedgehog/CSharp/Range.fs @@ -8,9 +8,9 @@ open Hedgehog [] type RangeExtensions = - + [] - member _.Select(range, mapper : Func<'T, 'U>) = + static member inline Select(range, mapper : Func<'T, 'U>) = Range.map mapper.Invoke range #endif diff --git a/src/Hedgehog/Property.fs b/src/Hedgehog/Property.fs index 2afe24f0..2c7cc3c5 100644 --- a/src/Hedgehog/Property.fs +++ b/src/Hedgehog/Property.fs @@ -414,7 +414,10 @@ module Property = /// Converts a possibly-throwing function to /// a property by treating "no exception" as success. - let internal fromThrowing (f : 'a -> unit) (x : 'a) : Property = +#if !FABLE_COMPILER + [] +#endif + let fromThrowing (f : 'a -> unit) (x : 'a) : Property = try f x success () diff --git a/tests/Hedgehog.CSharp.Tests/LinqTests.cs b/tests/Hedgehog.CSharp.Tests/LinqTests.cs index 5382bd3a..7aa22293 100644 --- a/tests/Hedgehog.CSharp.Tests/LinqTests.cs +++ b/tests/Hedgehog.CSharp.Tests/LinqTests.cs @@ -2,6 +2,7 @@ // Import Check and ForAll: using static Hedgehog.Property; +using Hedgehog.CSharp; namespace Hedgehog.CSharp.Tests { @@ -104,7 +105,7 @@ from i in ForAll(Gen.Int32(Range.Constant(1, 10))) from j in ForAll(Gen.Int32(Range.Constant(1, i))) select j <= i); } - + [Fact] public void CanUseSelectWithGen() { @@ -121,7 +122,7 @@ from i in Gen.Bool where i select !i; } - + [Fact] public void CanUseSelectManyWithGen() { @@ -130,7 +131,7 @@ from i in Gen.Bool from j in Gen.Bool select !i; } - + [Fact] public void CanUseSelectWithRange() { diff --git a/tests/Hedgehog.CSharp.Tests/NameTests.cs b/tests/Hedgehog.CSharp.Tests/NameTests.cs index 03084404..d4da067c 100644 --- a/tests/Hedgehog.CSharp.Tests/NameTests.cs +++ b/tests/Hedgehog.CSharp.Tests/NameTests.cs @@ -9,7 +9,8 @@ namespace Hedgehog.CSharp.Tests public class NameTests { private static Type[] _publicApiTypes = - { typeof(Gen) + { typeof(Hedgehog.CSharp.Gen) + , typeof(Hedgehog.CSharp.GenExtensions) , typeof(Range) , typeof(Property) }; From efb7eb850c4fb0f2461e9df65fb0b500987dec4d Mon Sep 17 00:00:00 2001 From: Adam Becker Date: Sun, 6 Dec 2020 23:06:38 +0000 Subject: [PATCH 03/17] Remove vestigial code from a previous experiment. --- src/Hedgehog/Gen.fs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Hedgehog/Gen.fs b/src/Hedgehog/Gen.fs index cf02290a..33d85de8 100644 --- a/src/Hedgehog/Gen.fs +++ b/src/Hedgehog/Gen.fs @@ -43,9 +43,6 @@ module Gen = let bind (m0 : Gen<'a>) (k0 : 'a -> Gen<'b>) : Gen<'b> = bindRandom (toRandom m0) (toRandom << k0) |> ofRandom - let bindFlipped (k0 : 'a -> Gen<'b>) (m0 : Gen<'a>) : Gen<'b> = - bindRandom (toRandom m0) (toRandom << k0) |> ofRandom - let apply (gf : Gen<'a -> 'b>) (gx : Gen<'a>) : Gen<'b> = bind gf <| fun f -> bind gx <| (f >> constant) From f558a760376ade44adc3a5c0730433e82db98344 Mon Sep 17 00:00:00 2001 From: Adam Becker Date: Mon, 7 Dec 2020 02:15:22 +0000 Subject: [PATCH 04/17] Add type annotations --- src/Hedgehog/CSharp/Gen.fs | 156 ++++++++++++++++---------------- src/Hedgehog/CSharp/Property.fs | 12 +-- src/Hedgehog/CSharp/Range.fs | 2 +- 3 files changed, 85 insertions(+), 85 deletions(-) diff --git a/src/Hedgehog/CSharp/Gen.fs b/src/Hedgehog/CSharp/Gen.fs index a7606582..f618d0f1 100644 --- a/src/Hedgehog/CSharp/Gen.fs +++ b/src/Hedgehog/CSharp/Gen.fs @@ -8,261 +8,261 @@ open Hedgehog module Gen = - let FromValue value : Gen<'T> = + let FromValue (value : 'T) : Gen<'T> = Gen.constant(value) - let FromRandom random : Gen<'T> = + let FromRandom (random : Random>) : Gen<'T> = Gen.ofRandom(random) let Delay (func : Func<_>) : Gen<'T> = Gen.delay func.Invoke - let Create shrink random : Gen<'T> = + let Create (shrink : 'T -> seq<'T>) (random : Random<'T>) : Gen<'T> = Gen.create shrink random - let Sized (scaler : Func<_, _>) : Gen<'T> = + let Sized (scaler : Func>) : Gen<'T> = Gen.sized scaler.Invoke - let inline Integral range : Gen<'T> = + let inline Integral (range : Range<'T>) : Gen<'T> = Gen.integral range - let Item sequence : Gen<'T> = + let Item (sequence : seq<'T>) : Gen<'T> = Gen.item sequence - let Frequency gens : Gen<'T> = + let Frequency (gens : seq>) : Gen<'T> = Gen.frequency gens - let Choice gens : Gen<'T> = + let Choice (gens : seq>) : Gen<'T> = Gen.choice gens - let ChoiceRecursive nonrecs recs = + let ChoiceRecursive (nonrecs : seq>) (recs : seq>) : Gen<'T> = Gen.choiceRec nonrecs recs - let Char lo hi = + let Char (lo : char) (hi : char) : Gen = Gen.char lo hi - let UnicodeAll = + let UnicodeAll : Gen = Gen.unicodeAll - let Digit = + let Digit : Gen = Gen.digit - let Lower = + let Lower : Gen = Gen.lower - let Upper = + let Upper : Gen = Gen.upper - let Ascii = + let Ascii : Gen = Gen.ascii - let Latin1 = + let Latin1 : Gen = Gen.latin1 - let Unicode = + let Unicode : Gen = Gen.unicode - let Alpha = + let Alpha : Gen = Gen.alpha - let AlphaNumeric = + let AlphaNumeric : Gen = Gen.alphaNum - let Bool = + let Bool : Gen = Gen.bool - let Byte range = + let Byte (range : Range) : Gen = Gen.byte range - let SByte range = + let SByte (range : Range) : Gen = Gen.sbyte range - let Int16 range = + let Int16 (range : Range) : Gen = Gen.int16 range - let UInt16 range = + let UInt16 (range : Range) : Gen = Gen.uint16 range - let Int32 range = + let Int32 (range : Range) : Gen = Gen.int range - let UInt32 range = + let UInt32 (range : Range) : Gen = Gen.uint32 range - let Int64 range = + let Int64 (range : Range) : Gen = Gen.int64 range - let UInt64 (range : Range) = + let UInt64 (range : Range) : Gen = Gen.uint64 range - let Double range = + let Double (range : Range) : Gen = Gen.double range - let Single (range : Range) = + let Single (range : Range) : Gen = Gen.float range - let Guid = + let Guid : Gen = Gen.guid - let DateTime = + let DateTime : Gen = Gen.dateTime [] type GenExtensions = [] - static member inline Apply(mf : Gen>) ma = + static member inline Apply(mf : Gen>, ma : Gen<'T>) : Gen<'TResult> = Gen.apply (mf |> Gen.map (fun f -> f.Invoke)) ma [] - static member inline Array(gen : Gen<'T>, range) = + static member inline Array(gen : Gen<'T>, range : Range) : Gen<'T []> = Gen.array range gen [] - static member inline Enumerable(gen : Gen<'T>, range) = + static member inline Enumerable(gen : Gen<'T>, range : Range) : Gen> = Gen.seq range gen [] - static member inline GenerateTree(gen : Gen<'T>) = + static member inline GenerateTree(gen : Gen<'T>) : Tree<'T> = Gen.generateTree gen [] - static member inline List(gen : Gen<'T>, range) = + static member inline List(gen : Gen<'T>, range : Range) : Gen> = Gen.list range gen [] - static member inline NoShrink gen : Gen<'T> = + static member inline NoShrink (gen : Gen<'T>) : Gen<'T> = Gen.noShrink gen [] - static member inline Option(gen : Gen<'T>) = + static member inline Option(gen : Gen<'T>) : Gen> = Gen.option gen [] - static member inline PrintSample(gen : Gen<'T>) = + static member inline PrintSample(gen : Gen<'T>) : unit = Gen.printSample gen [] - static member inline Resize(gen, size) : Gen<'T> = + static member inline Resize(gen : Gen<'T>, size : Size) : Gen<'T> = Gen.resize size gen [] - static member inline Sample(gen : Gen<'T>, size, count) = + static member inline Sample(gen : Gen<'T>, size : Size, count : int) : List<'T> = Gen.sample size count gen [] - static member inline SampleTree(gen : Gen<'T>, size, count) = + static member inline SampleTree(gen : Gen<'T>, size : Size, count : int) : List> = Gen.sampleTree size count gen [] - static member inline Scale(gen : Gen<'T>, scaler: Func<_, _>) = + static member inline Scale(gen : Gen<'T>, scaler : Func) : Gen<'T> = Gen.scale scaler.Invoke gen [] - static member inline SelectMany(gen : Gen<'T>, f: Func<_, _>) : Gen<'U> = - Gen.bind gen f.Invoke + static member inline SelectMany(gen : Gen<'T>, binder : Func<'T, Gen<'U>>) : Gen<'U> = + Gen.bind gen binder.Invoke [] - static member inline SelectMany(gen, f : Func<_, _>, proj : Func<'T, 'TCollection, 'TResult>) : Gen<'TResult> = + static member inline SelectMany(gen : Gen<'T>, binder : Func<'T, Gen<'TCollection>>, projection : Func<'T, 'TCollection, 'TResult>) : Gen<'TResult> = Gen.bind gen (fun a -> - Gen.map (fun b -> proj.Invoke(a, b)) (f.Invoke(a)) + Gen.map (fun b -> projection.Invoke(a, b)) (binder.Invoke(a)) ) [] - static member inline SelectRandom(gen : Gen<'T>, f: Func<_, _>) : Gen<'U> = - Gen.mapRandom f.Invoke gen + static member inline SelectRandom(gen : Gen<'T>, binder : Func>, Random>>) : Gen<'TResult> = + Gen.mapRandom binder.Invoke gen [] - static member inline SelectTree(gen : Gen<'T>, f: Func<_, _>) : Gen<'U> = - Gen.mapTree f.Invoke gen + static member inline SelectTree(gen : Gen<'T>, binder : Func, Tree<'TResult>>) : Gen<'TResult> = + Gen.mapTree binder.Invoke gen [] - static member inline Select(gen : Gen<'T>, f: Func<_, _>) : Gen<'U> = - Gen.map f.Invoke gen + static member inline Select(gen : Gen<'T>, mapper : Func<'T, 'TResult>) : Gen<'TResult> = + Gen.map mapper.Invoke gen [] - static member inline Select2(genA, f: Func<'T, 'U, 'TResult>, genB) = - Gen.map2 (fun a b -> f.Invoke(a, b)) + static member inline Select2(genA : Gen<'T>, mapper : Func<'T, 'U, 'TResult>, genB : Gen<'U>) : Gen<'TResult> = + Gen.map2 (fun a b -> mapper.Invoke(a, b)) genA genB [] - static member inline Select3(genA, f: Func<'T, 'U, 'V, 'TResult>, genB, genC) = - Gen.map3 (fun a b c -> f.Invoke(a, b, c)) + static member inline Select3(genA : Gen<'T>, mapper : Func<'T, 'U, 'V, 'TResult>, genB : Gen<'U>, genC : Gen<'V>) : Gen<'TResult> = + Gen.map3 (fun a b c -> mapper.Invoke(a, b, c)) genA genB genC [] - static member inline Select4(genA, f: Func<'T, 'U, 'V, 'W, 'TResult>, genB, genC, genD) = - Gen.map4 (fun a b c d -> f.Invoke(a, b, c, d)) + static member inline Select4(genA : Gen<'T>, mapper : Func<'T, 'U, 'V, 'W, 'TResult>, genB : Gen<'U>, genC : Gen<'V>, genD : Gen<'W>) : Gen<'TResult> = + Gen.map4 (fun a b c d -> mapper.Invoke(a, b, c, d)) genA genB genC genD [] - static member inline Shrink(gen : Gen<'T>, f: Func<_, _>) = - Gen.shrink f.Invoke gen + static member inline Shrink(gen : Gen<'T>, shrinker : Func<'T, List<'T>>) : Gen<'T> = + Gen.shrink shrinker.Invoke gen [] - static member inline ShrinkLazy(gen : Gen<'T>, f: Func<_, _>) = - Gen.shrinkLazy f.Invoke gen + static member inline ShrinkLazy(gen : Gen<'T>, shrinker : Func<'T, seq<'T>>) : Gen<'T> = + Gen.shrinkLazy shrinker.Invoke gen [] - static member inline Some(gen) : Gen<'T> = + static member inline Some(gen : Gen>) : Gen<'T> = Gen.some gen [] - static member inline String gen range = + static member inline String(gen : Gen, range : Range) : Gen = Gen.string range gen [] - static member inline ToGen(random) : Gen<'T> = + static member inline ToGen(random : Random>) : Gen<'T> = Gen.ofRandom random [] - static member inline ToRandom(gen : Gen<'T>) = + static member inline ToRandom(gen : Gen<'T>) : Random> = Gen.toRandom gen [] - static member inline TryFinally(gen : Gen<'T>, after: Action) = + static member inline TryFinally(gen : Gen<'T>, after : Action) : Gen<'T> = Gen.tryFinally gen after.Invoke [] - static member inline TryWhere(gen : Gen<'T>, after: Func<_, _>) = + static member inline TryWhere(gen : Gen<'T>, after : Func>) : Gen<'T> = Gen.tryWith gen after.Invoke [] - static member inline TryWith(gen : Gen<'T>, after: Func<_, _>) = + static member inline TryWith(gen : Gen<'T>, after : Func>) : Gen<'T> = Gen.tryWith gen after.Invoke [] - static member inline Tuple2(gen : Gen<'T>) = + static member inline Tuple2(gen : Gen<'T>) : Gen<'T * 'T> = Gen.tuple gen [] - static member inline Tuple3(gen : Gen<'T>) = + static member inline Tuple3(gen : Gen<'T>) : Gen<'T * 'T * 'T> = Gen.tuple3 gen [] - static member inline Tuple4(gen : Gen<'T>) = + static member inline Tuple4(gen : Gen<'T>) : Gen<'T * 'T * 'T * 'T> = Gen.tuple4 gen [] - static member inline Where(gen : Gen<'T>, predicate: Func<_, _>) = + static member inline Where(gen : Gen<'T>, predicate : Func<'T, bool>) : Gen<'T> = Gen.filter predicate.Invoke gen [] - static member inline Zip(genA, genB) : Gen<'T * 'U> = + static member inline Zip(genA : Gen<'T>, genB : Gen<'U>) : Gen<'T * 'U> = Gen.zip genA genB [] - static member inline Zip3(genA, genB, genC) : Gen<'T * 'U * 'V> = + static member inline Zip3(genA : Gen<'T>, genB : Gen<'U>, genC : Gen<'V>) : Gen<'T * 'U * 'V> = Gen.zip3 genA genB genC [] - static member inline Zip4(genA, genB, genC, genD) : Gen<'T * 'U * 'V * 'W> = + static member inline Zip4(genA : Gen<'T>, genB : Gen<'U>, genC : Gen<'V>, genD : Gen<'W>) : Gen<'T * 'U * 'V * 'W> = Gen.zip4 genA genB genC genD #endif diff --git a/src/Hedgehog/CSharp/Property.fs b/src/Hedgehog/CSharp/Property.fs index 9550def0..958d769e 100644 --- a/src/Hedgehog/CSharp/Property.fs +++ b/src/Hedgehog/CSharp/Property.fs @@ -10,24 +10,24 @@ open Hedgehog type PropertyExtensions = [] - static member inline Where(property, filter : Func<'T, _>) = + static member inline Where(property : Property<'T>, filter : Func<'T, bool>) : Property<'T> = Property.filter filter.Invoke property [] - static member inline Select(property, mapper : Func<'T, 'U>) = + static member inline Select(property : Property<'T>, mapper : Func<'T, 'TResult>) : Property<'TResult> = Property.map mapper.Invoke property [] - static member inline Select(property, mapper : Action<'T>) = + static member inline Select(property : Property<'T>, mapper : Action<'T>) : Property = Property.bind property (Property.fromThrowing mapper.Invoke) [] - static member inline SelectMany(property, binder : Func<_, _>, projection : Func<'T, 'TCollection, 'TResult>) = + static member inline SelectMany(property : Property<'T>, binder : Func<'T, Property<'TCollection>>, projection : Func<'T, 'TCollection, 'TResult>) : Property<'TResult> = Property.bind property (fun a -> - Property.map (fun b -> projection.Invoke (a, b)) (binder.Invoke(a))) + Property.map (fun b -> projection.Invoke(a, b)) (binder.Invoke(a))) [] - static member inline SelectMany(property, binder : Func<'T, Property<'U>>, projection : Action<_, _>) = + static member inline SelectMany(property : Property<'T>, binder : Func<'T, Property<'TCollection>>, projection : Action<'T, 'TCollection>) : Property = Property.bind property (fun a -> Property.bind (binder.Invoke a) (fun b -> Property.fromThrowing projection.Invoke (a, b))) diff --git a/src/Hedgehog/CSharp/Range.fs b/src/Hedgehog/CSharp/Range.fs index b7518eb9..aec3cea9 100644 --- a/src/Hedgehog/CSharp/Range.fs +++ b/src/Hedgehog/CSharp/Range.fs @@ -10,7 +10,7 @@ open Hedgehog type RangeExtensions = [] - static member inline Select(range, mapper : Func<'T, 'U>) = + static member inline Select(range : Range<'T>, mapper : Func<'T, 'TResult>) : Range<'TResult> = Range.map mapper.Invoke range #endif From 9a1907c2dcd1574b61b2d2fc24e9c5512315ddb0 Mon Sep 17 00:00:00 2001 From: Adam Becker Date: Wed, 16 Dec 2020 05:45:49 +0000 Subject: [PATCH 05/17] Complete layer for Range, Property, and Gen --- src/Hedgehog/CSharp/Gen.fs | 102 +++-- src/Hedgehog/CSharp/Property.fs | 102 ++++- src/Hedgehog/CSharp/Range.fs | 442 ++++++++++++++++++++- src/Hedgehog/Property.fs | 56 +-- src/Hedgehog/Range.fs | 477 ----------------------- tests/Hedgehog.CSharp.Tests/LinqTests.cs | 64 +-- tests/Hedgehog.CSharp.Tests/NameTests.cs | 5 +- 7 files changed, 652 insertions(+), 596 deletions(-) diff --git a/src/Hedgehog/CSharp/Gen.fs b/src/Hedgehog/CSharp/Gen.fs index f618d0f1..bc2edf18 100644 --- a/src/Hedgehog/CSharp/Gen.fs +++ b/src/Hedgehog/CSharp/Gen.fs @@ -6,110 +6,138 @@ open System open System.Runtime.CompilerServices open Hedgehog -module Gen = +[] +type Gen = - let FromValue (value : 'T) : Gen<'T> = + static member FromValue (value : 'T) : Gen<'T> = Gen.constant(value) - let FromRandom (random : Random>) : Gen<'T> = + static member FromRandom (random : Random>) : Gen<'T> = Gen.ofRandom(random) - let Delay (func : Func<_>) : Gen<'T> = + static member Delay (func : Func<_>) : Gen<'T> = Gen.delay func.Invoke - let Create (shrink : 'T -> seq<'T>) (random : Random<'T>) : Gen<'T> = + static member Create (shrink : 'T -> seq<'T>) (random : Random<'T>) : Gen<'T> = Gen.create shrink random - let Sized (scaler : Func>) : Gen<'T> = + static member Sized (scaler : Func>) : Gen<'T> = Gen.sized scaler.Invoke - let inline Integral (range : Range<'T>) : Gen<'T> = + static member IntegralByte (range : Range) : Gen = + Gen.integral range + + static member IntegralSByte (range : Range) : Gen = + Gen.integral range + + static member IntegralInt16 (range : Range) : Gen = + Gen.integral range + + static member IntegralUInt16 (range : Range) : Gen = + Gen.integral range + + static member IntegralInt32 (range : Range) : Gen = Gen.integral range - let Item (sequence : seq<'T>) : Gen<'T> = + static member IntegralUInt32 (range : Range) : Gen = + Gen.integral range + + static member IntegralInt64 (range : Range) : Gen = + Gen.integral range + + static member IntegralUInt64 (range : Range) : Gen = + Gen.integral range + + static member IntegralDouble (range : Range) : Gen = + Gen.integral range + + static member IntegralSingle (range : Range) : Gen = + Gen.integral range + + static member IntegralDecimal (range : Range) : Gen = + Gen.integral range + + static member Item (sequence : seq<'T>) : Gen<'T> = Gen.item sequence - let Frequency (gens : seq>) : Gen<'T> = + static member Frequency (gens : seq>) : Gen<'T> = Gen.frequency gens - let Choice (gens : seq>) : Gen<'T> = + static member Choice (gens : seq>) : Gen<'T> = Gen.choice gens - let ChoiceRecursive (nonrecs : seq>) (recs : seq>) : Gen<'T> = + static member ChoiceRecursive (nonrecs : seq>) (recs : seq>) : Gen<'T> = Gen.choiceRec nonrecs recs - let Char (lo : char) (hi : char) : Gen = + static member Char (lo : char) (hi : char) : Gen = Gen.char lo hi - let UnicodeAll : Gen = + static member UnicodeAll : Gen = Gen.unicodeAll - let Digit : Gen = + static member Digit : Gen = Gen.digit - let Lower : Gen = + static member Lower : Gen = Gen.lower - let Upper : Gen = + static member Upper : Gen = Gen.upper - let Ascii : Gen = + static member Ascii : Gen = Gen.ascii - let Latin1 : Gen = + static member Latin1 : Gen = Gen.latin1 - let Unicode : Gen = + static member Unicode : Gen = Gen.unicode - let Alpha : Gen = + static member Alpha : Gen = Gen.alpha - let AlphaNumeric : Gen = + static member AlphaNumeric : Gen = Gen.alphaNum - let Bool : Gen = + static member Bool : Gen = Gen.bool - let Byte (range : Range) : Gen = + static member Byte (range : Range) : Gen = Gen.byte range - let SByte (range : Range) : Gen = + static member SByte (range : Range) : Gen = Gen.sbyte range - let Int16 (range : Range) : Gen = + static member Int16 (range : Range) : Gen = Gen.int16 range - let UInt16 (range : Range) : Gen = + static member UInt16 (range : Range) : Gen = Gen.uint16 range - let Int32 (range : Range) : Gen = + static member Int32 (range : Range) : Gen = Gen.int range - let UInt32 (range : Range) : Gen = + static member UInt32 (range : Range) : Gen = Gen.uint32 range - let Int64 (range : Range) : Gen = + static member Int64 (range : Range) : Gen = Gen.int64 range - let UInt64 (range : Range) : Gen = + static member UInt64 (range : Range) : Gen = Gen.uint64 range - let Double (range : Range) : Gen = + static member Double (range : Range) : Gen = Gen.double range - let Single (range : Range) : Gen = + static member Single (range : Range) : Gen = Gen.float range - let Guid : Gen = + static member Guid : Gen = Gen.guid - let DateTime : Gen = + static member DateTime : Gen = Gen.dateTime -[] -type GenExtensions = - [] static member inline Apply(mf : Gen>, ma : Gen<'T>) : Gen<'TResult> = Gen.apply (mf |> Gen.map (fun f -> f.Invoke)) ma diff --git a/src/Hedgehog/CSharp/Property.fs b/src/Hedgehog/CSharp/Property.fs index 958d769e..3cc67a0a 100644 --- a/src/Hedgehog/CSharp/Property.fs +++ b/src/Hedgehog/CSharp/Property.fs @@ -7,7 +7,107 @@ open System.Runtime.CompilerServices open Hedgehog [] -type PropertyExtensions = +type Property = + + static member Failure : Property = + Property.failure + + static member Discard : Property = + Property.discard + + static member Success (value : 'T) : Property<'T> = + Property.Success(value) + + static member FromBool (value : bool) : Property = + Property.ofBool(value) + + static member FromGen (gen : Gen>) : Property<'T> = + Property.ofGen gen + + static member FromThrowing (f : Action<'T>) (arg : 'T) : Property = + Property.fromThrowing f.Invoke arg + + static member Delay (f : Func>) : Property<'T> = + Property.delay f.Invoke + + static member Using (resource : 'T) (action : Func<'T, Property<'TResult>>) : Property<'TResult> = + Property.using resource action.Invoke + + static member FromOutcome (result : Result<'T>) : Property<'T> = + Property.ofResult(result) + + static member CounterExample (message : Func) : Property = + Property.counterexample(message.Invoke) + + static member ForAll (gen : Gen<'T>, k : Func<'T, Property<'TResult>>) : Property<'TResult> = + Property.forAll gen k.Invoke + + static member ForAll (gen : Gen<'T>) : Property<'T> = + Property.forAll' gen + + [] + static member ToGen (property : Property<'T>) : Gen> = + Property.toGen property + + [] + static member TryFinally (property : Property<'T>) (onFinally : Action) : Property<'T> = + Property.tryFinally property onFinally.Invoke + + [] + static member TryWith (property : Property<'T>) (onError : Func>) : Property<'T> = + Property.tryWith property onError.Invoke + + // + // Runner + // + + [] + static member inline Report (property : Property) : Report = + Property.report property + + [] + static member inline Report (property : Property, tests : int) : Report = + Property.report' tests property + + [] + static member inline Check (property : Property) : unit = + Property.check property + + [] + static member Check (property : Property, tests : int) : unit = + Property.check' tests property + + [] + static member Check (property : Property) : unit = + Property.checkBool property + + [] + static member Check (property : Property, tests : int) : unit = + Property.checkBool' tests property + + [] + static member Recheck (property : Property, size : Size, seed : Seed) : unit = + Property.recheck size seed property + + [] + static member Recheck (property : Property, size : Size, seed : Seed, tests : int) : unit = + Property.recheck' size seed tests property + + [] + static member Recheck (property : Property, size : Size, seed : Seed) : unit = + Property.recheckBool size seed property + + [] + static member Recheck (property : Property, size : Size, seed : Seed, tests : int) : unit = + Property.recheckBool' size seed tests property + + [] + static member Print (property : Property, tests : int) : unit = + Property.print' tests property + + [] + static member Print (property : Property) : unit = + Property.print property [] static member inline Where(property : Property<'T>, filter : Func<'T, bool>) : Property<'T> = diff --git a/src/Hedgehog/CSharp/Range.fs b/src/Hedgehog/CSharp/Range.fs index aec3cea9..067efa83 100644 --- a/src/Hedgehog/CSharp/Range.fs +++ b/src/Hedgehog/CSharp/Range.fs @@ -7,10 +7,450 @@ open System.Runtime.CompilerServices open Hedgehog [] -type RangeExtensions = +type Range = + + // + // Combinators - Constant + // + + /// Construct a range which represents a constant single value. + static member FromValue (value : 'T) : Range<'T> = + Range.singleton value + + /// Construct a range which is unaffected by the size parameter with a + /// origin point which may differ from the bounds. + static member Constant (z : 'T, x : 'T, y : 'T) : Range<'T> = + Range.constantFrom z x y + + /// Construct a range which is unaffected by the size parameter. + static member Constant (x : 'T, y : 'T) : Range<'T> = + Range.constant x y + + /// Construct a range which is unaffected by the size parameter using the + /// full range of a data type. + static member ConstantBoundedInt8 : Range = + Range.constantBounded () + + /// Construct a range which is unaffected by the size parameter using the + /// full range of a data type. + static member ConstantBoundedInt16 : Range = + Range.constantBounded () + + /// Construct a range which is unaffected by the size parameter using the + /// full range of a data type. + static member ConstantBoundedInt32 : Range = + Range.constantBounded () + + /// Construct a range which is unaffected by the size parameter using the + /// full range of a data type. + static member ConstantBoundedInt64 : Range = + Range.constantBounded () + + /// Construct a range which is unaffected by the size parameter using the + /// full range of a data type. + static member ConstantBoundedUInt8 : Range = + Range.constantBounded () + + /// Construct a range which is unaffected by the size parameter using the + /// full range of a data type. + static member ConstantBoundedUInt16 : Range = + Range.constantBounded () + + /// Construct a range which is unaffected by the size parameter using the + /// full range of a data type. + static member ConstantBoundedUInt32 : Range = + Range.constantBounded () + + /// Construct a range which is unaffected by the size parameter using the + /// full range of a data type. + static member ConstantBoundedUInt64 : Range = + Range.constantBounded () + + /// Construct a range which is unaffected by the size parameter using the + /// full range of a data type. + static member ConstantBoundedSingle : Range = + Range.constantBounded () + + /// Construct a range which is unaffected by the size parameter using the + /// full range of a data type. + static member ConstantBoundedDouble : Range = + Range.constantBounded () + + /// Construct a range which is unaffected by the size parameter using the + /// full range of a data type. + static member ConstantBoundedDecimal : Range = + Range.constantBounded () + + // + // Combinators - Linear + // + + /// Construct a range which scales the bounds relative to the size + /// parameter. + static member LinearFromInt8 (z, x, y) : Range = + Range.linearFrom z x y + + /// Construct a range which scales the bounds relative to the size + /// parameter. + static member LinearFromInt16 (z, x, y) : Range = + Range.linearFrom z x y + + /// Construct a range which scales the bounds relative to the size + /// parameter. + static member LinearFromInt32 (z, x, y) : Range = + Range.linearFrom z x y + + /// Construct a range which scales the bounds relative to the size + /// parameter. + static member LinearFromInt64 (z, x, y) : Range = + Range.linearFrom z x y + + /// Construct a range which scales the bounds relative to the size + /// parameter. + static member LinearFromUInt8 (z, x, y) : Range = + Range.linearFrom z x y + + /// Construct a range which scales the bounds relative to the size + /// parameter. + static member LinearFromUInt16 (z, x, y) : Range = + Range.linearFrom z x y + + /// Construct a range which scales the bounds relative to the size + /// parameter. + static member LinearFromUInt32 (z, x, y) : Range = + Range.linearFrom z x y + + /// Construct a range which scales the bounds relative to the size + /// parameter. + static member LinearFromUInt64 (z, x, y) : Range = + Range.linearFrom z x y + + /// Construct a range which scales the bounds relative to the size + /// parameter. + static member LinearFromSingle (z, x, y) : Range = + Range.linearFrom z x y + + /// Construct a range which scales the bounds relative to the size + /// parameter. + static member LinearFromDouble (z, x, y) : Range = + Range.linearFrom z x y + + /// Construct a range which scales the bounds relative to the size + /// parameter. + static member LinearFromDecimal (z, x, y) : Range = + Range.linearFrom z x y + + /// Construct a range which scales the second bound relative to the size + /// parameter. + static member LinearInt8 (x, y) : Range = + Range.linear x y + + /// Construct a range which scales the second bound relative to the size + /// parameter. + static member LinearInt16 (x, y) : Range = + Range.linear x y + + /// Construct a range which scales the second bound relative to the size + /// parameter. + static member LinearInt32 (x, y) : Range = + Range.linear x y + + /// Construct a range which scales the second bound relative to the size + /// parameter. + static member LinearInt64 (x, y) : Range = + Range.linear x y + + /// Construct a range which scales the second bound relative to the size + /// parameter. + static member LinearUInt8 (x, y) : Range = + Range.linear x y + + /// Construct a range which scales the second bound relative to the size + /// parameter. + static member LinearUInt16 (x, y) : Range = + Range.linear x y + + /// Construct a range which scales the second bound relative to the size + /// parameter. + static member LinearUInt32 (x, y) : Range = + Range.linear x y + + /// Construct a range which scales the second bound relative to the size + /// parameter. + static member LinearUInt64 (x, y) : Range = + Range.linear x y + + /// Construct a range which scales the second bound relative to the size + /// parameter. + static member LinearSingle (x, y) : Range = + Range.linear x y + + /// Construct a range which scales the second bound relative to the size + /// parameter. + static member LinearDouble (z, x, y) : Range = + Range.linear x y + + /// Construct a range which scales the second bound relative to the size + /// parameter. + static member LinearDecimal (z, x, y) : Range = + Range.linear x y + + /// Construct a range which is scaled relative to the size parameter and + /// uses the full range of a data type. + static member LinearBoundedInt8 : Range = + Range.linearBounded () + + /// Construct a range which is scaled relative to the size parameter and + /// uses the full range of a data type. + static member LinearBoundedInt16 : Range = + Range.linearBounded () + + /// Construct a range which is scaled relative to the size parameter and + /// uses the full range of a data type. + static member LinearBoundedInt32 : Range = + Range.linearBounded () + + /// Construct a range which is scaled relative to the size parameter and + /// uses the full range of a data type. + static member LinearBoundedInt64 : Range = + Range.linearBounded () + + /// Construct a range which is scaled relative to the size parameter and + /// uses the full range of a data type. + static member LinearBoundedUInt8 : Range = + Range.linearBounded () + + /// Construct a range which is scaled relative to the size parameter and + /// uses the full range of a data type. + static member LinearBoundedUInt16 : Range = + Range.linearBounded () + + /// Construct a range which is scaled relative to the size parameter and + /// uses the full range of a data type. + static member LinearBoundedUInt32 : Range = + Range.linearBounded () + + /// Construct a range which is scaled relative to the size parameter and + /// uses the full range of a data type. + static member LinearBoundedUInt64 : Range = + Range.linearBounded () + + /// Construct a range which is scaled relative to the size parameter and + /// uses the full range of a data type. + static member LinearBoundedSingle : Range = + Range.linearBounded () + + /// Construct a range which is scaled relative to the size parameter and + /// uses the full range of a data type. + static member LinearBoundedDouble : Range = + Range.linearBounded () + + /// Construct a range which is scaled relative to the size parameter and + /// uses the full range of a data type. + static member LinearBoundedDecimal : Range = + Range.linearBounded () + + // + // Combinators - Exponential + // + + /// Construct a range which scales the bounds exponentially relative to the + /// size parameter. + static member ExponentialFromInt8 (z, x, y) : Range = + Range.exponentialFrom z x y + + /// Construct a range which scales the bounds exponentially relative to the + /// size parameter. + static member ExponentialFromInt16 (z, x, y) : Range = + Range.exponentialFrom z x y + + /// Construct a range which scales the bounds exponentially relative to the + /// size parameter. + static member ExponentialFromInt32 (z, x, y) : Range = + Range.exponentialFrom z x y + + /// Construct a range which scales the bounds exponentially relative to the + /// size parameter. + static member ExponentialFromInt64 (z, x, y) : Range = + Range.exponentialFrom z x y + + /// Construct a range which scales the bounds exponentially relative to the + /// size parameter. + static member ExponentialFromUInt8 (z, x, y) : Range = + Range.exponentialFrom z x y + + /// Construct a range which scales the bounds exponentially relative to the + /// size parameter. + static member ExponentialFromUInt16 (z, x, y) : Range = + Range.exponentialFrom z x y + + /// Construct a range which scales the bounds exponentially relative to the + /// size parameter. + static member ExponentialFromUInt32 (z, x, y) : Range = + Range.exponentialFrom z x y + + /// Construct a range which scales the bounds exponentially relative to the + /// size parameter. + static member ExponentialFromUInt64 (z, x, y) : Range = + Range.exponentialFrom z x y + + /// Construct a range which scales the bounds exponentially relative to the + /// size parameter. + static member ExponentialFromSingle (z, x, y) : Range = + Range.exponentialFrom z x y + + /// Construct a range which scales the bounds exponentially relative to the + /// size parameter. + static member ExponentialFromDouble (z, x, y) : Range = + Range.exponentialFrom z x y + + /// Construct a range which scales the bounds exponentially relative to the + /// size parameter. + static member ExponentialFromDecimal (z, x, y) : Range = + Range.exponentialFrom z x y + + /// Construct a range which scales the second bound exponentially relative + /// to the size parameter. + static member ExponentialInt8 (x, y) : Range = + Range.exponential x y + + /// Construct a range which scales the second bound exponentially relative + /// to the size parameter. + static member ExponentialInt16 (x, y) : Range = + Range.exponential x y + + /// Construct a range which scales the second bound exponentially relative + /// to the size parameter. + static member ExponentialInt32 (x, y) : Range = + Range.exponential x y + + /// Construct a range which scales the second bound exponentially relative + /// to the size parameter. + static member ExponentialInt64 (x, y) : Range = + Range.exponential x y + + /// Construct a range which scales the second bound exponentially relative + /// to the size parameter. + static member ExponentialUInt8 (x, y) : Range = + Range.exponential x y + + /// Construct a range which scales the second bound exponentially relative + /// to the size parameter. + static member ExponentialUInt16 (x, y) : Range = + Range.exponential x y + + /// Construct a range which scales the second bound exponentially relative + /// to the size parameter. + static member ExponentialUInt32 (x, y) : Range = + Range.exponential x y + + /// Construct a range which scales the second bound exponentially relative + /// to the size parameter. + static member ExponentialUInt64 (x, y) : Range = + Range.exponential x y + + /// Construct a range which scales the second bound exponentially relative + /// to the size parameter. + static member ExponentialSingle (x, y) : Range = + Range.exponential x y + + /// Construct a range which scales the second bound exponentially relative + /// to the size parameter. + static member ExponentialDouble (x, y) : Range = + Range.exponential x y + + /// Construct a range which scales the second bound exponentially relative + /// to the size parameter. + static member ExponentialDecimal (x, y) : Range = + Range.exponential x y + + /// Construct a range which is scaled exponentially relative to the size + /// parameter and uses the full range of a data type. + static member ExponentialBoundedInt8 : Range = + Range.exponentialBounded () + + /// Construct a range which is scaled exponentially relative to the size + /// parameter and uses the full range of a data type. + static member ExponentialBoundedInt16 : Range = + Range.exponentialBounded () + + /// Construct a range which is scaled exponentially relative to the size + /// parameter and uses the full range of a data type. + static member ExponentialBoundedInt32 : Range = + Range.exponentialBounded () + + /// Construct a range which is scaled exponentially relative to the size + /// parameter and uses the full range of a data type. + static member ExponentialBoundedInt64 : Range = + Range.exponentialBounded () + + /// Construct a range which is scaled exponentially relative to the size + /// parameter and uses the full range of a data type. + static member ExponentialBoundedUInt8 : Range = + Range.exponentialBounded () + + /// Construct a range which is scaled exponentially relative to the size + /// parameter and uses the full range of a data type. + static member ExponentialBoundedUInt16 : Range = + Range.exponentialBounded () + + /// Construct a range which is scaled exponentially relative to the size + /// parameter and uses the full range of a data type. + static member ExponentialBoundedUInt32 : Range = + Range.exponentialBounded () + + /// Construct a range which is scaled exponentially relative to the size + /// parameter and uses the full range of a data type. + static member ExponentialBoundedUInt64 : Range = + Range.exponentialBounded () + + /// Construct a range which is scaled exponentially relative to the size + /// parameter and uses the full range of a data type. + static member ExponentialBoundedSingle : Range = + Range.exponentialBounded () + + /// Construct a range which is scaled exponentially relative to the size + /// parameter and uses the full range of a data type. + static member ExponentialBoundedDouble : Range = + Range.exponentialBounded () + + /// Construct a range which is scaled exponentially relative to the size + /// parameter and uses the full range of a data type. + static member ExponentialBoundedDecimal : Range = + Range.exponentialBounded () [] static member inline Select(range : Range<'T>, mapper : Func<'T, 'TResult>) : Range<'TResult> = Range.map mapper.Invoke range + // + // Combinators - Range + // + + /// Get the origin of a range. This might be the mid-point or the lower + /// bound, depending on what the range represents. + /// + /// The 'bounds' of a range are scaled around this value when using the + /// 'linear' family of combinators. + /// + /// When using a 'Range' to generate numbers, the shrinking function will + /// shrink towards the origin. + [] + static member inline Origin (range : Range<'T>) : 'T = + Range.origin range + + /// Get the extents of a range, for a given size. + [] + static member inline Bounds (range : Range<'T>) (sz : Size) : 'T * 'T = + Range.bounds sz range + + /// Get the lower bound of a range for the given size. + [] + static member inline LowerBound (range : Range<'T>) (sz : Size) : 'T = + Range.lowerBound sz range + + /// Get the upper bound of a range for the given size. + static member inline UpperBound (range : Range<'T>) (sz : Size) : 'T = + Range.upperBound sz range + #endif diff --git a/src/Hedgehog/Property.fs b/src/Hedgehog/Property.fs index 2c7cc3c5..c95d3591 100644 --- a/src/Hedgehog/Property.fs +++ b/src/Hedgehog/Property.fs @@ -214,27 +214,21 @@ module Report = module Property = - [] let ofGen (x : Gen>) : Property<'a> = Property x - [] let toGen (Property x : Property<'a>) : Gen> = x - [] let tryFinally (m : Property<'a>) (after : unit -> unit) : Property<'a> = - Gen.tryFinally (toGen m) after |> ofGen + Gen.tryFinally (toGen m) after |> ofGen - [] let tryWith (m : Property<'a>) (k : exn -> Property<'a>) : Property<'a> = Gen.tryWith (toGen m) (toGen << k) |> ofGen - [] let delay (f : unit -> Property<'a>) : Property<'a> = Gen.delay (toGen << f) |> ofGen - [] let using (x : 'a) (k : 'a -> Property<'b>) : Property<'b> when 'a :> IDisposable and 'a : null = @@ -246,34 +240,27 @@ module Property = | _ -> x.Dispose () - [] let filter (p : 'a -> bool) (m : Property<'a>) : Property<'a> = Gen.map (second <| Result.filter p) (toGen m) |> ofGen - [] let ofResult (x : Result<'a>) : Property<'a> = (Journal.empty, x) |> Gen.constant |> ofGen - [] let failure : Property = Failure |> ofResult - [] let discard : Property = Discard |> ofResult - [] let success (x : 'a) : Property<'a> = Success x |> ofResult - [] let ofBool (x : bool) : Property = if x then success () else failure - [] let counterexample (msg : unit -> string) : Property = Gen.constant (Journal.delayedSingleton msg, Success ()) |> ofGen @@ -282,7 +269,6 @@ module Property = (x : Property<'a>) : Property<'b> = toGen x |> f |> ofGen - [] let map (f : 'a -> 'b) (x : Property<'a>) : Property<'b> = (mapGen << Gen.map << second << Result.map) f x @@ -298,11 +284,9 @@ module Property = | Success x -> Gen.map (first (Journal.append journal)) (k x) - [] let bind (m : Property<'a>) (k : 'a -> Property<'b>) : Property<'b> = bindGen (toGen m) (toGen << k) |> ofGen - [] let forAll (gen : Gen<'a>) (k : 'a -> Property<'b>) : Property<'b> = let handle (e : exn) = Gen.constant (Journal.singleton (string e), Failure) |> ofGen @@ -310,9 +294,6 @@ module Property = bind (counterexample (fun () -> sprintf "%A" x)) (fun _ -> try k x with e -> handle e) |> toGen Gen.bind gen prepend |> ofGen -#if !FABLE_COMPILER - [] -#endif let forAll' (gen : Gen<'a>) : Property<'a> = forAll gen success @@ -375,48 +356,29 @@ module Property = let private reportWith (renderRecheck : bool) (size : Size) (seed : Seed) (p : Property) : Report = reportWith' renderRecheck size seed 100 p -#if !FABLE_COMPILER - [] -#endif let report' (n : int) (p : Property) : Report = let seed = Seed.random () reportWith' true 1 seed n p - [] let report (p : Property) : Report = report' 100 p -#if !FABLE_COMPILER - [] -#endif let check' (n : int) (p : Property) : unit = report' n p |> Report.tryRaise - [] let check (p : Property) : unit = report p |> Report.tryRaise - // Overload for ease-of-use from C# -#if !FABLE_COMPILER - [] -#endif let checkBool (g : Property) : unit = bind g ofBool |> check - // Overload for ease-of-use from C# -#if !FABLE_COMPILER - [] -#endif let checkBool' (n : int) (g : Property) : unit = bind g ofBool |> check' n /// Converts a possibly-throwing function to /// a property by treating "no exception" as success. -#if !FABLE_COMPILER - [] -#endif let fromThrowing (f : 'a -> unit) (x : 'a) : Property = try f x @@ -424,41 +386,25 @@ module Property = with | _ -> failure -#if !FABLE_COMPILER - [] -#endif let recheck' (size : Size) (seed : Seed) (n : int) (p : Property) : unit = reportWith' false size seed n p |> Report.tryRaise -#if !FABLE_COMPILER - [] -#endif let recheck (size : Size) (seed : Seed) (p : Property) : unit = reportWith false size seed p |> Report.tryRaise -#if !FABLE_COMPILER - [] -#endif let recheckBool' (size : Size) (seed : Seed) (n : int) (g : Property) : unit = bind g ofBool |> recheck' size seed n -#if !FABLE_COMPILER - [] -#endif let recheckBool (size : Size) (seed : Seed) (g : Property) : unit = bind g ofBool |> recheck size seed -#if !FABLE_COMPILER - [] -#endif let print' (n : int) (p : Property) : unit = report' n p |> Report.render |> printfn "%s" - [] let print (p : Property) : unit = report p |> Report.render diff --git a/src/Hedgehog/Range.fs b/src/Hedgehog/Range.fs index d6a78b19..9af57fba 100644 --- a/src/Hedgehog/Range.fs +++ b/src/Hedgehog/Range.fs @@ -20,7 +20,6 @@ module Range = let private bimap (f : 'a -> 'b) (g : 'c -> 'd) (a : 'a, b : 'c) : 'b * 'd = f a, g b - [] let map (f : 'a -> 'b) (Range (z, g) : Range<'a>) : Range<'b> = Range (f z, fun sz -> bimap f f (g sz)) @@ -37,24 +36,20 @@ module Range = /// /// When using a 'Range' to generate numbers, the shrinking function will /// shrink towards the origin. - [] let origin (Range (z, _) : Range<'a>) : 'a = z /// Get the extents of a range, for a given size. - [] let bounds (sz : Size) (Range (_, f) : Range<'a>) : 'a * 'a = f sz /// Get the lower bound of a range for the given size. - [] let lowerBound (sz : Size) (range : Range<'a>) : 'a = let (x, y) = bounds sz range min x y /// Get the upper bound of a range for the given size. - [] let upperBound (sz : Size) (range : Range<'a>) : 'a = let (x, y) = bounds sz range @@ -65,24 +60,20 @@ module Range = // /// Construct a range which represents a constant single value. - [] let singleton (x : 'a) : Range<'a> = Range (x, fun _ -> x, x) /// Construct a range which is unaffected by the size parameter with a /// origin point which may differ from the bounds. - [] let constantFrom (z : 'a) (x : 'a) (y : 'a) : Range<'a> = Range (z, fun _ -> x, y) /// Construct a range which is unaffected by the size parameter. - [] let constant (x : 'a) (y : 'a) : Range<'a> = constantFrom x x y /// Construct a range which is unaffected by the size parameter using the /// full range of a data type. - [] let inline constantBounded () : Range<'a> = let lo = minValue () let hi = maxValue () @@ -90,72 +81,6 @@ module Range = constantFrom zero lo hi - /// Construct a range which is unaffected by the size parameter using the - /// full range of a data type. - [] - let __constantBoundedInt8 : Range = - constantBounded () - - /// Construct a range which is unaffected by the size parameter using the - /// full range of a data type. - [] - let __constantBoundedInt16 : Range = - constantBounded () - - /// Construct a range which is unaffected by the size parameter using the - /// full range of a data type. - [] - let __constantBoundedInt32 : Range = - constantBounded () - - /// Construct a range which is unaffected by the size parameter using the - /// full range of a data type. - [] - let __constantBoundedInt64 : Range = - constantBounded () - - /// Construct a range which is unaffected by the size parameter using the - /// full range of a data type. - [] - let __constantBoundedUInt8 : Range = - constantBounded () - - /// Construct a range which is unaffected by the size parameter using the - /// full range of a data type. - [] - let __constantBoundedUInt16 : Range = - constantBounded () - - /// Construct a range which is unaffected by the size parameter using the - /// full range of a data type. - [] - let __constantBoundedUInt32 : Range = - constantBounded () - - /// Construct a range which is unaffected by the size parameter using the - /// full range of a data type. - [] - let __constantBoundedUInt64 : Range = - constantBounded () - - /// Construct a range which is unaffected by the size parameter using the - /// full range of a data type. - [] - let __constantBoundedFloat : Range = - constantBounded () - - /// Construct a range which is unaffected by the size parameter using the - /// full range of a data type. - [] - let __constantBoundedDouble : Range = - constantBounded () - - /// Construct a range which is unaffected by the size parameter using the - /// full range of a data type. - [] - let __constantBoundedDecimal : Range = - constantBounded () - // // Combinators - Linear // @@ -211,7 +136,6 @@ module Range = /// Construct a range which scales the bounds relative to the size /// parameter. - [] let inline linearFrom (z : 'a) (x : 'a) (y : 'a) : Range<'a> = Range (z, fun sz -> let x_sized = @@ -220,147 +144,13 @@ module Range = clamp x y (scaleLinear sz z y) x_sized, y_sized) - /// Construct a range which scales the bounds relative to the size - /// parameter. - [] - let __linearFromInt8 (z, x, y) : Range = - linearFrom z x y - - /// Construct a range which scales the bounds relative to the size - /// parameter. - [] - let __linearFromInt16 (z, x, y) : Range = - linearFrom z x y - - /// Construct a range which scales the bounds relative to the size - /// parameter. - [] - let __linearFromInt32 (z, x, y) : Range = - linearFrom z x y - - /// Construct a range which scales the bounds relative to the size - /// parameter. - [] - let __linearFromInt64 (z, x, y) : Range = - linearFrom z x y - - /// Construct a range which scales the bounds relative to the size - /// parameter. - [] - let __linearFromUInt8 (z, x, y) : Range = - linearFrom z x y - - /// Construct a range which scales the bounds relative to the size - /// parameter. - [] - let __linearFromUInt16 (z, x, y) : Range = - linearFrom z x y - - /// Construct a range which scales the bounds relative to the size - /// parameter. - [] - let __linearFromUInt32 (z, x, y) : Range = - linearFrom z x y - - /// Construct a range which scales the bounds relative to the size - /// parameter. - [] - let __linearFromUInt64 (z, x, y) : Range = - linearFrom z x y - - /// Construct a range which scales the bounds relative to the size - /// parameter. - [] - let __linearFromFloat (z, x, y) : Range = - linearFrom z x y - - /// Construct a range which scales the bounds relative to the size - /// parameter. - [] - let __linearFromDouble (z, x, y) : Range = - linearFrom z x y - - /// Construct a range which scales the bounds relative to the size - /// parameter. - [] - let __linearFromDecimal (z, x, y) : Range = - linearFrom z x y - /// Construct a range which scales the second bound relative to the size /// parameter. - [] let inline linear (x : 'a) (y : 'a) : Range<'a> = linearFrom x x y - /// Construct a range which scales the second bound relative to the size - /// parameter. - [] - let __linearInt8 (x, y) : Range = - linear x y - - /// Construct a range which scales the second bound relative to the size - /// parameter. - [] - let __linearInt16 (x, y) : Range = - linear x y - - /// Construct a range which scales the second bound relative to the size - /// parameter. - [] - let __linearInt32 (x, y) : Range = - linear x y - - /// Construct a range which scales the second bound relative to the size - /// parameter. - [] - let __linearInt64 (x, y) : Range = - linear x y - - /// Construct a range which scales the second bound relative to the size - /// parameter. - [] - let __linearUInt8 (x, y) : Range = - linear x y - - /// Construct a range which scales the second bound relative to the size - /// parameter. - [] - let __linearUInt16 (x, y) : Range = - linear x y - - /// Construct a range which scales the second bound relative to the size - /// parameter. - [] - let __linearUInt32 (x, y) : Range = - linear x y - - /// Construct a range which scales the second bound relative to the size - /// parameter. - [] - let __linearUInt64 (x, y) : Range = - linear x y - - /// Construct a range which scales the second bound relative to the size - /// parameter. - [] - let __linearFloat (x, y) : Range = - linear x y - - /// Construct a range which scales the second bound relative to the size - /// parameter. - [] - let __linearDouble (z, x, y) : Range = - linear x y - - /// Construct a range which scales the second bound relative to the size - /// parameter. - [] - let __linearDecimal (z, x, y) : Range = - linear x y - /// Construct a range which is scaled relative to the size parameter and /// uses the full range of a data type. - [] let inline linearBounded () : Range<'a> = let lo = minValue () let hi = maxValue () @@ -368,79 +158,12 @@ module Range = linearFrom zero lo hi - /// Construct a range which is scaled relative to the size parameter and - /// uses the full range of a data type. - [] - let __linearBoundedInt8 : Range = - linearBounded () - - /// Construct a range which is scaled relative to the size parameter and - /// uses the full range of a data type. - [] - let __linearBoundedInt16 : Range = - linearBounded () - - /// Construct a range which is scaled relative to the size parameter and - /// uses the full range of a data type. - [] - let __linearBoundedInt32 : Range = - linearBounded () - - /// Construct a range which is scaled relative to the size parameter and - /// uses the full range of a data type. - [] - let __linearBoundedInt64 : Range = - linearBounded () - - /// Construct a range which is scaled relative to the size parameter and - /// uses the full range of a data type. - [] - let __linearBoundedUInt8 : Range = - linearBounded () - - /// Construct a range which is scaled relative to the size parameter and - /// uses the full range of a data type. - [] - let __linearBoundedUInt16 : Range = - linearBounded () - - /// Construct a range which is scaled relative to the size parameter and - /// uses the full range of a data type. - [] - let __linearBoundedUInt32 : Range = - linearBounded () - - /// Construct a range which is scaled relative to the size parameter and - /// uses the full range of a data type. - [] - let __linearBoundedUInt64 : Range = - linearBounded () - - /// Construct a range which is scaled relative to the size parameter and - /// uses the full range of a data type. - [] - let __linearBoundedFloat : Range = - linearBounded () - - /// Construct a range which is scaled relative to the size parameter and - /// uses the full range of a data type. - [] - let __linearBoundedDouble : Range = - linearBounded () - - /// Construct a range which is scaled relative to the size parameter and - /// uses the full range of a data type. - [] - let __linearBoundedDecimal : Range = - linearBounded () - // // Combinators - Exponential // /// Construct a range which scales the bounds exponentially relative to the /// size parameter. - [] let inline exponentialFrom (z : 'a) (x : 'a) (y : 'a) : Range<'a> = Range (z, fun sz -> let scale = @@ -452,216 +175,16 @@ module Range = scale y x_sized, y_sized) - /// Construct a range which scales the bounds exponentially relative to the - /// size parameter. - [] - let __exponentialFromInt8 (z, x, y) : Range = - exponentialFrom z x y - - /// Construct a range which scales the bounds exponentially relative to the - /// size parameter. - [] - let __exponentialFromInt16 (z, x, y) : Range = - exponentialFrom z x y - - /// Construct a range which scales the bounds exponentially relative to the - /// size parameter. - [] - let __exponentialFromInt32 (z, x, y) : Range = - exponentialFrom z x y - - /// Construct a range which scales the bounds exponentially relative to the - /// size parameter. - [] - let __exponentialFromInt64 (z, x, y) : Range = - exponentialFrom z x y - - /// Construct a range which scales the bounds exponentially relative to the - /// size parameter. - [] - let __exponentialFromUInt8 (z, x, y) : Range = - exponentialFrom z x y - - /// Construct a range which scales the bounds exponentially relative to the - /// size parameter. - [] - let __exponentialFromUInt16 (z, x, y) : Range = - exponentialFrom z x y - - /// Construct a range which scales the bounds exponentially relative to the - /// size parameter. - [] - let __exponentialFromUInt32 (z, x, y) : Range = - exponentialFrom z x y - - /// Construct a range which scales the bounds exponentially relative to the - /// size parameter. - [] - let __exponentialFromUInt64 (z, x, y) : Range = - exponentialFrom z x y - - /// Construct a range which scales the bounds exponentially relative to the - /// size parameter. - [] - let __exponentialFromFloat (z, x, y) : Range = - exponentialFrom z x y - - /// Construct a range which scales the bounds exponentially relative to the - /// size parameter. - [] - let __exponentialFromDouble (z, x, y) : Range = - exponentialFrom z x y - - /// Construct a range which scales the bounds exponentially relative to the - /// size parameter. - [] - let __exponentialFromDecimal (z, x, y) : Range = - exponentialFrom z x y - /// Construct a range which scales the second bound exponentially relative /// to the size parameter. - [] let inline exponential (x : 'a) (y : 'a) : Range<'a> = exponentialFrom x x y - /// Construct a range which scales the second bound exponentially relative - /// to the size parameter. - [] - let __exponentialInt8 (x, y) : Range = - exponential x y - - /// Construct a range which scales the second bound exponentially relative - /// to the size parameter. - [] - let __exponentialInt16 (x, y) : Range = - exponential x y - - /// Construct a range which scales the second bound exponentially relative - /// to the size parameter. - [] - let __exponentialInt32 (x, y) : Range = - exponential x y - - /// Construct a range which scales the second bound exponentially relative - /// to the size parameter. - [] - let __exponentialInt64 (x, y) : Range = - exponential x y - - /// Construct a range which scales the second bound exponentially relative - /// to the size parameter. - [] - let __exponentialUInt8 (x, y) : Range = - exponential x y - - /// Construct a range which scales the second bound exponentially relative - /// to the size parameter. - [] - let __exponentialUInt16 (x, y) : Range = - exponential x y - - /// Construct a range which scales the second bound exponentially relative - /// to the size parameter. - [] - let __exponentialUInt32 (x, y) : Range = - exponential x y - - /// Construct a range which scales the second bound exponentially relative - /// to the size parameter. - [] - let __exponentialUInt64 (x, y) : Range = - exponential x y - - /// Construct a range which scales the second bound exponentially relative - /// to the size parameter. - [] - let __exponentialFloat (x, y) : Range = - exponential x y - - /// Construct a range which scales the second bound exponentially relative - /// to the size parameter. - [] - let __exponentialDouble (x, y) : Range = - exponential x y - - /// Construct a range which scales the second bound exponentially relative - /// to the size parameter. - [] - let __exponentialDecimal (x, y) : Range = - exponential x y - /// Construct a range which is scaled exponentially relative to the size /// parameter and uses the full range of a data type. - [] let inline exponentialBounded () : Range<'a> = let lo = minValue () let hi = maxValue () let zero = LanguagePrimitives.GenericZero exponentialFrom zero lo hi - - /// Construct a range which is scaled exponentially relative to the size - /// parameter and uses the full range of a data type. - [] - let __exponentialBoundedInt8 : Range = - exponentialBounded () - - /// Construct a range which is scaled exponentially relative to the size - /// parameter and uses the full range of a data type. - [] - let __exponentialBoundedInt16 : Range = - exponentialBounded () - - /// Construct a range which is scaled exponentially relative to the size - /// parameter and uses the full range of a data type. - [] - let __exponentialBoundedInt32 : Range = - exponentialBounded () - - /// Construct a range which is scaled exponentially relative to the size - /// parameter and uses the full range of a data type. - [] - let __exponentialBoundedInt64 : Range = - exponentialBounded () - - /// Construct a range which is scaled exponentially relative to the size - /// parameter and uses the full range of a data type. - [] - let __exponentialBoundedUInt8 : Range = - exponentialBounded () - - /// Construct a range which is scaled exponentially relative to the size - /// parameter and uses the full range of a data type. - [] - let __exponentialBoundedUInt16 : Range = - exponentialBounded () - - /// Construct a range which is scaled exponentially relative to the size - /// parameter and uses the full range of a data type. - [] - let __exponentialBoundedUInt32 : Range = - exponentialBounded () - - /// Construct a range which is scaled exponentially relative to the size - /// parameter and uses the full range of a data type. - [] - let __exponentialBoundedUInt64 : Range = - exponentialBounded () - - /// Construct a range which is scaled exponentially relative to the size - /// parameter and uses the full range of a data type. - [] - let __exponentialBoundedFloat : Range = - exponentialBounded () - - /// Construct a range which is scaled exponentially relative to the size - /// parameter and uses the full range of a data type. - [] - let __exponentialBoundedDouble : Range = - exponentialBounded () - - /// Construct a range which is scaled exponentially relative to the size - /// parameter and uses the full range of a data type. - [] - let __exponentialBoundedDecimal : Range = - exponentialBounded () diff --git a/tests/Hedgehog.CSharp.Tests/LinqTests.cs b/tests/Hedgehog.CSharp.Tests/LinqTests.cs index 7aa22293..94c8bd70 100644 --- a/tests/Hedgehog.CSharp.Tests/LinqTests.cs +++ b/tests/Hedgehog.CSharp.Tests/LinqTests.cs @@ -1,8 +1,8 @@ using Xunit; -// Import Check and ForAll: -using static Hedgehog.Property; +// Import ForAll: using Hedgehog.CSharp; +using static Hedgehog.CSharp.Property; namespace Hedgehog.CSharp.Tests { @@ -15,95 +15,115 @@ public class LinqTests [Fact] public void CanUseSelectWithAssertion() { - Check( + var property = from x in ForAll(Gen.Bool) - select Assert.True(x || !x)); + select Assert.True(x || !x); + + property.Check(); } [Fact] public void CanUseSelectWithBool() { - Check( + var property = from x in ForAll(Gen.Bool) - select x || !x); + select x || !x; + + property.Check(); } [Fact] public void CanSelectFromTwoWithAssertion() { - Check( + var property = from x in ForAll(Gen.Bool) from y in ForAll(Gen.Bool) - select Assert.True((x || !x) && (y || !y))); + select Assert.True((x || !x) && (y || !y)); + + property.Check(); } [Fact] public void CanSelectFromTwoWithBool() { - Check( + var property = from x in ForAll(Gen.Bool) from y in ForAll(Gen.Bool) - select (x || !x) && (y || !y)); + select (x || !x) && (y || !y); + + property.Check(); } [Fact] public void CanSelectFromThreeWithAssertion() { - Check( + var property = from x in ForAll(Gen.Bool) from y in ForAll(Gen.Bool) from z in ForAll(Gen.Bool) - select Assert.True(x || y || z || (!x || !y || !z))); + select Assert.True(x || y || z || (!x || !y || !z)); + + property.Check(); } [Fact] public void CanSelectFromThreeWithBool() { - Check( + var property = from x in ForAll(Gen.Bool) from y in ForAll(Gen.Bool) from z in ForAll(Gen.Bool) - select x || y || z || (!x || !y || !z)); + select x || y || z || (!x || !y || !z); + + property.Check(); } [Fact] public void CanUseWhereWithAssertion() { - Check(20, + var property = from x in ForAll(Gen.Bool) where x == true from y in ForAll(Gen.Bool) where y == false - select Assert.True(x && !y)); + select Assert.True(x && !y); + + property.Check(20); } [Fact] public void CanUseWhereWithBool() { - Check(20, + var property = from x in ForAll(Gen.Bool) where x == true from y in ForAll(Gen.Bool) where y == false - select x && !y); + select x && !y; + + property.Check(20); } [Fact] public void CanDependOnEarlierValuesWithAssertion() { - Check( + var property = from i in ForAll(Gen.Int32(Range.Constant(1, 10))) from j in ForAll(Gen.Int32(Range.Constant(1, i))) - select Assert.True(j <= i)); + select Assert.True(j <= i); + + property.Check(); } [Fact] public void CanDependOnEarlierValuesWithBool() { - Check( + var property = from i in ForAll(Gen.Int32(Range.Constant(1, 10))) from j in ForAll(Gen.Int32(Range.Constant(1, i))) - select j <= i); + select j <= i; + + property.Check(); } [Fact] diff --git a/tests/Hedgehog.CSharp.Tests/NameTests.cs b/tests/Hedgehog.CSharp.Tests/NameTests.cs index d4da067c..9f11e350 100644 --- a/tests/Hedgehog.CSharp.Tests/NameTests.cs +++ b/tests/Hedgehog.CSharp.Tests/NameTests.cs @@ -10,9 +10,8 @@ public class NameTests { private static Type[] _publicApiTypes = { typeof(Hedgehog.CSharp.Gen) - , typeof(Hedgehog.CSharp.GenExtensions) - , typeof(Range) - , typeof(Property) + , typeof(Hedgehog.CSharp.Range) + , typeof(Hedgehog.CSharp.Property) }; public static IEnumerable AllPublicMembers() From 78e04686be10e5c524ad954a043a4bada3b5d972 Mon Sep 17 00:00:00 2001 From: Adam Becker Date: Wed, 16 Dec 2020 06:03:36 +0000 Subject: [PATCH 06/17] Missed a function. --- src/Hedgehog/CSharp/Gen.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Hedgehog/CSharp/Gen.fs b/src/Hedgehog/CSharp/Gen.fs index bc2edf18..6cef97ee 100644 --- a/src/Hedgehog/CSharp/Gen.fs +++ b/src/Hedgehog/CSharp/Gen.fs @@ -18,8 +18,8 @@ type Gen = static member Delay (func : Func<_>) : Gen<'T> = Gen.delay func.Invoke - static member Create (shrink : 'T -> seq<'T>) (random : Random<'T>) : Gen<'T> = - Gen.create shrink random + static member Create (shrink : Func<'T, seq<'T>>) (random : Random<'T>) : Gen<'T> = + Gen.create shrink.Invoke random static member Sized (scaler : Func>) : Gen<'T> = Gen.sized scaler.Invoke From 7070f31c5f525d322b35ec8a5466549f06deff21 Mon Sep 17 00:00:00 2001 From: Adam Becker Date: Tue, 5 Jan 2021 22:16:18 +0000 Subject: [PATCH 07/17] Fix minor indentation issue --- src/Hedgehog/Property.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Hedgehog/Property.fs b/src/Hedgehog/Property.fs index c95d3591..28e200c7 100644 --- a/src/Hedgehog/Property.fs +++ b/src/Hedgehog/Property.fs @@ -221,7 +221,7 @@ module Property = x let tryFinally (m : Property<'a>) (after : unit -> unit) : Property<'a> = - Gen.tryFinally (toGen m) after |> ofGen + Gen.tryFinally (toGen m) after |> ofGen let tryWith (m : Property<'a>) (k : exn -> Property<'a>) : Property<'a> = Gen.tryWith (toGen m) (toGen << k) |> ofGen From 2c99952d21335e87ea07a14f803105aa104060ef Mon Sep 17 00:00:00 2001 From: Adam Becker Date: Tue, 5 Jan 2021 22:47:17 +0000 Subject: [PATCH 08/17] Consistency changes. --- src/Hedgehog/CSharp/Gen.fs | 111 ++++++++++++++++---------------- src/Hedgehog/CSharp/Property.fs | 20 +++--- src/Hedgehog/CSharp/Range.fs | 8 +-- 3 files changed, 69 insertions(+), 70 deletions(-) diff --git a/src/Hedgehog/CSharp/Gen.fs b/src/Hedgehog/CSharp/Gen.fs index 6cef97ee..becbdf61 100644 --- a/src/Hedgehog/CSharp/Gen.fs +++ b/src/Hedgehog/CSharp/Gen.fs @@ -18,43 +18,40 @@ type Gen = static member Delay (func : Func<_>) : Gen<'T> = Gen.delay func.Invoke - static member Create (shrink : Func<'T, seq<'T>>) (random : Random<'T>) : Gen<'T> = + static member Create (shrink : Func<'T, seq<'T>>, random : Random<'T>) : Gen<'T> = Gen.create shrink.Invoke random static member Sized (scaler : Func>) : Gen<'T> = Gen.sized scaler.Invoke - static member IntegralByte (range : Range) : Gen = + static member Integral (range : Range) : Gen = Gen.integral range - static member IntegralSByte (range : Range) : Gen = + static member Integral (range : Range) : Gen = Gen.integral range - static member IntegralInt16 (range : Range) : Gen = + static member Integral (range : Range) : Gen = Gen.integral range - static member IntegralUInt16 (range : Range) : Gen = + static member Integral (range : Range) : Gen = Gen.integral range - static member IntegralInt32 (range : Range) : Gen = + static member Integral (range : Range) : Gen = Gen.integral range - static member IntegralUInt32 (range : Range) : Gen = + static member Integral (range : Range) : Gen = Gen.integral range - static member IntegralInt64 (range : Range) : Gen = + static member Integral (range : Range) : Gen = Gen.integral range - static member IntegralUInt64 (range : Range) : Gen = + static member Integral (range : Range) : Gen = Gen.integral range - static member IntegralDouble (range : Range) : Gen = + static member Integral (range : Range) : Gen = Gen.integral range - static member IntegralSingle (range : Range) : Gen = - Gen.integral range - - static member IntegralDecimal (range : Range) : Gen = + static member Integral (range : Range) : Gen = Gen.integral range static member Item (sequence : seq<'T>) : Gen<'T> = @@ -66,10 +63,10 @@ type Gen = static member Choice (gens : seq>) : Gen<'T> = Gen.choice gens - static member ChoiceRecursive (nonrecs : seq>) (recs : seq>) : Gen<'T> = + static member ChoiceRecursive (nonrecs : seq>, recs : seq>) : Gen<'T> = Gen.choiceRec nonrecs recs - static member Char (lo : char) (hi : char) : Gen = + static member Char (lo : char, hi : char) : Gen = Gen.char lo hi static member UnicodeAll : Gen = @@ -139,90 +136,92 @@ type Gen = Gen.dateTime [] - static member inline Apply(mf : Gen>, ma : Gen<'T>) : Gen<'TResult> = - Gen.apply (mf |> Gen.map (fun f -> f.Invoke)) ma + static member Apply (genFunc : Gen>, genArg : Gen<'T>) : Gen<'TResult> = + Gen.apply (genFunc |> Gen.map (fun f -> f.Invoke)) genArg [] - static member inline Array(gen : Gen<'T>, range : Range) : Gen<'T []> = + static member Array (gen : Gen<'T>, range : Range) : Gen<'T []> = Gen.array range gen [] - static member inline Enumerable(gen : Gen<'T>, range : Range) : Gen> = + static member Enumerable (gen : Gen<'T>, range : Range) : Gen> = Gen.seq range gen [] - static member inline GenerateTree(gen : Gen<'T>) : Tree<'T> = + static member GenerateTree (gen : Gen<'T>) : Tree<'T> = Gen.generateTree gen [] - static member inline List(gen : Gen<'T>, range : Range) : Gen> = + static member List (gen : Gen<'T>, range : Range) : Gen> = Gen.list range gen [] - static member inline NoShrink (gen : Gen<'T>) : Gen<'T> = + static member NoShrink (gen : Gen<'T>) : Gen<'T> = Gen.noShrink gen [] - static member inline Option(gen : Gen<'T>) : Gen> = + static member Option (gen : Gen<'T>) : Gen> = Gen.option gen [] - static member inline PrintSample(gen : Gen<'T>) : unit = + static member PrintSample (gen : Gen<'T>) : unit = Gen.printSample gen [] - static member inline Resize(gen : Gen<'T>, size : Size) : Gen<'T> = + static member Resize (gen : Gen<'T>, size : Size) : Gen<'T> = Gen.resize size gen [] - static member inline Sample(gen : Gen<'T>, size : Size, count : int) : List<'T> = + static member Sample (gen : Gen<'T>, size : Size, count : int) : List<'T> = Gen.sample size count gen [] - static member inline SampleTree(gen : Gen<'T>, size : Size, count : int) : List> = + static member SampleTree (gen : Gen<'T>, size : Size, count : int) : List> = Gen.sampleTree size count gen [] - static member inline Scale(gen : Gen<'T>, scaler : Func) : Gen<'T> = + static member Scale (gen : Gen<'T>, scaler : Func) : Gen<'T> = Gen.scale scaler.Invoke gen [] - static member inline SelectMany(gen : Gen<'T>, binder : Func<'T, Gen<'U>>) : Gen<'U> = + static member SelectMany (gen : Gen<'T>, binder : Func<'T, Gen<'U>>) : Gen<'U> = Gen.bind gen binder.Invoke [] - static member inline SelectMany(gen : Gen<'T>, binder : Func<'T, Gen<'TCollection>>, projection : Func<'T, 'TCollection, 'TResult>) : Gen<'TResult> = - Gen.bind gen (fun a -> - Gen.map (fun b -> projection.Invoke(a, b)) (binder.Invoke(a)) - ) + static member SelectMany (gen : Gen<'T>, binder : Func<'T, Gen<'TCollection>>, projection : Func<'T, 'TCollection, 'TResult>) : Gen<'TResult> = + GenBuilder.gen { + let! a = gen + let! b = binder.Invoke(a) + return projection.Invoke(a, b) + } [] - static member inline SelectRandom(gen : Gen<'T>, binder : Func>, Random>>) : Gen<'TResult> = + static member SelectRandom (gen : Gen<'T>, binder : Func>, Random>>) : Gen<'TResult> = Gen.mapRandom binder.Invoke gen [] - static member inline SelectTree(gen : Gen<'T>, binder : Func, Tree<'TResult>>) : Gen<'TResult> = + static member SelectTree (gen : Gen<'T>, binder : Func, Tree<'TResult>>) : Gen<'TResult> = Gen.mapTree binder.Invoke gen [] - static member inline Select(gen : Gen<'T>, mapper : Func<'T, 'TResult>) : Gen<'TResult> = + static member Select (gen : Gen<'T>, mapper : Func<'T, 'TResult>) : Gen<'TResult> = Gen.map mapper.Invoke gen [] - static member inline Select2(genA : Gen<'T>, mapper : Func<'T, 'U, 'TResult>, genB : Gen<'U>) : Gen<'TResult> = + static member Select2 (genA : Gen<'T>, mapper : Func<'T, 'U, 'TResult>, genB : Gen<'U>) : Gen<'TResult> = Gen.map2 (fun a b -> mapper.Invoke(a, b)) genA genB [] - static member inline Select3(genA : Gen<'T>, mapper : Func<'T, 'U, 'V, 'TResult>, genB : Gen<'U>, genC : Gen<'V>) : Gen<'TResult> = + static member Select3 (genA : Gen<'T>, mapper : Func<'T, 'U, 'V, 'TResult>, genB : Gen<'U>, genC : Gen<'V>) : Gen<'TResult> = Gen.map3 (fun a b c -> mapper.Invoke(a, b, c)) genA genB genC [] - static member inline Select4(genA : Gen<'T>, mapper : Func<'T, 'U, 'V, 'W, 'TResult>, genB : Gen<'U>, genC : Gen<'V>, genD : Gen<'W>) : Gen<'TResult> = + static member Select4 (genA : Gen<'T>, mapper : Func<'T, 'U, 'V, 'W, 'TResult>, genB : Gen<'U>, genC : Gen<'V>, genD : Gen<'W>) : Gen<'TResult> = Gen.map4 (fun a b c d -> mapper.Invoke(a, b, c, d)) genA genB @@ -230,67 +229,67 @@ type Gen = genD [] - static member inline Shrink(gen : Gen<'T>, shrinker : Func<'T, List<'T>>) : Gen<'T> = + static member Shrink (gen : Gen<'T>, shrinker : Func<'T, List<'T>>) : Gen<'T> = Gen.shrink shrinker.Invoke gen [] - static member inline ShrinkLazy(gen : Gen<'T>, shrinker : Func<'T, seq<'T>>) : Gen<'T> = + static member ShrinkLazy (gen : Gen<'T>, shrinker : Func<'T, seq<'T>>) : Gen<'T> = Gen.shrinkLazy shrinker.Invoke gen [] - static member inline Some(gen : Gen>) : Gen<'T> = + static member Some (gen : Gen>) : Gen<'T> = Gen.some gen [] - static member inline String(gen : Gen, range : Range) : Gen = + static member String (gen : Gen, range : Range) : Gen = Gen.string range gen [] - static member inline ToGen(random : Random>) : Gen<'T> = + static member ToGen (random : Random>) : Gen<'T> = Gen.ofRandom random [] - static member inline ToRandom(gen : Gen<'T>) : Random> = + static member ToRandom (gen : Gen<'T>) : Random> = Gen.toRandom gen [] - static member inline TryFinally(gen : Gen<'T>, after : Action) : Gen<'T> = + static member TryFinally (gen : Gen<'T>, after : Action) : Gen<'T> = Gen.tryFinally gen after.Invoke [] - static member inline TryWhere(gen : Gen<'T>, after : Func>) : Gen<'T> = + static member TryWhere (gen : Gen<'T>, after : Func>) : Gen<'T> = Gen.tryWith gen after.Invoke [] - static member inline TryWith(gen : Gen<'T>, after : Func>) : Gen<'T> = + static member TryWith (gen : Gen<'T>, after : Func>) : Gen<'T> = Gen.tryWith gen after.Invoke [] - static member inline Tuple2(gen : Gen<'T>) : Gen<'T * 'T> = + static member Tuple2 (gen : Gen<'T>) : Gen<'T * 'T> = Gen.tuple gen [] - static member inline Tuple3(gen : Gen<'T>) : Gen<'T * 'T * 'T> = + static member Tuple3 (gen : Gen<'T>) : Gen<'T * 'T * 'T> = Gen.tuple3 gen [] - static member inline Tuple4(gen : Gen<'T>) : Gen<'T * 'T * 'T * 'T> = + static member Tuple4 (gen : Gen<'T>) : Gen<'T * 'T * 'T * 'T> = Gen.tuple4 gen [] - static member inline Where(gen : Gen<'T>, predicate : Func<'T, bool>) : Gen<'T> = + static member Where (gen : Gen<'T>, predicate : Func<'T, bool>) : Gen<'T> = Gen.filter predicate.Invoke gen [] - static member inline Zip(genA : Gen<'T>, genB : Gen<'U>) : Gen<'T * 'U> = + static member Zip (genA : Gen<'T>, genB : Gen<'U>) : Gen<'T * 'U> = Gen.zip genA genB [] - static member inline Zip3(genA : Gen<'T>, genB : Gen<'U>, genC : Gen<'V>) : Gen<'T * 'U * 'V> = + static member Zip3 (genA : Gen<'T>, genB : Gen<'U>, genC : Gen<'V>) : Gen<'T * 'U * 'V> = Gen.zip3 genA genB genC [] - static member inline Zip4(genA : Gen<'T>, genB : Gen<'U>, genC : Gen<'V>, genD : Gen<'W>) : Gen<'T * 'U * 'V * 'W> = + static member Zip4 (genA : Gen<'T>, genB : Gen<'U>, genC : Gen<'V>, genD : Gen<'W>) : Gen<'T * 'U * 'V * 'W> = Gen.zip4 genA genB genC genD #endif diff --git a/src/Hedgehog/CSharp/Property.fs b/src/Hedgehog/CSharp/Property.fs index 3cc67a0a..27216b41 100644 --- a/src/Hedgehog/CSharp/Property.fs +++ b/src/Hedgehog/CSharp/Property.fs @@ -24,13 +24,13 @@ type Property = static member FromGen (gen : Gen>) : Property<'T> = Property.ofGen gen - static member FromThrowing (f : Action<'T>) (arg : 'T) : Property = - Property.fromThrowing f.Invoke arg + static member FromThrowing (throwingFunc : Action<'T>, arg : 'T) : Property = + Property.fromThrowing throwingFunc.Invoke arg static member Delay (f : Func>) : Property<'T> = Property.delay f.Invoke - static member Using (resource : 'T) (action : Func<'T, Property<'TResult>>) : Property<'TResult> = + static member Using (resource : 'T, action : Func<'T, Property<'TResult>>) : Property<'TResult> = Property.using resource action.Invoke static member FromOutcome (result : Result<'T>) : Property<'T> = @@ -50,11 +50,11 @@ type Property = Property.toGen property [] - static member TryFinally (property : Property<'T>) (onFinally : Action) : Property<'T> = + static member TryFinally (property : Property<'T>, onFinally : Action) : Property<'T> = Property.tryFinally property onFinally.Invoke [] - static member TryWith (property : Property<'T>) (onError : Func>) : Property<'T> = + static member TryWith (property : Property<'T>, onError : Func>) : Property<'T> = Property.tryWith property onError.Invoke // @@ -110,24 +110,24 @@ type Property = Property.print property [] - static member inline Where(property : Property<'T>, filter : Func<'T, bool>) : Property<'T> = + static member inline Where (property : Property<'T>, filter : Func<'T, bool>) : Property<'T> = Property.filter filter.Invoke property [] - static member inline Select(property : Property<'T>, mapper : Func<'T, 'TResult>) : Property<'TResult> = + static member inline Select (property : Property<'T>, mapper : Func<'T, 'TResult>) : Property<'TResult> = Property.map mapper.Invoke property [] - static member inline Select(property : Property<'T>, mapper : Action<'T>) : Property = + static member inline Select (property : Property<'T>, mapper : Action<'T>) : Property = Property.bind property (Property.fromThrowing mapper.Invoke) [] - static member inline SelectMany(property : Property<'T>, binder : Func<'T, Property<'TCollection>>, projection : Func<'T, 'TCollection, 'TResult>) : Property<'TResult> = + static member inline SelectMany (property : Property<'T>, binder : Func<'T, Property<'TCollection>>, projection : Func<'T, 'TCollection, 'TResult>) : Property<'TResult> = Property.bind property (fun a -> Property.map (fun b -> projection.Invoke(a, b)) (binder.Invoke(a))) [] - static member inline SelectMany(property : Property<'T>, binder : Func<'T, Property<'TCollection>>, projection : Action<'T, 'TCollection>) : Property = + static member inline SelectMany (property : Property<'T>, binder : Func<'T, Property<'TCollection>>, projection : Action<'T, 'TCollection>) : Property = Property.bind property (fun a -> Property.bind (binder.Invoke a) (fun b -> Property.fromThrowing projection.Invoke (a, b))) diff --git a/src/Hedgehog/CSharp/Range.fs b/src/Hedgehog/CSharp/Range.fs index 067efa83..d9d332b4 100644 --- a/src/Hedgehog/CSharp/Range.fs +++ b/src/Hedgehog/CSharp/Range.fs @@ -420,7 +420,7 @@ type Range = Range.exponentialBounded () [] - static member inline Select(range : Range<'T>, mapper : Func<'T, 'TResult>) : Range<'TResult> = + static member inline Select (range : Range<'T>, mapper : Func<'T, 'TResult>) : Range<'TResult> = Range.map mapper.Invoke range // @@ -441,16 +441,16 @@ type Range = /// Get the extents of a range, for a given size. [] - static member inline Bounds (range : Range<'T>) (sz : Size) : 'T * 'T = + static member inline Bounds (range : Range<'T>, sz : Size) : 'T * 'T = Range.bounds sz range /// Get the lower bound of a range for the given size. [] - static member inline LowerBound (range : Range<'T>) (sz : Size) : 'T = + static member inline LowerBound (range : Range<'T>, sz : Size) : 'T = Range.lowerBound sz range /// Get the upper bound of a range for the given size. - static member inline UpperBound (range : Range<'T>) (sz : Size) : 'T = + static member inline UpperBound (range : Range<'T>, sz : Size) : 'T = Range.upperBound sz range #endif From 093ab5e5283fb53cae2df692b5ec4c6b8141c176 Mon Sep 17 00:00:00 2001 From: Adam Becker Date: Tue, 5 Jan 2021 23:40:50 +0000 Subject: [PATCH 09/17] Straightening out float types. --- src/Hedgehog/CSharp/Gen.fs | 6 +++--- src/Hedgehog/CSharp/Range.fs | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Hedgehog/CSharp/Gen.fs b/src/Hedgehog/CSharp/Gen.fs index becbdf61..ca6d1b77 100644 --- a/src/Hedgehog/CSharp/Gen.fs +++ b/src/Hedgehog/CSharp/Gen.fs @@ -123,12 +123,12 @@ type Gen = static member UInt64 (range : Range) : Gen = Gen.uint64 range + static member Single (range : Range) : Gen = + Gen.single range + static member Double (range : Range) : Gen = Gen.double range - static member Single (range : Range) : Gen = - Gen.float range - static member Guid : Gen = Gen.guid diff --git a/src/Hedgehog/CSharp/Range.fs b/src/Hedgehog/CSharp/Range.fs index d9d332b4..fe1aa551 100644 --- a/src/Hedgehog/CSharp/Range.fs +++ b/src/Hedgehog/CSharp/Range.fs @@ -68,7 +68,7 @@ type Range = /// Construct a range which is unaffected by the size parameter using the /// full range of a data type. - static member ConstantBoundedSingle : Range = + static member ConstantBoundedSingle : Range = Range.constantBounded () /// Construct a range which is unaffected by the size parameter using the @@ -127,7 +127,7 @@ type Range = /// Construct a range which scales the bounds relative to the size /// parameter. - static member LinearFromSingle (z, x, y) : Range = + static member LinearFromSingle (z, x, y) : Range = Range.linearFrom z x y /// Construct a range which scales the bounds relative to the size @@ -182,7 +182,7 @@ type Range = /// Construct a range which scales the second bound relative to the size /// parameter. - static member LinearSingle (x, y) : Range = + static member LinearSingle (x, y) : Range = Range.linear x y /// Construct a range which scales the second bound relative to the size @@ -237,7 +237,7 @@ type Range = /// Construct a range which is scaled relative to the size parameter and /// uses the full range of a data type. - static member LinearBoundedSingle : Range = + static member LinearBoundedSingle : Range = Range.linearBounded () /// Construct a range which is scaled relative to the size parameter and @@ -296,7 +296,7 @@ type Range = /// Construct a range which scales the bounds exponentially relative to the /// size parameter. - static member ExponentialFromSingle (z, x, y) : Range = + static member ExponentialFromSingle (z, x, y) : Range = Range.exponentialFrom z x y /// Construct a range which scales the bounds exponentially relative to the @@ -351,7 +351,7 @@ type Range = /// Construct a range which scales the second bound exponentially relative /// to the size parameter. - static member ExponentialSingle (x, y) : Range = + static member ExponentialSingle (x, y) : Range = Range.exponential x y /// Construct a range which scales the second bound exponentially relative @@ -406,7 +406,7 @@ type Range = /// Construct a range which is scaled exponentially relative to the size /// parameter and uses the full range of a data type. - static member ExponentialBoundedSingle : Range = + static member ExponentialBoundedSingle : Range = Range.exponentialBounded () /// Construct a range which is scaled exponentially relative to the size From a6db498d8ac0cf1cec63454f17b2e9c371a7e793 Mon Sep 17 00:00:00 2001 From: Adam Becker Date: Wed, 6 Jan 2021 00:03:55 +0000 Subject: [PATCH 10/17] Use member instead of member inline. --- src/Hedgehog/CSharp/Property.fs | 16 ++++++++-------- src/Hedgehog/CSharp/Range.fs | 10 +++++----- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Hedgehog/CSharp/Property.fs b/src/Hedgehog/CSharp/Property.fs index 27216b41..b637a448 100644 --- a/src/Hedgehog/CSharp/Property.fs +++ b/src/Hedgehog/CSharp/Property.fs @@ -62,15 +62,15 @@ type Property = // [] - static member inline Report (property : Property) : Report = + static member Report (property : Property) : Report = Property.report property [] - static member inline Report (property : Property, tests : int) : Report = + static member Report (property : Property, tests : int) : Report = Property.report' tests property [] - static member inline Check (property : Property) : unit = + static member Check (property : Property) : unit = Property.check property [] @@ -110,24 +110,24 @@ type Property = Property.print property [] - static member inline Where (property : Property<'T>, filter : Func<'T, bool>) : Property<'T> = + static member Where (property : Property<'T>, filter : Func<'T, bool>) : Property<'T> = Property.filter filter.Invoke property [] - static member inline Select (property : Property<'T>, mapper : Func<'T, 'TResult>) : Property<'TResult> = + static member Select (property : Property<'T>, mapper : Func<'T, 'TResult>) : Property<'TResult> = Property.map mapper.Invoke property [] - static member inline Select (property : Property<'T>, mapper : Action<'T>) : Property = + static member Select (property : Property<'T>, mapper : Action<'T>) : Property = Property.bind property (Property.fromThrowing mapper.Invoke) [] - static member inline SelectMany (property : Property<'T>, binder : Func<'T, Property<'TCollection>>, projection : Func<'T, 'TCollection, 'TResult>) : Property<'TResult> = + static member SelectMany (property : Property<'T>, binder : Func<'T, Property<'TCollection>>, projection : Func<'T, 'TCollection, 'TResult>) : Property<'TResult> = Property.bind property (fun a -> Property.map (fun b -> projection.Invoke(a, b)) (binder.Invoke(a))) [] - static member inline SelectMany (property : Property<'T>, binder : Func<'T, Property<'TCollection>>, projection : Action<'T, 'TCollection>) : Property = + static member SelectMany (property : Property<'T>, binder : Func<'T, Property<'TCollection>>, projection : Action<'T, 'TCollection>) : Property = Property.bind property (fun a -> Property.bind (binder.Invoke a) (fun b -> Property.fromThrowing projection.Invoke (a, b))) diff --git a/src/Hedgehog/CSharp/Range.fs b/src/Hedgehog/CSharp/Range.fs index fe1aa551..a8a1b7e7 100644 --- a/src/Hedgehog/CSharp/Range.fs +++ b/src/Hedgehog/CSharp/Range.fs @@ -420,7 +420,7 @@ type Range = Range.exponentialBounded () [] - static member inline Select (range : Range<'T>, mapper : Func<'T, 'TResult>) : Range<'TResult> = + static member Select (range : Range<'T>, mapper : Func<'T, 'TResult>) : Range<'TResult> = Range.map mapper.Invoke range // @@ -436,21 +436,21 @@ type Range = /// When using a 'Range' to generate numbers, the shrinking function will /// shrink towards the origin. [] - static member inline Origin (range : Range<'T>) : 'T = + static member Origin (range : Range<'T>) : 'T = Range.origin range /// Get the extents of a range, for a given size. [] - static member inline Bounds (range : Range<'T>, sz : Size) : 'T * 'T = + static member Bounds (range : Range<'T>, sz : Size) : 'T * 'T = Range.bounds sz range /// Get the lower bound of a range for the given size. [] - static member inline LowerBound (range : Range<'T>, sz : Size) : 'T = + static member LowerBound (range : Range<'T>, sz : Size) : 'T = Range.lowerBound sz range /// Get the upper bound of a range for the given size. - static member inline UpperBound (range : Range<'T>, sz : Size) : 'T = + static member UpperBound (range : Range<'T>, sz : Size) : 'T = Range.upperBound sz range #endif From 97f248c0d528876c9d9fee30bc91af9bffc5e9bf Mon Sep 17 00:00:00 2001 From: Adam Becker Date: Wed, 6 Jan 2021 00:06:48 +0000 Subject: [PATCH 11/17] Make the extension classes static. --- src/Hedgehog/CSharp/Gen.fs | 3 ++- src/Hedgehog/CSharp/Property.fs | 3 ++- src/Hedgehog/CSharp/Range.fs | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Hedgehog/CSharp/Gen.fs b/src/Hedgehog/CSharp/Gen.fs index ca6d1b77..c66bf6ac 100644 --- a/src/Hedgehog/CSharp/Gen.fs +++ b/src/Hedgehog/CSharp/Gen.fs @@ -7,7 +7,8 @@ open System.Runtime.CompilerServices open Hedgehog [] -type Gen = +[] +type Gen private () = static member FromValue (value : 'T) : Gen<'T> = Gen.constant(value) diff --git a/src/Hedgehog/CSharp/Property.fs b/src/Hedgehog/CSharp/Property.fs index b637a448..e034106f 100644 --- a/src/Hedgehog/CSharp/Property.fs +++ b/src/Hedgehog/CSharp/Property.fs @@ -7,7 +7,8 @@ open System.Runtime.CompilerServices open Hedgehog [] -type Property = +[] +type Property private () = static member Failure : Property = Property.failure diff --git a/src/Hedgehog/CSharp/Range.fs b/src/Hedgehog/CSharp/Range.fs index a8a1b7e7..2928bb76 100644 --- a/src/Hedgehog/CSharp/Range.fs +++ b/src/Hedgehog/CSharp/Range.fs @@ -7,7 +7,8 @@ open System.Runtime.CompilerServices open Hedgehog [] -type Range = +[] +type Range private () = // // Combinators - Constant From 33e2c339626cd06beec5624851b5fe0ac6c6c842 Mon Sep 17 00:00:00 2001 From: Adam Becker Date: Fri, 8 Jan 2021 16:48:06 +0000 Subject: [PATCH 12/17] fromThrowing -> ofThrowing --- src/Hedgehog/CSharp/Property.fs | 6 +++--- src/Hedgehog/Property.fs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Hedgehog/CSharp/Property.fs b/src/Hedgehog/CSharp/Property.fs index e034106f..648d08af 100644 --- a/src/Hedgehog/CSharp/Property.fs +++ b/src/Hedgehog/CSharp/Property.fs @@ -26,7 +26,7 @@ type Property private () = Property.ofGen gen static member FromThrowing (throwingFunc : Action<'T>, arg : 'T) : Property = - Property.fromThrowing throwingFunc.Invoke arg + Property.ofThrowing throwingFunc.Invoke arg static member Delay (f : Func>) : Property<'T> = Property.delay f.Invoke @@ -120,7 +120,7 @@ type Property private () = [] static member Select (property : Property<'T>, mapper : Action<'T>) : Property = - Property.bind property (Property.fromThrowing mapper.Invoke) + Property.bind property (Property.ofThrowing mapper.Invoke) [] static member SelectMany (property : Property<'T>, binder : Func<'T, Property<'TCollection>>, projection : Func<'T, 'TCollection, 'TResult>) : Property<'TResult> = @@ -131,6 +131,6 @@ type Property private () = static member SelectMany (property : Property<'T>, binder : Func<'T, Property<'TCollection>>, projection : Action<'T, 'TCollection>) : Property = Property.bind property (fun a -> Property.bind (binder.Invoke a) (fun b -> - Property.fromThrowing projection.Invoke (a, b))) + Property.ofThrowing projection.Invoke (a, b))) #endif diff --git a/src/Hedgehog/Property.fs b/src/Hedgehog/Property.fs index 28e200c7..897c8084 100644 --- a/src/Hedgehog/Property.fs +++ b/src/Hedgehog/Property.fs @@ -379,7 +379,7 @@ module Property = /// Converts a possibly-throwing function to /// a property by treating "no exception" as success. - let fromThrowing (f : 'a -> unit) (x : 'a) : Property = + let ofThrowing (f : 'a -> unit) (x : 'a) : Property = try f x success () From 821a91c2b2a8afd283e14e300dcfd5987d18af9b Mon Sep 17 00:00:00 2001 From: Adam Becker Date: Fri, 8 Jan 2021 16:53:57 +0000 Subject: [PATCH 13/17] Fix C# API with datetime changes --- src/Hedgehog/CSharp/Gen.fs | 7 +++++-- src/Hedgehog/Gen.fs | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/Hedgehog/CSharp/Gen.fs b/src/Hedgehog/CSharp/Gen.fs index c66bf6ac..d491cccf 100644 --- a/src/Hedgehog/CSharp/Gen.fs +++ b/src/Hedgehog/CSharp/Gen.fs @@ -133,8 +133,11 @@ type Gen private () = static member Guid : Gen = Gen.guid - static member DateTime : Gen = - Gen.dateTime + static member DateTime (range : Range) : Gen = + Gen.dateTime range + + static member DateTimeOffset (range : Range) : Gen = + Gen.dateTimeOffset range [] static member Apply (genFunc : Gen>, genArg : Gen<'T>) : Gen<'TResult> = diff --git a/src/Hedgehog/Gen.fs b/src/Hedgehog/Gen.fs index 33d85de8..4fdfa5e9 100644 --- a/src/Hedgehog/Gen.fs +++ b/src/Hedgehog/Gen.fs @@ -324,8 +324,8 @@ module Gen = /// Generates a Unicode character, including invalid standalone surrogates: /// '\000'..'\65535' let unicodeAll : Gen = - let lo = System.Char.MinValue - let hi = System.Char.MaxValue + let lo = Char.MinValue + let hi = Char.MaxValue char lo hi // Generates a random digit. @@ -357,7 +357,7 @@ module Gen = || x = Operators.char 65535 unicodeAll |> filter (not << isNoncharacter) - |> filter (not << System.Char.IsSurrogate) + |> filter (not << Char.IsSurrogate) // Generates a random alpha character. let alpha : Gen = @@ -370,9 +370,9 @@ module Gen = /// Generates a random string using 'Range' to determine the length and the /// specified character generator. let string (range : Range) (g : Gen) : Gen = - sized <| fun size -> + sized <| fun _size -> g |> array range - |> map System.String + |> map String // // Combinators - Primitives @@ -437,26 +437,26 @@ module Gen = // /// Generates a random globally unique identifier. - let guid : Gen = gen { + let guid : Gen = gen { let! bs = array (Range.constant 16 16) (byte <| Range.constantBounded ()) - return System.Guid bs + return Guid bs } /// Generates a random DateTime using the specified range. /// For example: /// let range = /// Range.constantFrom - /// (System.DateTime (2000, 1, 1)) System.DateTime.MinValue System.DateTime.MaxValue + /// (DateTime (2000, 1, 1)) DateTime.MinValue DateTime.MaxValue /// Gen.dateTime range - let dateTime (range : Range) : Gen = + let dateTime (range : Range) : Gen = gen { let! ticks = range |> Range.map (fun dt -> dt.Ticks) |> integral - return System.DateTime ticks + return DateTime ticks } /// Generates a random DateTimeOffset using the specified range. [] - let dateTimeOffset (range : Range) : Gen = + let dateTimeOffset (range : Range) : Gen = gen { let! ticks = range |> Range.map (fun dt -> dt.Ticks) |> integral // Ensure there is no overflow near the edges when adding the offset @@ -469,7 +469,7 @@ module Gen = (14L * 60L) ((ticks - DateTimeOffset.MinValue.Ticks) / TimeSpan.TicksPerMinute) let! offsetMinutes = int (Range.linearFrom 0 (Operators.int minOffsetMinutes) (Operators.int maxOffsetMinutes)) - return System.DateTimeOffset(ticks, TimeSpan.FromMinutes (Operators.float offsetMinutes)) + return DateTimeOffset(ticks, TimeSpan.FromMinutes (Operators.float offsetMinutes)) } // From 70e22d5213958a8c36eed26380926c957911b832 Mon Sep 17 00:00:00 2001 From: Adam Becker Date: Sun, 10 Jan 2021 01:47:54 +0000 Subject: [PATCH 14/17] More idiomatic for C# --- src/Hedgehog/CSharp/Gen.fs | 30 +++++--- src/Hedgehog/CSharp/Range.fs | 135 ++++++++++++++++++----------------- src/Hedgehog/Gen.fs | 3 - 3 files changed, 88 insertions(+), 80 deletions(-) diff --git a/src/Hedgehog/CSharp/Gen.fs b/src/Hedgehog/CSharp/Gen.fs index d491cccf..59928b90 100644 --- a/src/Hedgehog/CSharp/Gen.fs +++ b/src/Hedgehog/CSharp/Gen.fs @@ -100,12 +100,12 @@ type Gen private () = static member Bool : Gen = Gen.bool - static member Byte (range : Range) : Gen = - Gen.byte range - static member SByte (range : Range) : Gen = Gen.sbyte range + static member Byte (range : Range) : Gen = + Gen.byte range + static member Int16 (range : Range) : Gen = Gen.int16 range @@ -130,6 +130,9 @@ type Gen private () = static member Double (range : Range) : Gen = Gen.double range + static member Decimal (range : Range) : Gen = + Gen.decimal range + static member Guid : Gen = Gen.guid @@ -156,16 +159,21 @@ type Gen private () = Gen.generateTree gen [] - static member List (gen : Gen<'T>, range : Range) : Gen> = + static member List (gen : Gen<'T>, range : Range) : Gen> = Gen.list range gen + |> Gen.map ResizeArray [] static member NoShrink (gen : Gen<'T>) : Gen<'T> = Gen.noShrink gen [] - static member Option (gen : Gen<'T>) : Gen> = - Gen.option gen + static member NullReference (gen : Gen<'T>) : Gen<'T> = + Gen.option gen |> Gen.map (Option.defaultValue null) + + [] + static member NullValue (gen : Gen<_>) : Gen<_> = + Gen.option gen |> Gen.map (Option.defaultWith Nullable << Option.map Nullable) [] static member PrintSample (gen : Gen<'T>) : unit = @@ -176,12 +184,14 @@ type Gen private () = Gen.resize size gen [] - static member Sample (gen : Gen<'T>, size : Size, count : int) : List<'T> = + static member Sample (gen : Gen<'T>, size : Size, count : int) : ResizeArray<'T> = Gen.sample size count gen + |> ResizeArray [] - static member SampleTree (gen : Gen<'T>, size : Size, count : int) : List> = + static member SampleTree (gen : Gen<'T>, size : Size, count : int) : ResizeArray> = Gen.sampleTree size count gen + |> ResizeArray [] static member Scale (gen : Gen<'T>, scaler : Func) : Gen<'T> = @@ -233,8 +243,8 @@ type Gen private () = genD [] - static member Shrink (gen : Gen<'T>, shrinker : Func<'T, List<'T>>) : Gen<'T> = - Gen.shrink shrinker.Invoke gen + static member Shrink (gen : Gen<'T>, shrinker : Func<'T, ResizeArray<'T>>) : Gen<'T> = + Gen.shrink (shrinker.Invoke >> Seq.toList) gen [] static member ShrinkLazy (gen : Gen<'T>, shrinker : Func<'T, seq<'T>>) : Gen<'T> = diff --git a/src/Hedgehog/CSharp/Range.fs b/src/Hedgehog/CSharp/Range.fs index 2928bb76..52509ed2 100644 --- a/src/Hedgehog/CSharp/Range.fs +++ b/src/Hedgehog/CSharp/Range.fs @@ -29,57 +29,57 @@ type Range private () = /// Construct a range which is unaffected by the size parameter using the /// full range of a data type. - static member ConstantBoundedInt8 : Range = + static member ConstantBoundedSByte () : Range = Range.constantBounded () /// Construct a range which is unaffected by the size parameter using the /// full range of a data type. - static member ConstantBoundedInt16 : Range = + static member ConstantBoundedInt16 () : Range = Range.constantBounded () /// Construct a range which is unaffected by the size parameter using the /// full range of a data type. - static member ConstantBoundedInt32 : Range = + static member ConstantBoundedInt32 () : Range = Range.constantBounded () /// Construct a range which is unaffected by the size parameter using the /// full range of a data type. - static member ConstantBoundedInt64 : Range = + static member ConstantBoundedInt64 () : Range = Range.constantBounded () /// Construct a range which is unaffected by the size parameter using the /// full range of a data type. - static member ConstantBoundedUInt8 : Range = + static member ConstantBoundedByte () : Range = Range.constantBounded () /// Construct a range which is unaffected by the size parameter using the /// full range of a data type. - static member ConstantBoundedUInt16 : Range = + static member ConstantBoundedUInt16 () : Range = Range.constantBounded () /// Construct a range which is unaffected by the size parameter using the /// full range of a data type. - static member ConstantBoundedUInt32 : Range = + static member ConstantBoundedUInt32 () : Range = Range.constantBounded () /// Construct a range which is unaffected by the size parameter using the /// full range of a data type. - static member ConstantBoundedUInt64 : Range = + static member ConstantBoundedUInt64 () : Range = Range.constantBounded () /// Construct a range which is unaffected by the size parameter using the /// full range of a data type. - static member ConstantBoundedSingle : Range = + static member ConstantBoundedSingle () : Range = Range.constantBounded () /// Construct a range which is unaffected by the size parameter using the /// full range of a data type. - static member ConstantBoundedDouble : Range = + static member ConstantBoundedDouble () : Range = Range.constantBounded () /// Construct a range which is unaffected by the size parameter using the /// full range of a data type. - static member ConstantBoundedDecimal : Range = + static member ConstantBoundedDecimal () : Range = Range.constantBounded () // @@ -88,42 +88,42 @@ type Range private () = /// Construct a range which scales the bounds relative to the size /// parameter. - static member LinearFromInt8 (z, x, y) : Range = + static member LinearFromSByte (z, x, y) : Range = Range.linearFrom z x y /// Construct a range which scales the bounds relative to the size /// parameter. - static member LinearFromInt16 (z, x, y) : Range = + static member LinearFromInt16 (z, x, y) : Range = Range.linearFrom z x y /// Construct a range which scales the bounds relative to the size /// parameter. - static member LinearFromInt32 (z, x, y) : Range = + static member LinearFromInt32 (z, x, y) : Range = Range.linearFrom z x y /// Construct a range which scales the bounds relative to the size /// parameter. - static member LinearFromInt64 (z, x, y) : Range = + static member LinearFromInt64 (z, x, y) : Range = Range.linearFrom z x y /// Construct a range which scales the bounds relative to the size /// parameter. - static member LinearFromUInt8 (z, x, y) : Range = + static member LinearFromByte (z, x, y) : Range = Range.linearFrom z x y /// Construct a range which scales the bounds relative to the size /// parameter. - static member LinearFromUInt16 (z, x, y) : Range = + static member LinearFromUInt16 (z, x, y) : Range = Range.linearFrom z x y /// Construct a range which scales the bounds relative to the size /// parameter. - static member LinearFromUInt32 (z, x, y) : Range = + static member LinearFromUInt32 (z, x, y) : Range = Range.linearFrom z x y /// Construct a range which scales the bounds relative to the size /// parameter. - static member LinearFromUInt64 (z, x, y) : Range = + static member LinearFromUInt64 (z, x, y) : Range = Range.linearFrom z x y /// Construct a range which scales the bounds relative to the size @@ -143,42 +143,42 @@ type Range private () = /// Construct a range which scales the second bound relative to the size /// parameter. - static member LinearInt8 (x, y) : Range = + static member LinearSByte (x, y) : Range = Range.linear x y /// Construct a range which scales the second bound relative to the size /// parameter. - static member LinearInt16 (x, y) : Range = + static member LinearInt16 (x, y) : Range = Range.linear x y /// Construct a range which scales the second bound relative to the size /// parameter. - static member LinearInt32 (x, y) : Range = + static member LinearInt32 (x, y) : Range = Range.linear x y /// Construct a range which scales the second bound relative to the size /// parameter. - static member LinearInt64 (x, y) : Range = + static member LinearInt64 (x, y) : Range = Range.linear x y /// Construct a range which scales the second bound relative to the size /// parameter. - static member LinearUInt8 (x, y) : Range = + static member LinearByte (x, y) : Range = Range.linear x y /// Construct a range which scales the second bound relative to the size /// parameter. - static member LinearUInt16 (x, y) : Range = + static member LinearUInt16 (x, y) : Range = Range.linear x y /// Construct a range which scales the second bound relative to the size /// parameter. - static member LinearUInt32 (x, y) : Range = + static member LinearUInt32 (x, y) : Range = Range.linear x y /// Construct a range which scales the second bound relative to the size /// parameter. - static member LinearUInt64 (x, y) : Range = + static member LinearUInt64 (x, y) : Range = Range.linear x y /// Construct a range which scales the second bound relative to the size @@ -188,67 +188,67 @@ type Range private () = /// Construct a range which scales the second bound relative to the size /// parameter. - static member LinearDouble (z, x, y) : Range = + static member LinearDouble (x, y) : Range = Range.linear x y /// Construct a range which scales the second bound relative to the size /// parameter. - static member LinearDecimal (z, x, y) : Range = + static member LinearDecimal (x, y) : Range = Range.linear x y /// Construct a range which is scaled relative to the size parameter and /// uses the full range of a data type. - static member LinearBoundedInt8 : Range = + static member LinearBoundedSByte () : Range = Range.linearBounded () /// Construct a range which is scaled relative to the size parameter and /// uses the full range of a data type. - static member LinearBoundedInt16 : Range = + static member LinearBoundedInt16 () : Range = Range.linearBounded () /// Construct a range which is scaled relative to the size parameter and /// uses the full range of a data type. - static member LinearBoundedInt32 : Range = + static member LinearBoundedInt32 () : Range = Range.linearBounded () /// Construct a range which is scaled relative to the size parameter and /// uses the full range of a data type. - static member LinearBoundedInt64 : Range = + static member LinearBoundedInt64 () : Range = Range.linearBounded () /// Construct a range which is scaled relative to the size parameter and /// uses the full range of a data type. - static member LinearBoundedUInt8 : Range = + static member LinearBoundedByte () : Range = Range.linearBounded () /// Construct a range which is scaled relative to the size parameter and /// uses the full range of a data type. - static member LinearBoundedUInt16 : Range = + static member LinearBoundedUInt16 () : Range = Range.linearBounded () /// Construct a range which is scaled relative to the size parameter and /// uses the full range of a data type. - static member LinearBoundedUInt32 : Range = + static member LinearBoundedUInt32 () : Range = Range.linearBounded () /// Construct a range which is scaled relative to the size parameter and /// uses the full range of a data type. - static member LinearBoundedUInt64 : Range = + static member LinearBoundedUInt64 () : Range = Range.linearBounded () /// Construct a range which is scaled relative to the size parameter and /// uses the full range of a data type. - static member LinearBoundedSingle : Range = + static member LinearBoundedSingle () : Range = Range.linearBounded () /// Construct a range which is scaled relative to the size parameter and /// uses the full range of a data type. - static member LinearBoundedDouble : Range = + static member LinearBoundedDouble () : Range = Range.linearBounded () /// Construct a range which is scaled relative to the size parameter and /// uses the full range of a data type. - static member LinearBoundedDecimal : Range = + static member LinearBoundedDecimal () : Range = Range.linearBounded () // @@ -257,42 +257,42 @@ type Range private () = /// Construct a range which scales the bounds exponentially relative to the /// size parameter. - static member ExponentialFromInt8 (z, x, y) : Range = + static member ExponentialFromSByte (z, x, y) : Range = Range.exponentialFrom z x y /// Construct a range which scales the bounds exponentially relative to the /// size parameter. - static member ExponentialFromInt16 (z, x, y) : Range = + static member ExponentialFromInt16 (z, x, y) : Range = Range.exponentialFrom z x y /// Construct a range which scales the bounds exponentially relative to the /// size parameter. - static member ExponentialFromInt32 (z, x, y) : Range = + static member ExponentialFromInt32 (z, x, y) : Range = Range.exponentialFrom z x y /// Construct a range which scales the bounds exponentially relative to the /// size parameter. - static member ExponentialFromInt64 (z, x, y) : Range = + static member ExponentialFromInt64 (z, x, y) : Range = Range.exponentialFrom z x y /// Construct a range which scales the bounds exponentially relative to the /// size parameter. - static member ExponentialFromUInt8 (z, x, y) : Range = + static member ExponentialFromByte (z, x, y) : Range = Range.exponentialFrom z x y /// Construct a range which scales the bounds exponentially relative to the /// size parameter. - static member ExponentialFromUInt16 (z, x, y) : Range = + static member ExponentialFromUInt16 (z, x, y) : Range = Range.exponentialFrom z x y /// Construct a range which scales the bounds exponentially relative to the /// size parameter. - static member ExponentialFromUInt32 (z, x, y) : Range = + static member ExponentialFromUInt32 (z, x, y) : Range = Range.exponentialFrom z x y /// Construct a range which scales the bounds exponentially relative to the /// size parameter. - static member ExponentialFromUInt64 (z, x, y) : Range = + static member ExponentialFromUInt64 (z, x, y) : Range = Range.exponentialFrom z x y /// Construct a range which scales the bounds exponentially relative to the @@ -312,42 +312,42 @@ type Range private () = /// Construct a range which scales the second bound exponentially relative /// to the size parameter. - static member ExponentialInt8 (x, y) : Range = + static member ExponentialSByte (x, y) : Range = Range.exponential x y /// Construct a range which scales the second bound exponentially relative /// to the size parameter. - static member ExponentialInt16 (x, y) : Range = + static member ExponentialInt16 (x, y) : Range = Range.exponential x y /// Construct a range which scales the second bound exponentially relative /// to the size parameter. - static member ExponentialInt32 (x, y) : Range = + static member ExponentialInt32 (x, y) : Range = Range.exponential x y /// Construct a range which scales the second bound exponentially relative /// to the size parameter. - static member ExponentialInt64 (x, y) : Range = + static member ExponentialInt64 (x, y) : Range = Range.exponential x y /// Construct a range which scales the second bound exponentially relative /// to the size parameter. - static member ExponentialUInt8 (x, y) : Range = + static member ExponentialByte (x, y) : Range = Range.exponential x y /// Construct a range which scales the second bound exponentially relative /// to the size parameter. - static member ExponentialUInt16 (x, y) : Range = + static member ExponentialUInt16 (x, y) : Range = Range.exponential x y /// Construct a range which scales the second bound exponentially relative /// to the size parameter. - static member ExponentialUInt32 (x, y) : Range = + static member ExponentialUInt32 (x, y) : Range = Range.exponential x y /// Construct a range which scales the second bound exponentially relative /// to the size parameter. - static member ExponentialUInt64 (x, y) : Range = + static member ExponentialUInt64 (x, y) : Range = Range.exponential x y /// Construct a range which scales the second bound exponentially relative @@ -367,57 +367,57 @@ type Range private () = /// Construct a range which is scaled exponentially relative to the size /// parameter and uses the full range of a data type. - static member ExponentialBoundedInt8 : Range = + static member ExponentialBoundedSByte () : Range = Range.exponentialBounded () /// Construct a range which is scaled exponentially relative to the size /// parameter and uses the full range of a data type. - static member ExponentialBoundedInt16 : Range = + static member ExponentialBoundedInt16 () : Range = Range.exponentialBounded () /// Construct a range which is scaled exponentially relative to the size /// parameter and uses the full range of a data type. - static member ExponentialBoundedInt32 : Range = + static member ExponentialBoundedInt32 () : Range = Range.exponentialBounded () /// Construct a range which is scaled exponentially relative to the size /// parameter and uses the full range of a data type. - static member ExponentialBoundedInt64 : Range = + static member ExponentialBoundedInt64 () : Range = Range.exponentialBounded () /// Construct a range which is scaled exponentially relative to the size /// parameter and uses the full range of a data type. - static member ExponentialBoundedUInt8 : Range = + static member ExponentialBoundedByte () : Range = Range.exponentialBounded () /// Construct a range which is scaled exponentially relative to the size /// parameter and uses the full range of a data type. - static member ExponentialBoundedUInt16 : Range = + static member ExponentialBoundedUInt16 () : Range = Range.exponentialBounded () /// Construct a range which is scaled exponentially relative to the size /// parameter and uses the full range of a data type. - static member ExponentialBoundedUInt32 : Range = + static member ExponentialBoundedUInt32 () : Range = Range.exponentialBounded () /// Construct a range which is scaled exponentially relative to the size /// parameter and uses the full range of a data type. - static member ExponentialBoundedUInt64 : Range = + static member ExponentialBoundedUInt64 () : Range = Range.exponentialBounded () /// Construct a range which is scaled exponentially relative to the size /// parameter and uses the full range of a data type. - static member ExponentialBoundedSingle : Range = + static member ExponentialBoundedSingle () : Range = Range.exponentialBounded () /// Construct a range which is scaled exponentially relative to the size /// parameter and uses the full range of a data type. - static member ExponentialBoundedDouble : Range = + static member ExponentialBoundedDouble () : Range = Range.exponentialBounded () /// Construct a range which is scaled exponentially relative to the size /// parameter and uses the full range of a data type. - static member ExponentialBoundedDecimal : Range = + static member ExponentialBoundedDecimal () : Range = Range.exponentialBounded () [] @@ -451,6 +451,7 @@ type Range private () = Range.lowerBound sz range /// Get the upper bound of a range for the given size. + [] static member UpperBound (range : Range<'T>, sz : Size) : 'T = Range.upperBound sz range diff --git a/src/Hedgehog/Gen.fs b/src/Hedgehog/Gen.fs index 4fdfa5e9..dfd10f43 100644 --- a/src/Hedgehog/Gen.fs +++ b/src/Hedgehog/Gen.fs @@ -423,12 +423,10 @@ module Gen = (double range) |> map float /// Generates a random 32-bit floating point number. - [] let single (range : Range) : Gen = double (Range.map ExtraTopLevelOperators.double range) |> map single /// Generates a random decimal floating-point number. - [] let decimal (range : Range) : Gen = double (Range.map ExtraTopLevelOperators.double range) |> map decimal @@ -455,7 +453,6 @@ module Gen = } /// Generates a random DateTimeOffset using the specified range. - [] let dateTimeOffset (range : Range) : Gen = gen { let! ticks = range |> Range.map (fun dt -> dt.Ticks) |> integral From 02df74a6f869d1ebc609481e13581a7bc899c0c4 Mon Sep 17 00:00:00 2001 From: Adam Becker Date: Sun, 10 Jan 2021 02:24:18 +0000 Subject: [PATCH 15/17] Better use of overloads --- src/Hedgehog/CSharp/Gen.fs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Hedgehog/CSharp/Gen.fs b/src/Hedgehog/CSharp/Gen.fs index 59928b90..9fba807a 100644 --- a/src/Hedgehog/CSharp/Gen.fs +++ b/src/Hedgehog/CSharp/Gen.fs @@ -11,12 +11,12 @@ open Hedgehog type Gen private () = static member FromValue (value : 'T) : Gen<'T> = - Gen.constant(value) + Gen.constant value static member FromRandom (random : Random>) : Gen<'T> = - Gen.ofRandom(random) + Gen.ofRandom random - static member Delay (func : Func<_>) : Gen<'T> = + static member Delay (func : Func>) : Gen<'T> = Gen.delay func.Invoke static member Create (shrink : Func<'T, seq<'T>>, random : Random<'T>) : Gen<'T> = @@ -172,7 +172,7 @@ type Gen private () = Gen.option gen |> Gen.map (Option.defaultValue null) [] - static member NullValue (gen : Gen<_>) : Gen<_> = + static member NullValue (gen : Gen<'T>) : Gen> = Gen.option gen |> Gen.map (Option.defaultWith Nullable << Option.map Nullable) [] @@ -222,20 +222,20 @@ type Gen private () = Gen.map mapper.Invoke gen [] - static member Select2 (genA : Gen<'T>, mapper : Func<'T, 'U, 'TResult>, genB : Gen<'U>) : Gen<'TResult> = + static member Select (genA : Gen<'T>, mapper : Func<'T, 'U, 'TResult>, genB : Gen<'U>) : Gen<'TResult> = Gen.map2 (fun a b -> mapper.Invoke(a, b)) genA genB [] - static member Select3 (genA : Gen<'T>, mapper : Func<'T, 'U, 'V, 'TResult>, genB : Gen<'U>, genC : Gen<'V>) : Gen<'TResult> = + static member Select (genA : Gen<'T>, mapper : Func<'T, 'U, 'V, 'TResult>, genB : Gen<'U>, genC : Gen<'V>) : Gen<'TResult> = Gen.map3 (fun a b c -> mapper.Invoke(a, b, c)) genA genB genC [] - static member Select4 (genA : Gen<'T>, mapper : Func<'T, 'U, 'V, 'W, 'TResult>, genB : Gen<'U>, genC : Gen<'V>, genD : Gen<'W>) : Gen<'TResult> = + static member Select (genA : Gen<'T>, mapper : Func<'T, 'U, 'V, 'W, 'TResult>, genB : Gen<'U>, genC : Gen<'V>, genD : Gen<'W>) : Gen<'TResult> = Gen.map4 (fun a b c d -> mapper.Invoke(a, b, c, d)) genA genB @@ -299,11 +299,11 @@ type Gen private () = Gen.zip genA genB [] - static member Zip3 (genA : Gen<'T>, genB : Gen<'U>, genC : Gen<'V>) : Gen<'T * 'U * 'V> = + static member Zip (genA : Gen<'T>, genB : Gen<'U>, genC : Gen<'V>) : Gen<'T * 'U * 'V> = Gen.zip3 genA genB genC [] - static member Zip4 (genA : Gen<'T>, genB : Gen<'U>, genC : Gen<'V>, genD : Gen<'W>) : Gen<'T * 'U * 'V * 'W> = + static member Zip (genA : Gen<'T>, genB : Gen<'U>, genC : Gen<'V>, genD : Gen<'W>) : Gen<'T * 'U * 'V * 'W> = Gen.zip4 genA genB genC genD #endif From 91cd8db3aae4e298ab4c2b972fac60d0019600c7 Mon Sep 17 00:00:00 2001 From: Adam Becker Date: Sun, 10 Jan 2021 19:27:27 +0000 Subject: [PATCH 16/17] Remove accidental direct recursion --- src/Hedgehog/CSharp/Property.fs | 8 ++++---- tests/Hedgehog.CSharp.Tests/LinqTests.cs | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Hedgehog/CSharp/Property.fs b/src/Hedgehog/CSharp/Property.fs index 648d08af..299f1b00 100644 --- a/src/Hedgehog/CSharp/Property.fs +++ b/src/Hedgehog/CSharp/Property.fs @@ -17,7 +17,7 @@ type Property private () = Property.discard static member Success (value : 'T) : Property<'T> = - Property.Success(value) + Property.success value static member FromBool (value : bool) : Property = Property.ofBool(value) @@ -25,6 +25,9 @@ type Property private () = static member FromGen (gen : Gen>) : Property<'T> = Property.ofGen gen + static member FromResult (result : Result<'T>) : Property<'T> = + Property.ofResult result + static member FromThrowing (throwingFunc : Action<'T>, arg : 'T) : Property = Property.ofThrowing throwingFunc.Invoke arg @@ -34,9 +37,6 @@ type Property private () = static member Using (resource : 'T, action : Func<'T, Property<'TResult>>) : Property<'TResult> = Property.using resource action.Invoke - static member FromOutcome (result : Result<'T>) : Property<'T> = - Property.ofResult(result) - static member CounterExample (message : Func) : Property = Property.counterexample(message.Invoke) diff --git a/tests/Hedgehog.CSharp.Tests/LinqTests.cs b/tests/Hedgehog.CSharp.Tests/LinqTests.cs index 94c8bd70..98fa41e7 100644 --- a/tests/Hedgehog.CSharp.Tests/LinqTests.cs +++ b/tests/Hedgehog.CSharp.Tests/LinqTests.cs @@ -1,7 +1,6 @@ using Xunit; // Import ForAll: -using Hedgehog.CSharp; using static Hedgehog.CSharp.Property; namespace Hedgehog.CSharp.Tests From e6f0e7cc800b6121ef9bf7146ff7b4a7802f6938 Mon Sep 17 00:00:00 2001 From: Adam Becker Date: Sun, 10 Jan 2021 19:28:46 +0000 Subject: [PATCH 17/17] Unnecessary parens --- src/Hedgehog/CSharp/Property.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Hedgehog/CSharp/Property.fs b/src/Hedgehog/CSharp/Property.fs index 299f1b00..8bffaf83 100644 --- a/src/Hedgehog/CSharp/Property.fs +++ b/src/Hedgehog/CSharp/Property.fs @@ -20,7 +20,7 @@ type Property private () = Property.success value static member FromBool (value : bool) : Property = - Property.ofBool(value) + Property.ofBool value static member FromGen (gen : Gen>) : Property<'T> = Property.ofGen gen