Skip to content

Commit

Permalink
Issues ntwilson#33, ntwilson#34: *[.NonEmpty].init and .replicate, an…
Browse files Browse the repository at this point in the history
…d some basic Numbers members
  • Loading branch information
cmorley191 committed Jul 11, 2019
1 parent 4fdc6e0 commit 6ac8015
Show file tree
Hide file tree
Showing 17 changed files with 586 additions and 62 deletions.
18 changes: 18 additions & 0 deletions SafetyFirst.Specs/ArraySpec.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,18 @@ open FsCheck

open SafetyFirst
open SafetyFirst.Specs.SeqSpec
open SafetyFirst.Numbers

let upcastNE = Array.NonEmpty.toArray

let averageFloats' (xs:float[]) = Array.average' xs
let averageFloats (xs:float[]) = Array.average xs
let averageByFloats' (projection:_ -> float) xs = Array.averageBy' projection xs
let averageByFloats (projection:_ -> float) xs = Array.averageBy projection xs

let initByInts' = (fun count initializer -> Array.init' count (NaturalInt.value >> initializer))
let initByIntsNonEmpty = (fun count initializer -> Array.NonEmpty.initN count (NaturalInt.value >> initializer))

[<Test>]
let ``Safe Array functions error whenever unsafe versions throw for all random inputs`` () =
errorsWheneverThrows1 averageFloats' averageFloats
Expand All @@ -25,6 +31,7 @@ let ``Safe Array functions error whenever unsafe versions throw for all random i
errorsWheneverThrows4 Array.foldBack2' Array.foldBack2
errorsWheneverThrows3 Array.forall2' Array.forall2
errorsWheneverThrows1 Array.head' Array.head
errorsWheneverThrows2 initByInts' Array.init
errorsWheneverThrows2 Array.item' Array.item
errorsWheneverThrows1 Array.last' Array.last
errorsWheneverThrows3 Array.map2' Array.map2
Expand All @@ -37,6 +44,7 @@ let ``Safe Array functions error whenever unsafe versions throw for all random i
errorsWheneverThrows2 Array.pick' Array.pick
errorsWheneverThrows2 Array.reduce' Array.reduce
errorsWheneverThrows2 Array.reduceBack' Array.reduceBack
errorsWheneverThrows2 Array.replicate' Array.replicate
errorsWheneverThrows2 Array.skip' Array.skip
errorsWheneverThrows2 Array.splitAt' Array.splitAt
errorsWheneverThrows2 Array.splitInto' Array.splitInto
Expand All @@ -63,6 +71,7 @@ let ``Safe Array functions always produce the same output as unsafe versions for
alwaysProduceSameOutput4 Array.foldBack2' Array.foldBack2
alwaysProduceSameOutput3 Array.forall2' Array.forall2
alwaysProduceSameOutput1 Array.head' Array.head
alwaysProduceSameOutput2 initByInts' Array.init
alwaysProduceSameOutput2 Array.item' Array.item
alwaysProduceSameOutput1 Array.last' Array.last
alwaysProduceSameOutput3 Array.map2' Array.map2
Expand All @@ -75,6 +84,7 @@ let ``Safe Array functions always produce the same output as unsafe versions for
alwaysProduceSameOutput2 Array.pick' Array.pick
alwaysProduceSameOutput2 Array.reduce' Array.reduce
alwaysProduceSameOutput2 Array.reduceBack' Array.reduceBack
alwaysProduceSameOutput2 Array.replicate' Array.replicate
alwaysProduceSameOutput2 Array.skip' Array.skip
alwaysProduceSameOutput2 Array.splitAt' Array.splitAt
alwaysProduceSameOutput2 Array.splitInto' Array.splitInto
Expand All @@ -86,4 +96,12 @@ let ``Safe Array functions always produce the same output as unsafe versions for
alwaysProduceSameOutput2 Array.zip' Array.zip
alwaysProduceSameOutput3 Array.zip3' Array.zip3

module SafeByType =
open SeqSpec.SafeByType

[<Test>]
let ``Array functions that are safe by type behave like the base functions`` () =
let (>>>) f g = (fun a b -> f a b |> g)

alwaysProduceSameOutput2 (initByIntsNonEmpty >>> upcastNE) (Array.init << PositiveInt.value)
alwaysProduceSameOutput2 (Array.NonEmpty.replicateN >>> upcastNE) (Array.replicate << PositiveInt.value)
31 changes: 28 additions & 3 deletions SafetyFirst.Specs/FSeqSpec.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ open NUnit.Framework
open Swensen.Unquote

open SafetyFirst
open SafetyFirst.Numbers

[<Test>]
let ``can construct an FSeq with the fseq function`` () =
Expand Down Expand Up @@ -294,6 +295,11 @@ module Splitting =
module SafeFunctions =
open SeqSpec

let upcastNE = FSeq.NonEmpty.toSeq

let initByInts' = (fun count initializer -> FSeq.init' count (NaturalInt.value >> initializer))
let initByIntsNonEmpty = (fun count initializer -> FSeq.NonEmpty.initN count (NaturalInt.value >> initializer))

let averageFloats' (xs:float fseq) = FSeq.average' xs
let averageFloats (xs:float seq) = Seq.average xs
let averageByFloats' (projection:_ -> float) xs = FSeq.averageBy' projection xs
Expand Down Expand Up @@ -321,13 +327,15 @@ module SafeFunctions =
errorsWheneverThrowsForFSeq2 averageByFloats' averageByFloats
errorsWheneverThrowsForFSeq2 FSeq.findBack' Seq.findBack
errorsWheneverThrowsForFSeq2 FSeq.findIndexBack' Seq.findIndexBack
errorsWheneverThrows2 initByInts' Seq.init
errorsWheneverThrowsForFSeq1 FSeq.last' Seq.last
errorsWheneverThrowsForFSeq1 FSeq.max'<int> Seq.max<int>
errorsWheneverThrowsForFSeq2 FSeq.maxBy'<int, int> Seq.maxBy<int, int>
errorsWheneverThrowsForFSeq1 FSeq.min'<int> Seq.min<int>
errorsWheneverThrowsForFSeq2 FSeq.minBy'<int, int> Seq.minBy<int, int>
errorsWheneverThrowsForFSeq2 FSeq.reduce' Seq.reduce
errorsWheneverThrowsForFSeq2 FSeq.reduceBack' Seq.reduceBack
errorsWheneverThrows2 FSeq.replicate' Seq.replicate
errorsWheneverThrowsForFSeq2 FSeq.splitInto' Seq.splitInto
errorsWheneverThrowsForSeq1 fseqTransposeComparable seqTransposeComparable

Expand All @@ -340,25 +348,42 @@ module SafeFunctions =
(fun a xs -> safeVersion a (fseq xs))
(fun a xs -> unsafeVersion a (List.toSeq xs))

let alwaysProduceSameFSeqOutput1 safeVersion unsafeVersion =
alwaysProduceSameOutput1 (safeVersion >> Result.map FSeq.toSeq) unsafeVersion

let alwaysProduceSameFSeqOutput2 safeVersion unsafeVersion =
alwaysProduceSameOutput2
(fun a b -> safeVersion a b |> Result.map FSeq.toSeq)
unsafeVersion

let fseqSplitIntoComparable n xs =
FSeq.splitInto' n xs
|> Result.map (FSeq.map FSeq.toArray >> FSeq.toSeq)

[<Test>]
let ``Safe FSeq functions always produce the same output as unsafe versions for all random inputs`` () =
alwaysProduceSameOutputForFSeq1 averageFloats' averageFloats
alwaysProduceSameOutputForFSeq2 averageByFloats' averageByFloats
alwaysProduceSameOutputForFSeq2 FSeq.findBack' Seq.findBack
alwaysProduceSameOutputForFSeq2 FSeq.findIndexBack' Seq.findIndexBack
alwaysProduceSameFSeqOutput2 initByInts' Seq.init
alwaysProduceSameOutputForFSeq1 FSeq.last' Seq.last
alwaysProduceSameOutputForFSeq1 FSeq.max'<int> Seq.max
alwaysProduceSameOutputForFSeq2 FSeq.maxBy'<int, int> Seq.maxBy
alwaysProduceSameOutputForFSeq1 FSeq.min'<int> Seq.min
alwaysProduceSameOutputForFSeq2 FSeq.minBy'<int, int> Seq.minBy
alwaysProduceSameOutputForFSeq2 FSeq.reduce' Seq.reduce
alwaysProduceSameOutputForFSeq2 FSeq.reduceBack' Seq.reduceBack
alwaysProduceSameFSeqOutput2 FSeq.replicate' Seq.replicate
alwaysProduceSameOutputForFSeq2 fseqSplitIntoComparable Seq.splitInto
alwaysProduceSameOutputForSeq1 fseqTransposeComparable seqTransposeComparable



module SafeByType =
open SeqSpec.SafeByType

[<Test>]
let ``FSeq functions that are safe by type behave like the base functions`` () =
let (>>>) f g = (fun a b -> f a b |> g)

alwaysProduceSameOutput2 (initByIntsNonEmpty >>> upcastNE) (Seq.init << PositiveInt.value)
alwaysProduceSameOutput2 (FSeq.NonEmpty.replicateN >>> upcastNE) (Seq.replicate << PositiveInt.value)
23 changes: 23 additions & 0 deletions SafetyFirst.Specs/Generators.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module SafetyFirst.Specs.Generators

open FsCheck
open SafetyFirst.Numbers

type Numbers =
static member private gen_NaturalInt = gen {
let! x = Arb.generate<int>
return NaturalInt.assume (abs x)
}
static member NaturalIntGen() = { new Arbitrary<NaturalInt>() with override this.Generator = Numbers.gen_NaturalInt }

static member private gen_PositiveInt = gen {
let! t = Numbers.gen_NaturalInt
return t.Increment
}
static member PositiveIntGen() = { new Arbitrary<PositiveInt>() with override this.Generator = Numbers.gen_PositiveInt }

static member private gen_NegativeInt = gen {
let! p = Numbers.gen_PositiveInt
return p.Opposite
}
static member NegativeIntGen() = { new Arbitrary<NegativeInt>() with override this.Generator = Numbers.gen_NegativeInt }
19 changes: 19 additions & 0 deletions SafetyFirst.Specs/ListSpec.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,18 @@ open FsCheck

open SafetyFirst
open SafetyFirst.Specs.SeqSpec
open SafetyFirst.Numbers

let upcastNE = List.NonEmpty.toList

let averageFloats' (xs:float list) = List.average' xs
let averageFloats (xs:float list) = List.average xs
let averageByFloats' (projection:_ -> float) xs = List.averageBy' projection xs
let averageByFloats (projection:_ -> float) xs = List.averageBy projection xs

let initByInts' = (fun count initializer -> List.init' count (NaturalInt.value >> initializer))
let initByIntsNonEmpty = (fun count initializer -> List.NonEmpty.initN count (NaturalInt.value >> initializer))

let arrayTransposeComparable xs =
Array.transpose xs
|> Seq.map (Array.toList) |> Seq.toList
Expand All @@ -33,6 +39,7 @@ let ``Safe List functions error whenever unsafe versions throw for all random in
errorsWheneverThrows4 List.foldBack2' List.foldBack2
errorsWheneverThrows3 List.forall2' List.forall2
errorsWheneverThrows1 List.head' List.head
errorsWheneverThrows2 initByInts' List.init
errorsWheneverThrows2 List.item' List.item
errorsWheneverThrows1 List.last' List.last
errorsWheneverThrows3 List.map2' List.map2
Expand All @@ -45,6 +52,7 @@ let ``Safe List functions error whenever unsafe versions throw for all random in
errorsWheneverThrows2 List.pick' List.pick
errorsWheneverThrows2 List.reduce' List.reduce
errorsWheneverThrows2 List.reduceBack' List.reduceBack
errorsWheneverThrows2 List.replicate' List.replicate
errorsWheneverThrows2 List.skip' List.skip
errorsWheneverThrows2 List.splitAt' List.splitAt
errorsWheneverThrows2 List.splitInto' List.splitInto
Expand All @@ -70,6 +78,7 @@ let ``Safe List functions always produce the same output as unsafe versions for
alwaysProduceSameOutput4 List.foldBack2' List.foldBack2
alwaysProduceSameOutput3 List.forall2' List.forall2
alwaysProduceSameOutput1 List.head' List.head
alwaysProduceSameOutput2 initByInts' List.init
alwaysProduceSameOutput2 List.item' List.item
alwaysProduceSameOutput1 List.last' List.last
alwaysProduceSameOutput3 List.map2' List.map2
Expand All @@ -82,6 +91,7 @@ let ``Safe List functions always produce the same output as unsafe versions for
alwaysProduceSameOutput2 List.pick' List.pick
alwaysProduceSameOutput2 List.reduce' List.reduce
alwaysProduceSameOutput2 List.reduceBack' List.reduceBack
alwaysProduceSameOutput2 List.replicate' List.replicate
alwaysProduceSameOutput2 List.skip' List.skip
alwaysProduceSameOutput2 List.splitAt' List.splitAt
alwaysProduceSameOutput2 List.splitInto' List.splitInto
Expand All @@ -92,3 +102,12 @@ let ``Safe List functions always produce the same output as unsafe versions for
alwaysProduceSameOutput2 List.zip' List.zip
alwaysProduceSameOutput3 List.zip3' List.zip3

module SafeByType =
open SeqSpec.SafeByType

[<Test>]
let ``List functions that are safe by type behave like the base functions`` () =
let (>>>) f g = (fun a b -> f a b |> g)

alwaysProduceSameOutput2 (initByIntsNonEmpty >>> upcastNE) (List.init << PositiveInt.value)
alwaysProduceSameOutput2 (List.NonEmpty.replicateN >>> upcastNE) (List.replicate << PositiveInt.value)
2 changes: 2 additions & 0 deletions SafetyFirst.Specs/SafetyFirst.Specs.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
</PropertyGroup>

<ItemGroup>
<Compile Include="Generators.fs" />
<Compile Include="OptionSpec.fs" />
<Compile Include="OptionExpressionSpec.fs" />
<Compile Include="ValueOptionSpec.fs" />
Expand All @@ -23,6 +24,7 @@
<Compile Include="ArraySpec.fs" />
<Compile Include="MapSpec.fs" />
<Compile Include="FSeqSpec.fs" />
<Compile Include="StringSpec.fs" />
<Compile Include="IEnumerableSpec.fs" />
<Compile Include="ReadmeSpec.fs" />
</ItemGroup>
Expand Down
Loading

0 comments on commit 6ac8015

Please sign in to comment.