Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Increase surface area: TaskSeq.length, lengthBy and lengthByAsync #53

Merged
merged 5 commits into from
Oct 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/FSharpy.TaskSeq.Test/FSharpy.TaskSeq.Test.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<Compile Include="TaskSeq.Item.Tests.fs" />
<Compile Include="TaskSeq.Iter.Tests.fs" />
<Compile Include="TaskSeq.Last.Tests.fs" />
<Compile Include="TaskSeq.Length.Tests.fs" />
<Compile Include="TaskSeq.Map.Tests.fs" />
<Compile Include="TaskSeq.Pick.Tests.fs" />
<Compile Include="TaskSeq.Zip.Tests.fs" />
Expand Down
88 changes: 65 additions & 23 deletions src/FSharpy.TaskSeq.Test/TaskSeq.ExactlyOne.Tests.fs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module FSharpy.Tests.Head
module FSharpy.Tests.ExactlyOne

open System
open Xunit
Expand All @@ -9,49 +9,91 @@ open FSharpy


[<Fact>]
let ``TaskSeq-head throws on empty sequences`` () = task {
fun () -> TaskSeq.empty<string> |> TaskSeq.head |> Task.ignore
let ``TaskSeq-exactlyOne throws on empty sequences`` () = task {
fun () -> TaskSeq.empty<string> |> TaskSeq.exactlyOne |> Task.ignore
|> should throwAsyncExact typeof<ArgumentException>
}

[<Fact>]
let ``TaskSeq-head throws on empty sequences - variant`` () = task {
fun () -> taskSeq { do () } |> TaskSeq.head |> Task.ignore
let ``TaskSeq-exactlyOne throws on empty sequences - variant`` () = task {
fun () -> taskSeq { do () } |> TaskSeq.exactlyOne |> Task.ignore
|> should throwAsyncExact typeof<ArgumentException>
}

[<Fact>]
let ``TaskSeq-tryHead returns None on empty sequences`` () = task {
let! nothing = TaskSeq.empty<string> |> TaskSeq.tryHead
let ``TaskSeq-tryExactlyOne returns None on empty sequences`` () = task {
let! nothing = TaskSeq.empty<string> |> TaskSeq.tryExactlyOne
nothing |> should be None'
}

[<Fact>]
let ``TaskSeq-head gets the first item in a longer sequence`` () = task {
let! head = createDummyTaskSeqWith 50L<µs> 1000L<µs> 50 |> TaskSeq.head
let ``TaskSeq-exactlyOne throws for a sequence of length = two`` () = task {
fun () ->
taskSeq {
yield 1
yield 2
}
|> TaskSeq.exactlyOne
|> Task.ignore
|> should throwAsyncExact typeof<ArgumentException>
}

[<Fact>]
let ``TaskSeq-exactlyOne throws for a sequence of length = two - variant`` () = task {
fun () ->
createDummyTaskSeqWith 50L<µs> 1000L<µs> 2
|> TaskSeq.exactlyOne
|> Task.ignore
|> should throwAsyncExact typeof<ArgumentException>
}


[<Fact>]
let ``TaskSeq-exactlyOne throws with a larger sequence`` () = task {
fun () ->
createDummyTaskSeqWith 50L<µs> 300L<µs> 200
|> TaskSeq.exactlyOne
|> Task.ignore
|> should throwAsyncExact typeof<ArgumentException>
}

head |> should equal 1
[<Fact>]
let ``TaskSeq-tryExactlyOne returns None with a larger sequence`` () = task {
let! nothing =
createDummyTaskSeqWith 50L<µs> 300L<µs> 20
|> TaskSeq.tryExactlyOne

nothing |> should be None'
}

[<Fact>]
let ``TaskSeq-head gets the only item in a singleton sequence`` () = task {
let! head = taskSeq { yield 10 } |> TaskSeq.head
head |> should equal 10
let ``TaskSeq-exactlyOne gets the only item in a singleton sequence`` () = task {
let! exactlyOne = taskSeq { yield 10 } |> TaskSeq.exactlyOne
exactlyOne |> should equal 10
}

[<Fact>]
let ``TaskSeq-tryHead gets the first item in a longer sequence`` () = task {
let! head =
createDummyTaskSeqWith 50L<µs> 1000L<µs> 50
|> TaskSeq.tryHead
let ``TaskSeq-tryExactlyOne gets the only item in a singleton sequence`` () = task {
let! exactlyOne = taskSeq { yield 10 } |> TaskSeq.tryExactlyOne
exactlyOne |> should be Some'
exactlyOne |> should equal (Some 10)
}

[<Fact>]
let ``TaskSeq-exactlyOne gets the only item in a singleton sequence - variant`` () = task {
let! exactlyOne =
createLongerDummyTaskSeq 50<ms> 300<ms> 1
|> TaskSeq.exactlyOne

head |> should be Some'
head |> should equal (Some 1)
exactlyOne |> should equal 1
}

[<Fact>]
let ``TaskSeq-tryHead gets the only item in a singleton sequence`` () = task {
let! head = taskSeq { yield 10 } |> TaskSeq.tryHead
head |> should be Some'
head |> should equal (Some 10)
let ``TaskSeq-tryExactlyOne gets the only item in a singleton sequence - variant`` () = task {
let! exactlyOne =
createLongerDummyTaskSeq 50<ms> 300<ms> 1
|> TaskSeq.tryExactlyOne

exactlyOne |> should be Some'
exactlyOne |> should equal (Some 1)
}
88 changes: 23 additions & 65 deletions src/FSharpy.TaskSeq.Test/TaskSeq.Head.Tests.fs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module FSharpy.Tests.ExactlyOne
module FSharpy.Tests.Head

open System
open Xunit
Expand All @@ -9,91 +9,49 @@ open FSharpy


[<Fact>]
let ``TaskSeq-exactlyOne throws on empty sequences`` () = task {
fun () -> TaskSeq.empty<string> |> TaskSeq.exactlyOne |> Task.ignore
let ``TaskSeq-head throws on empty sequences`` () = task {
fun () -> TaskSeq.empty<string> |> TaskSeq.head |> Task.ignore
|> should throwAsyncExact typeof<ArgumentException>
}

[<Fact>]
let ``TaskSeq-exactlyOne throws on empty sequences - variant`` () = task {
fun () -> taskSeq { do () } |> TaskSeq.exactlyOne |> Task.ignore
let ``TaskSeq-head throws on empty sequences - variant`` () = task {
fun () -> taskSeq { do () } |> TaskSeq.head |> Task.ignore
|> should throwAsyncExact typeof<ArgumentException>
}

[<Fact>]
let ``TaskSeq-tryExactlyOne returns None on empty sequences`` () = task {
let! nothing = TaskSeq.empty<string> |> TaskSeq.tryExactlyOne
let ``TaskSeq-tryHead returns None on empty sequences`` () = task {
let! nothing = TaskSeq.empty<string> |> TaskSeq.tryHead
nothing |> should be None'
}

[<Fact>]
let ``TaskSeq-exactlyOne throws for a sequence of length = two`` () = task {
fun () ->
taskSeq {
yield 1
yield 2
}
|> TaskSeq.exactlyOne
|> Task.ignore
|> should throwAsyncExact typeof<ArgumentException>
}

[<Fact>]
let ``TaskSeq-exactlyOne throws for a sequence of length = two - variant`` () = task {
fun () ->
createDummyTaskSeqWith 50L<µs> 1000L<µs> 2
|> TaskSeq.exactlyOne
|> Task.ignore
|> should throwAsyncExact typeof<ArgumentException>
}


[<Fact>]
let ``TaskSeq-exactlyOne throws with a larger sequence`` () = task {
fun () ->
createDummyTaskSeqWith 50L<µs> 300L<µs> 200
|> TaskSeq.exactlyOne
|> Task.ignore
|> should throwAsyncExact typeof<ArgumentException>
}
let ``TaskSeq-head gets the first item in a longer sequence`` () = task {
let! head = createDummyTaskSeqWith 50L<µs> 1000L<µs> 50 |> TaskSeq.head

[<Fact>]
let ``TaskSeq-tryExactlyOne returns None with a larger sequence`` () = task {
let! nothing =
createDummyTaskSeqWith 50L<µs> 300L<µs> 20
|> TaskSeq.tryExactlyOne

nothing |> should be None'
head |> should equal 1
}

[<Fact>]
let ``TaskSeq-exactlyOne gets the only item in a singleton sequence`` () = task {
let! exactlyOne = taskSeq { yield 10 } |> TaskSeq.exactlyOne
exactlyOne |> should equal 10
let ``TaskSeq-head gets the only item in a singleton sequence`` () = task {
let! head = taskSeq { yield 10 } |> TaskSeq.head
head |> should equal 10
}

[<Fact>]
let ``TaskSeq-tryExactlyOne gets the only item in a singleton sequence`` () = task {
let! exactlyOne = taskSeq { yield 10 } |> TaskSeq.tryExactlyOne
exactlyOne |> should be Some'
exactlyOne |> should equal (Some 10)
}

[<Fact>]
let ``TaskSeq-exactlyOne gets the only item in a singleton sequence - variant`` () = task {
let! exactlyOne =
createLongerDummyTaskSeq 50<ms> 300<ms> 1
|> TaskSeq.exactlyOne
let ``TaskSeq-tryHead gets the first item in a longer sequence`` () = task {
let! head =
createDummyTaskSeqWith 50L<µs> 1000L<µs> 50
|> TaskSeq.tryHead

exactlyOne |> should equal 1
head |> should be Some'
head |> should equal (Some 1)
}

[<Fact>]
let ``TaskSeq-tryExactlyOne gets the only item in a singleton sequence - variant`` () = task {
let! exactlyOne =
createLongerDummyTaskSeq 50<ms> 300<ms> 1
|> TaskSeq.tryExactlyOne

exactlyOne |> should be Some'
exactlyOne |> should equal (Some 1)
let ``TaskSeq-tryHead gets the only item in a singleton sequence`` () = task {
let! head = taskSeq { yield 10 } |> TaskSeq.tryHead
head |> should be Some'
head |> should equal (Some 10)
}
41 changes: 16 additions & 25 deletions src/FSharpy.TaskSeq.Test/TaskSeq.Last.Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8,45 +8,36 @@ open FsToolkit.ErrorHandling
open FSharpy


[<Fact>]
let ``TaskSeq-last throws on empty sequences`` () = task {
fun () -> TaskSeq.empty<string> |> TaskSeq.last |> Task.ignore
|> should throwAsyncExact typeof<ArgumentException>
}

[<Fact>]
let ``TaskSeq-last throws on empty sequences - variant`` () = task {
fun () -> taskSeq { do () } |> TaskSeq.last |> Task.ignore
[<Theory; ClassData(typeof<TestEmptyVariants>)>]
let ``TaskSeq-last throws on empty sequences`` variant = task {
fun () -> getEmptyVariant variant |> TaskSeq.last |> Task.ignore
|> should throwAsyncExact typeof<ArgumentException>
}

[<Fact>]
let ``TaskSeq-tryLast returns None on empty sequences`` () = task {
let! nothing = TaskSeq.empty<string> |> TaskSeq.tryLast
[<Theory; ClassData(typeof<TestEmptyVariants>)>]
let ``TaskSeq-tryLast returns None on empty sequences`` variant = task {
let! nothing = getEmptyVariant variant |> TaskSeq.tryLast
nothing |> should be None'
}

[<Fact>]
let ``TaskSeq-last gets the last item in a longer sequence`` () = task {
let! last = createDummyTaskSeqWith 50L<µs> 1000L<µs> 50 |> TaskSeq.last

last |> should equal 50
[<Theory; ClassData(typeof<TestSmallVariants>)>]
let ``TaskSeq-last gets the last item in a longer sequence`` variant = task {
let! last = getSmallVariant variant |> TaskSeq.last
last |> should equal 10
}

[<Fact>]
let ``TaskSeq-last gets the only item in a singleton sequence`` () = task {
let! last = taskSeq { yield 10 } |> TaskSeq.last
last |> should equal 10
let! last = taskSeq { yield 42 } |> TaskSeq.last
last |> should equal 42
}

[<Fact>]
let ``TaskSeq-tryLast gets the last item in a longer sequence`` () = task {
let! last =
createDummyTaskSeqWith 50L<µs> 1000L<µs> 50
|> TaskSeq.tryLast
[<Theory; ClassData(typeof<TestSmallVariants>)>]
let ``TaskSeq-tryLast gets the last item in a longer sequence`` variant = task {
let! last = getSmallVariant variant |> TaskSeq.tryLast

last |> should be Some'
last |> should equal (Some 50)
last |> should equal (Some 10)
}

[<Fact>]
Expand Down
76 changes: 76 additions & 0 deletions src/FSharpy.TaskSeq.Test/TaskSeq.Length.Tests.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
module FSharpy.Tests.Length

open System
open Xunit
open FsUnit.Xunit
open FsToolkit.ErrorHandling

open FSharpy


[<Theory; ClassData(typeof<TestEmptyVariants>)>]
let ``TaskSeq-length returns zero on empty sequences`` variant = task {
let! len = getEmptyVariant variant |> TaskSeq.length
len |> should equal 0
}

[<Theory; ClassData(typeof<TestEmptyVariants>)>]
let ``TaskSeq-lengthBy returns zero on empty sequences`` variant = task {
let! len = getEmptyVariant variant |> TaskSeq.lengthBy (fun _ -> true)
len |> should equal 0
}

[<Theory; ClassData(typeof<TestEmptyVariants>)>]
let ``TaskSeq-lengthByAsync returns zero on empty sequences`` variant = task {
let! len =
getEmptyVariant variant
|> TaskSeq.lengthByAsync (Task.apply (fun _ -> true))

len |> should equal 0
}

[<Theory; ClassData(typeof<TestSmallVariants>)>]
let ``TaskSeq-length returns proper length`` variant = task {
let! len = getSmallVariant variant |> TaskSeq.length
len |> should equal 10
}

[<Theory; ClassData(typeof<TestSmallVariants>)>]
let ``TaskSeq-lengthBy returns proper length`` variant = task {
let! len = getSmallVariant variant |> TaskSeq.lengthBy (fun _ -> true)
len |> should equal 10
}

[<Theory; ClassData(typeof<TestSmallVariants>)>]
let ``TaskSeq-lengthByAsync returns proper length`` variant = task {
let! len =
getSmallVariant variant
|> TaskSeq.lengthByAsync (Task.apply (fun _ -> true))

len |> should equal 10
}

[<Theory; ClassData(typeof<TestSmallVariants>)>]
let ``TaskSeq-lengthBy returns proper length when filtering`` variant = task {
let run f = getSmallVariant variant |> TaskSeq.lengthBy f
let! len = run (fun x -> x % 3 = 0)
len |> should equal 3 // [3; 6; 9]
let! len = run (fun x -> x % 3 = 1)
len |> should equal 4 // [1; 4; 7; 10]
let! len = run (fun x -> x % 3 = 2)
len |> should equal 3 // [2; 5; 8]
}

[<Theory; ClassData(typeof<TestSmallVariants>)>]
let ``TaskSeq-lengthByAsync returns proper length when filtering`` variant = task {
let run f =
getSmallVariant variant
|> TaskSeq.lengthByAsync (Task.apply f)

let! len = run (fun x -> x % 3 = 0)
len |> should equal 3 // [3; 6; 9]
let! len = run (fun x -> x % 3 = 1)
len |> should equal 4 // [1; 4; 7; 10]
let! len = run (fun x -> x % 3 = 2)
len |> should equal 3 // [2; 5; 8]
}
Loading