From a7f612213d917bc3bc0baf8801a5b49f88b33ba9 Mon Sep 17 00:00:00 2001 From: ThisFunctionalTom Date: Sat, 23 Jan 2021 09:45:06 +0100 Subject: [PATCH] Add tree tests to fable tests --- src/Hedgehog/Tuple.fs | 2 +- tests/Hedgehog.Fable.Tests/GenTests.fs | 33 ++----- .../Hedgehog.Fable.Tests.fsproj | 3 +- tests/Hedgehog.Fable.Tests/MinimalTests.fs | 28 +++--- tests/Hedgehog.Fable.Tests/Program.fs | 5 +- tests/Hedgehog.Fable.Tests/RangeTests.fs | 97 +++++++++++------- tests/Hedgehog.Fable.Tests/ShrinkTests.fs | 61 +++++++----- tests/Hedgehog.Fable.Tests/TreeTests.fs | 98 +++++++++++++++++++ 8 files changed, 230 insertions(+), 97 deletions(-) create mode 100644 tests/Hedgehog.Fable.Tests/TreeTests.fs diff --git a/src/Hedgehog/Tuple.fs b/src/Hedgehog/Tuple.fs index 645fdb9b..730569e2 100644 --- a/src/Hedgehog/Tuple.fs +++ b/src/Hedgehog/Tuple.fs @@ -9,7 +9,7 @@ module private Tuple = x, f y -module private GenTuple = +module GenTuple = let mapFst (f : 'a -> 'c) (gen : Gen<'a * 'b>) : Gen<'c * 'b> = Gen.map (Tuple.mapFst f) gen diff --git a/tests/Hedgehog.Fable.Tests/GenTests.fs b/tests/Hedgehog.Fable.Tests/GenTests.fs index bd6b1cd0..c427fa72 100644 --- a/tests/Hedgehog.Fable.Tests/GenTests.fs +++ b/tests/Hedgehog.Fable.Tests/GenTests.fs @@ -5,23 +5,22 @@ open Hedgehog let dtRange = Range.constantFrom (System.DateTime (2000, 1, 1)) System.DateTime.MinValue System.DateTime.MaxValue let genTests = xunitTests "Gen tests" [ - theory "dateTime creates System.DateTime instances" + theory "dateTime creates System.DateTime instances" [ 8; 16; 32; 64; 128; 256; 512 ] <| fun count -> let actual = Gen.dateTime dtRange |> Gen.sample 0 count actual |> List.distinct |> List.length =! actual.Length - + fact "unicode doesn't return any surrogate" <| fun _ -> - let actual = Gen.sample 100 100000 Gen.unicode + let actual = Gen.sample 100 100000 Gen.unicode [] =! List.filter System.Char.IsSurrogate actual - theory "unicode doesn't return any noncharacter" + theory "unicode doesn't return any noncharacter" [ 65534; 65535 ] <| fun nonchar -> - let isNoncharacter = (=) <| Operators.char nonchar let actual = Gen.sample 100 100000 Gen.unicode - [] =! List.filter isNoncharacter actual + [] =! List.filter (fun ch -> ch = char nonchar) actual fact "dateTime randomly generates value between max and min ticks" <| fun _ -> let seed0 = Seed.random() @@ -54,26 +53,14 @@ let genTests = xunitTests "Gen tests" [ System.DateTime (2000, 1, 1) =! result pfact "int64 can create exponentially bounded integer" <| fun _ -> - Property.check <| property { + Property.check (property { let! _ = Gen.int64 (Range.exponentialBounded ()) return true - } + }) pfact "uint64 can create exponentially bounded integer" <| fun _ -> - Property.check <| property { + Property.check (property { let! _ = Gen.uint64 (Range.exponentialBounded ()) return true - } - - fact "int can create exponentially bounded integer" <| fun _ -> - Property.check <| property { - let! _ = Gen.int (Range.exponentialBounded ()) - return true - } - - pfact "uint32 can create exponentially bounded integer" <| fun _ -> - Property.check <| property { - let! _ = Gen.uint32 (Range.exponentialBounded ()) - return true - } -] \ No newline at end of file + }) +] diff --git a/tests/Hedgehog.Fable.Tests/Hedgehog.Fable.Tests.fsproj b/tests/Hedgehog.Fable.Tests/Hedgehog.Fable.Tests.fsproj index 813d7217..0f849023 100644 --- a/tests/Hedgehog.Fable.Tests/Hedgehog.Fable.Tests.fsproj +++ b/tests/Hedgehog.Fable.Tests/Hedgehog.Fable.Tests.fsproj @@ -10,6 +10,7 @@ + @@ -22,4 +23,4 @@ - \ No newline at end of file + diff --git a/tests/Hedgehog.Fable.Tests/MinimalTests.fs b/tests/Hedgehog.Fable.Tests/MinimalTests.fs index 2e52be21..2f2c0e16 100644 --- a/tests/Hedgehog.Fable.Tests/MinimalTests.fs +++ b/tests/Hedgehog.Fable.Tests/MinimalTests.fs @@ -50,20 +50,24 @@ let rec tryFindSmallest (p : 'a -> bool) (Node (x, xs) : Tree<'a>) : 'a option = #nowarn "40" let rec genExp : Gen = - Gen.delay <| fun _ -> - Gen.shrink shrinkExp <| // comment this out to see the property fail - Gen.choiceRec [ - Lit Gen.int (Range.constant 0 10) - Var genName - ] [ - Lam Gen.zip genName genExp - App Gen.zip genExp genExp - ] + Gen.delay (fun _ -> + let recs = [ + Lit Gen.int (Range.constant 0 10) + Var genName + ] + let nonrecs = [ + Lam Gen.zip genName genExp + App Gen.zip genExp genExp + ] + + Gen.choiceRec recs nonrecs + |> Gen.shrink shrinkExp + ) let minimalTests = xunitTests "Minimal tests" [ fact "greedy traversal with a predicate yields the perfect minimal shrink" <| fun _ -> - Property.check <| property { + Property.check (property { let! xs = Gen.mapTree Tree.duplicate genExp |> Gen.resize 20 match tryFindSmallest noAppLit10 xs with | None -> @@ -81,5 +85,5 @@ let minimalTests = xunitTests "Minimal tests" [ counterexample (sprintf "%A" x) return false } - } -] \ No newline at end of file + }) +] diff --git a/tests/Hedgehog.Fable.Tests/Program.fs b/tests/Hedgehog.Fable.Tests/Program.fs index 303735fe..2327a6fa 100644 --- a/tests/Hedgehog.Fable.Tests/Program.fs +++ b/tests/Hedgehog.Fable.Tests/Program.fs @@ -19,6 +19,7 @@ let smokeTests = testList "Smoke tests" [ let allTests = testList "All tests" [ smokeTests + TreeTests.treeTests RangeTests.rangeTests GenTests.genTests SeedTests.seedTests @@ -27,9 +28,9 @@ let allTests = testList "All tests" [ ] [] -let main (args: string[]) = +let main (args: string[]) = #if FABLE_COMPILER Mocha.runTests allTests #else runTestsWithArgs defaultConfig args allTests -#endif \ No newline at end of file +#endif diff --git a/tests/Hedgehog.Fable.Tests/RangeTests.fs b/tests/Hedgehog.Fable.Tests/RangeTests.fs index 1f469845..0ed78e9e 100644 --- a/tests/Hedgehog.Fable.Tests/RangeTests.fs +++ b/tests/Hedgehog.Fable.Tests/RangeTests.fs @@ -12,16 +12,18 @@ let rangeTests = xunitTests "Range tests" [ ( 256, 128) ( 512, 256) (1024, 512) ] <| fun (sz, x) -> - + let actual = - Range.bounds sz <| Range.singleton x + Range.singleton x + |> Range.bounds sz (x, x) =! actual theory "singleton origin returns correct result" [ 1; 2; 3; 30; 128; 256; 512; 1024 ] <| fun x -> - + let actual = - Range.origin <| Range.singleton x + Range.singleton x + |> Range.origin x =! actual theory "constant bounds returns correct result" @@ -34,7 +36,8 @@ let rangeTests = xunitTests "Range tests" [ (1024, 511, 512) ] <| fun (sz, x, y) -> let actual = - Range.bounds sz <| Range.constant x y + Range.constant x y + |> Range.bounds sz (x, y) =! actual theory "constant origin returns correct result" @@ -47,14 +50,16 @@ let rangeTests = xunitTests "Range tests" [ (1024, 511) ] <| fun (x, y) -> let actual = - Range.origin <| Range.constant x y - x =! actual + Range.constant x y + |> Range.origin + x =! actual theory "range from -x to x, with the origin at" [ 1; 2; 3; 30; 128; 256; 512; 1024] <| fun x -> let actual = - Range.origin <| Range.constantFrom x -10 10 + Range.constantFrom x -10 10 + |> Range.origin x =! actual theory "range from -x to x, with the bounds at" @@ -67,31 +72,35 @@ let rangeTests = xunitTests "Range tests" [ (1024, 511) ] <| fun (sz, x) -> let actual = - Range.bounds sz <| Range.constantFrom 0 -x x + Range.constantFrom 0 -x x + |> Range.bounds sz (-x, x) =! actual - theory "constantBounded bounds returns correct result - Byte range" + theory "constantBounded bounds returns correct result - Byte range" [ 1; 2; 3; 30; 128; 256; 512; 1024 ] <| fun sz -> let x = - Range.bounds sz <| (Range.constantBounded () : Range) + (Range.constantBounded () : Range) + |> Range.bounds sz (Byte.MinValue, Byte.MaxValue) =! x - theory "constantBounded bounds returns correct result - Int32 range" + theory "constantBounded bounds returns correct result - Int32 range" [ 1; 2; 3; 30; 128; 256; 512; 1024 ] <| fun sz -> let x = - Range.bounds sz <| (Range.constantBounded () : Range) + (Range.constantBounded () : Range) + |> Range.bounds sz (Int32.MinValue, Int32.MaxValue) =! x - theory "constantBounded bounds returns correct result - Int64 range" + theory "constantBounded bounds returns correct result - Int64 range" [ 1; 2; 3; 30; 128; 256; 512; 1024 ] <| fun sz -> let x = - Range.bounds sz <| (Range.constantBounded () : Range) + (Range.constantBounded () : Range) + |> Range.bounds sz (Int64.MinValue, Int64.MaxValue) =! x - theory "clamp truncates a value so it stays within some range" + theory "clamp truncates a value so it stays within some range" [ (5, 10, 15, 10) (5, 10, 0, 5) ] <| fun (x, y, n, expected) -> @@ -101,92 +110,110 @@ let rangeTests = xunitTests "Range tests" [ fact "linear scales the second bound relative to the size - example 1" <| fun _ -> let actual = - Range.bounds 0 <| Range.linear 0 10 + Range.linear 0 10 + |> Range.bounds 0 (0, 0) =! actual fact "linear scales the second bound relative to the size - example 2" <| fun _ -> let actual = - Range.bounds 50 <| Range.linear 0 10 + Range.linear 0 10 + |> Range.bounds 50 (0, 5) =! actual fact "linear scales the second bound relative to the size - example 3" <| fun _ -> let actual = - Range.bounds 99 <| Range.linear 0 10 + Range.linear 0 10 + |> Range.bounds 99 (0, 10) =! actual fact "linearFrom scales the bounds relative to the size - example 1" <| fun _ -> let actual = - Range.bounds 0 <| Range.linearFrom 0 -10 10 + Range.linearFrom 0 -10 10 + |> Range.bounds 0 (0, 0) =! actual fact "linearFrom scales the bounds relative to the size - example 2" <| fun _ -> let actual = - Range.bounds 50 <| Range.linearFrom 0 -10 20 + Range.linearFrom 0 -10 20 + |> Range.bounds 50 (-5, 10) =! actual fact "linearFrom scales the bounds relative to the size - example 3" <| fun _ -> let actual = - Range.bounds 99 <| Range.linearFrom 0 -10 20 + Range.linearFrom 0 -10 20 + |> Range.bounds 99 (-10, 20) =! actual fact "linearBounded uses the full range of a data type - example 1" <| fun _ -> let actual = - Range.bounds 0 <| (Range.linearBounded () : Range) + (Range.linearBounded () : Range) + |> Range.bounds 0 (-0y, 0y) =! actual fact "linearBounded uses the full range of a data type - example 2" <| fun _ -> let actual = - Range.bounds 50 <| (Range.linearBounded () : Range) + (Range.linearBounded () : Range) + |> Range.bounds 50 (-64y, 64y) =! actual fact "linearBounded uses the full range of a data type - example 3" <| fun _ -> let actual = - Range.bounds 99 <| (Range.linearBounded () : Range) + (Range.linearBounded () : Range) + |> Range.bounds 99 (-128y, 127y) =! actual fact "exponential scales the second bound exponentially relative to the size - example 1" <| fun _ -> let actual = - Range.bounds 0 <| Range.exponential 1 512 + Range.exponential 1 512 + |> Range.bounds 0 (1, 1) =! actual fact "exponential scales the second bound exponentially relative to the size - example 2" <| fun _ -> let actual = - Range.bounds 77 <| Range.exponential 1 512 + Range.exponential 1 512 + |> Range.bounds 77 (1, 128) =! actual fact "exponential scales the second bound exponentially relative to the size - example 3" <| fun _ -> let actual = - Range.bounds 99 <| Range.exponential 1 512 + Range.exponential 1 512 + |> Range.bounds 99 (1, 512) =! actual fact "exponentialFrom scales the bounds exponentially relative to the size - example 1" <| fun _ -> let actual = - Range.bounds 0 <| Range.exponentialFrom 0 -128 512 + Range.exponentialFrom 0 -128 512 + |> Range.bounds 0 (0, 0) =! actual fact "exponentialFrom scales the bounds exponentially relative to the size - example 2" <| fun _ -> let actual = - Range.bounds 50 <| Range.exponentialFrom 0 -128 512 + Range.exponentialFrom 0 -128 512 + |> Range.bounds 50 (-11, 22) =! actual fact "exponentialFrom scales the bounds exponentially relative to the size - example 3" <| fun _ -> let actual = - Range.bounds 99 <| Range.exponentialFrom 3 -128 512 + Range.exponentialFrom 3 -128 512 + |> Range.bounds 99 (-128, 512) =! actual fact "exponentialBounded uses the full range of a data type - example 1" <| fun _ -> let actual = - Range.bounds 0 <| (Range.exponentialBounded () : Range) + (Range.exponentialBounded () : Range) + |> Range.bounds 0 (-0y, 0y) =! actual fact "exponentialBounded uses the full range of a data type - example 2" <| fun _ -> let actual = - Range.bounds 50 <| (Range.exponentialBounded () : Range) + (Range.exponentialBounded () : Range) + |> Range.bounds 50 (-11y, 11y) =! actual fact "exponentialBounded uses the full range of a data type - example 3" <| fun _ -> let actual = - Range.bounds 99 <| (Range.exponentialBounded () : Range) + (Range.exponentialBounded () : Range) + |> Range.bounds 99 (-128y, 127y) =! actual -] \ No newline at end of file +] diff --git a/tests/Hedgehog.Fable.Tests/ShrinkTests.fs b/tests/Hedgehog.Fable.Tests/ShrinkTests.fs index 781e4489..df29e6e5 100644 --- a/tests/Hedgehog.Fable.Tests/ShrinkTests.fs +++ b/tests/Hedgehog.Fable.Tests/ShrinkTests.fs @@ -3,7 +3,7 @@ module Hedgehog.Fable.Tests.ShrinkTests open Hedgehog let shrinkTests = xunitTests "Shrink tests" [ - + fact "removes permutes a list by removing 'k' consecutive elements from it" <| fun _ -> let actual = Shrink.removes 2 [ 1; 2; 3; 4; 5; 6 ] @@ -13,47 +13,55 @@ let shrinkTests = xunitTests "Shrink tests" [ [ 1; 2; 3; 4 ] ] // http://stackoverflow.com/a/17101488 Seq.zip expected actual - |> Seq.forall (fun (a, b) -> a = b) + |> Seq.forall (fun (a, b) -> a = b) |> Expect.isTrue fact "removes produces all permutations of removing 'k' elements from a list - example 1" <| fun _ -> let actual = - Seq.toList <| Shrink.removes 2 [1; 2; 3; 4; 5; 6] + Shrink.removes 2 [1; 2; 3; 4; 5; 6] + |> Seq.toList [[3; 4; 5; 6]; [1; 2; 5; 6]; [1; 2; 3; 4]] =! actual fact "removes produces all permutations of removing 'k' elements from a list - example 2" <| fun _ -> let actual = - Seq.toList <| Shrink.removes 3 [1; 2; 3; 4; 5; 6] + Shrink.removes 3 [1; 2; 3; 4; 5; 6] + |> Seq.toList [[4; 5; 6]; [1; 2; 3]] =! actual fact "removes produces all permutations of removing 'k' elements from a list - example 3" <| fun _ -> let actual = - Seq.toList <| Shrink.removes 2 ["a"; "b"; "c"; "d"; "e"; "f"] + Shrink.removes 2 ["a"; "b"; "c"; "d"; "e"; "f"] + |> Seq.toList [["c"; "d"; "e"; "f"]; ["a"; "b"; "e"; "f"]; ["a"; "b"; "c"; "d"]] =! actual fact "halves produces a list containing the progressive halving of an integral - example 1" <| fun _ -> let actual = - Seq.toList <| Shrink.halves 15 + Shrink.halves 15 + |> Seq.toList [15; 7; 3; 1] =! actual fact "halves produces a list containing the progressive halving of an integral - example 2" <| fun _ -> let actual = - Seq.toList <| Shrink.halves 100 + Shrink.halves 100 + |> Seq.toList [100; 50; 25; 12; 6; 3; 1] =! actual fact "halves produces a list containing the progressive halving of an integral - example 3" <| fun _ -> let actual = - Seq.toList <| Shrink.halves -26 + Shrink.halves -26 + |> Seq.toList [-26; -13; -6; -3; -1] =! actual fact "list shrinks a list by edging towards the empty list - example 1" <| fun _ -> let actual = - Seq.toList <| Shrink.list [1; 2; 3] + Shrink.list [1; 2; 3] + |> Seq.toList [[]; [2; 3]; [1; 3]; [1; 2]] =! actual fact "list shrinks a list by edging towards the empty list - example 2" <| fun _ -> let actual = - Seq.toList <| Shrink.list ["a"; "b"; "c"; "d"] + Shrink.list ["a"; "b"; "c"; "d"] + |> Seq.toList [ [] [ "c"; "d" ] [ "a"; "b" ] @@ -65,27 +73,34 @@ let shrinkTests = xunitTests "Shrink tests" [ fact "towards shrinks an integral number by edging towards a destination - exmaple 1" <| fun _ -> let actual = - Seq.toList <| Shrink.towards 0 100 + Shrink.towards 0 100 + |> Seq.toList [0; 50; 75; 88; 94; 97; 99] =! actual fact "towards shrinks an integral number by edging towards a destination - exmaple 2" <| fun _ -> let actual = - Seq.toList <| Shrink.towards 500 1000 + Shrink.towards 500 1000 + |> Seq.toList [500; 750; 875; 938; 969; 985; 993; 997; 999] =! actual fact "towards shrinks an integral number by edging towards a destination - exmaple 3" <| fun _ -> let actual = - Seq.toList <| Shrink.towards -50 -26 + Shrink.towards -50 -26 + |> Seq.toList [-50; -38; -32; -29; -27] =! actual fact "towardsDouble shrinks a floating-point number by edging towards a destination - example 1" <| fun _ -> let actual = - Seq.toList << Seq.take 7 <| Shrink.towardsDouble 0.0 100.0 + Shrink.towardsDouble 0.0 100.0 + |> Seq.take 7 + |> Seq.toList [0.0; 50.0; 75.0; 87.5; 93.75; 96.875; 98.4375] =! actual fact "towardsDouble shrinks a floating-point number by edging towards a destination - example 2" <| fun _ -> let actual = - Seq.toList << Seq.take 7 <| Shrink.towardsDouble 1.0 0.5 + Shrink.towardsDouble 1.0 0.5 + |> Seq.take 7 + |> Seq.toList [1.0; 0.75; 0.625; 0.5625; 0.53125; 0.515625; 0.5078125] =! actual theory "halves Produces a list containing the results of halving a number" @@ -138,7 +153,7 @@ let shrinkTests = xunitTests "Shrink tests" [ x0 |> Shrink.towards destination |> Seq.toList - actual + actual |> List.forall (fun x1 -> x1 < x0 && x1 >= destination) |> Expect.isTrue @@ -151,8 +166,8 @@ let shrinkTests = xunitTests "Shrink tests" [ x0 |> Shrink.towards destination |> Seq.toList - actual - |> List.isEmpty + actual + |> List.isEmpty |> Expect.isTrue theory "towardsDouble shrinks by edging towards a destination number" @@ -168,7 +183,7 @@ let shrinkTests = xunitTests "Shrink tests" [ x0 |> Shrink.towardsDouble destination |> Seq.toList - actual + actual |> List.forall (fun x1 -> x1 < x0 && x1 >= destination) |> Expect.isTrue @@ -176,13 +191,13 @@ let shrinkTests = xunitTests "Shrink tests" [ [ ( 1.0, 1.0) ( 30.0, 30.0) (1024.0, 1024.0) ] <| fun (x0, destination) -> - + let actual = x0 |> Shrink.towards destination |> Seq.toList - actual - |> List.isEmpty + actual + |> List.isEmpty |> Expect.isTrue -] \ No newline at end of file +] diff --git a/tests/Hedgehog.Fable.Tests/TreeTests.fs b/tests/Hedgehog.Fable.Tests/TreeTests.fs new file mode 100644 index 00000000..d600eeac --- /dev/null +++ b/tests/Hedgehog.Fable.Tests/TreeTests.fs @@ -0,0 +1,98 @@ +module Hedgehog.Fable.Tests.TreeTests + +open Hedgehog + +let treeTests = xunitTests "Tree tests" [ + fact "render tree with depth 0" <| fun _ -> + Property.check (property { + let! x0 = Gen.constant "0" + + let tree = + Node (x0, [ + ]) + |> Tree.map (sprintf "%A") + + let expected = [ + sprintf "%A" x0 + ] + expected =! Tree.renderList tree + }) + + fact "render tree with depth 1" <| fun _ -> + Property.check (property { + let! x0 = Gen.constant "0" + let! x1 = Gen.constant "1" + let! x2 = Gen.constant "2" + let! x3 = Gen.constant "3" + + let tree = + Node (x0, [ + Node (x1, []) + Node (x2, []) + Node (x3, []) + ]) + |> Tree.map (sprintf "%A") + + let expected = [ + sprintf "%A" x0 + sprintf "├-%A" x1 + sprintf "├-%A" x2 + sprintf "└-%A" x3 + ] + expected =! Tree.renderList tree + }) + + fact "render tree with depth 2" <| fun _ -> + Property.check (property { + let! x0 = Gen.constant "0" + let! x1 = Gen.constant "1" + let! x2 = Gen.constant "2" + let! x3 = Gen.constant "3" + let! x4 = Gen.constant "4" + let! x5 = Gen.constant "5" + let! x6 = Gen.constant "6" + let! x7 = Gen.constant "7" + let! x8 = Gen.constant "8" + let! x9 = Gen.constant "9" + let! x10 = Gen.constant "10" + let! x11 = Gen.constant "11" + let! x12 = Gen.constant "12" + + let tree = + Node (x0, [ + Node (x1, [ + Node (x4, []) + Node (x5, []) + Node (x6, []) + ]) + Node (x2, [ + Node (x7, []) + Node (x8, []) + Node (x9, []) + ]) + Node (x3, [ + Node (x10, []) + Node (x11, []) + Node (x12, []) + ]) + ]) + |> Tree.map (sprintf "%A") + + let expected = [ + sprintf "%A" x0 + sprintf "├-%A" x1 + sprintf "| ├-%A" x4 + sprintf "| ├-%A" x5 + sprintf "| └-%A" x6 + sprintf "├-%A" x2 + sprintf "| ├-%A" x7 + sprintf "| ├-%A" x8 + sprintf "| └-%A" x9 + sprintf "└-%A" x3 + sprintf " ├-%A" x10 + sprintf " ├-%A" x11 + sprintf " └-%A" x12 + ] + expected =! Tree.renderList tree + }) + ]