diff --git a/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj b/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj
index ff7ae5e..d625d93 100644
--- a/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj
+++ b/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj
@@ -24,6 +24,7 @@
+
diff --git a/src/FSharp.Control.TaskSeq.Test/TaskSeq.Forall.Tests.fs b/src/FSharp.Control.TaskSeq.Test/TaskSeq.Forall.Tests.fs
new file mode 100644
index 0000000..04a652f
--- /dev/null
+++ b/src/FSharp.Control.TaskSeq.Test/TaskSeq.Forall.Tests.fs
@@ -0,0 +1,228 @@
+module TaskSeq.Tests.Exists
+
+open Xunit
+open FsUnit.Xunit
+
+open FSharp.Control
+
+//
+// TaskSeq.exists
+// TaskSeq.existsAsyncc
+//
+
+module EmptySeq =
+ []
+ let ``Null source is invalid`` () =
+ assertNullArg
+ <| fun () -> TaskSeq.exists (fun _ -> false) null
+
+ assertNullArg
+ <| fun () -> TaskSeq.existsAsync (fun _ -> Task.fromResult false) null
+
+ [)>]
+ let ``TaskSeq-exists returns false`` variant =
+ Gen.getEmptyVariant variant
+ |> TaskSeq.exists ((=) 12)
+ |> Task.map (should be False)
+
+ [)>]
+ let ``TaskSeq-existsAsync returns false`` variant =
+ Gen.getEmptyVariant variant
+ |> TaskSeq.existsAsync (fun x -> task { return x = 12 })
+ |> Task.map (should be False)
+
+module Immutable =
+ [)>]
+ let ``TaskSeq-exists sad path returns false`` variant =
+ Gen.getSeqImmutable variant
+ |> TaskSeq.exists ((=) 0)
+ |> Task.map (should be False)
+
+ [)>]
+ let ``TaskSeq-existsAsync sad path return false`` variant =
+ Gen.getSeqImmutable variant
+ |> TaskSeq.existsAsync (fun x -> task { return x = 0 })
+ |> Task.map (should be False)
+
+ [)>]
+ let ``TaskSeq-exists happy path middle of seq`` variant =
+ Gen.getSeqImmutable variant
+ |> TaskSeq.exists (fun x -> x < 6 && x > 4)
+ |> Task.map (should be True)
+
+ [)>]
+ let ``TaskSeq-existsAsync happy path middle of seq`` variant =
+ Gen.getSeqImmutable variant
+ |> TaskSeq.existsAsync (fun x -> task { return x < 6 && x > 4 })
+ |> Task.map (should be True)
+
+ [)>]
+ let ``TaskSeq-exists happy path first item of seq`` variant =
+ Gen.getSeqImmutable variant
+ |> TaskSeq.exists ((=) 1)
+ |> Task.map (should be True)
+
+ [)>]
+ let ``TaskSeq-existsAsync happy path first item of seq`` variant =
+ Gen.getSeqImmutable variant
+ |> TaskSeq.existsAsync (fun x -> task { return x = 1 })
+ |> Task.map (should be True)
+
+ [)>]
+ let ``TaskSeq-exists happy path last item of seq`` variant =
+ Gen.getSeqImmutable variant
+ |> TaskSeq.exists ((=) 10)
+ |> Task.map (should be True)
+
+ [)>]
+ let ``TaskSeq-existsAsync happy path last item of seq`` variant =
+ Gen.getSeqImmutable variant
+ |> TaskSeq.existsAsync (fun x -> task { return x = 10 })
+ |> Task.map (should be True)
+
+module SideEffects =
+ [)>]
+ let ``TaskSeq-exists KeyNotFoundException only sometimes for mutated state`` variant = task {
+ let ts = Gen.getSeqWithSideEffect variant
+ let finder = (=) 11
+
+ // first: false
+ let! found = TaskSeq.exists finder ts
+ found |> should be False
+
+ // find again: found now, because of side effects
+ let! found = TaskSeq.exists finder ts
+ found |> should be True
+
+ // find once more: false
+ let! found = TaskSeq.exists finder ts
+ found |> should be False
+ }
+
+ [)>]
+ let ``TaskSeq-existsAsync KeyNotFoundException only sometimes for mutated state`` variant = task {
+ let ts = Gen.getSeqWithSideEffect variant
+ let finder x = task { return x = 11 }
+
+ // first: false
+ let! found = TaskSeq.existsAsync finder ts
+ found |> should be False
+
+ // find again: found now, because of side effects
+ let! found = TaskSeq.existsAsync finder ts
+ found |> should be True
+
+ // find once more: false
+ let! found = TaskSeq.existsAsync finder ts
+ found |> should be False
+ }
+
+ []
+ let ``TaskSeq-exists _specialcase_ prove we don't read past the found item`` () = task {
+ let mutable i = 0
+
+ let ts = taskSeq {
+ for _ in 0..9 do
+ i <- i + 1
+ yield i
+ }
+
+ let! found = ts |> TaskSeq.exists ((=) 3)
+ found |> should be True
+ i |> should equal 3 // only partial evaluation!
+
+ // find next item. We do get a new iterator, but mutable state is now starting at '3', so first item now returned is '4'.
+ let! found = ts |> TaskSeq.exists ((=) 4)
+ found |> should be True
+ i |> should equal 4 // only partial evaluation!
+ }
+
+ []
+ let ``TaskSeq-existsAsync _specialcase_ prove we don't read past the found item`` () = task {
+ let mutable i = 0
+
+ let ts = taskSeq {
+ for _ in 0..9 do
+ i <- i + 1
+ yield i
+ }
+
+ let! found = ts |> TaskSeq.existsAsync (fun x -> task { return x = 3 })
+ found |> should be True
+ i |> should equal 3 // only partial evaluation!
+
+ // find next item. We do get a new iterator, but mutable state is now starting at '3', so first item now returned is '4'.
+ let! found = ts |> TaskSeq.existsAsync (fun x -> task { return x = 4 })
+ found |> should be True
+ i |> should equal 4
+ }
+
+ []
+ let ``TaskSeq-exists _specialcase_ prove we don't read past the found item v2`` () = task {
+ let mutable i = 0
+
+ let ts = taskSeq {
+ yield 42
+ i <- i + 1
+ i <- i + 1
+ }
+
+ let! found = ts |> TaskSeq.exists ((=) 42)
+ found |> should be True
+ i |> should equal 0 // because no MoveNext after found item, the last statements are not executed
+ }
+
+ []
+ let ``TaskSeq-existsAsync _specialcase_ prove we don't read past the found item v2`` () = task {
+ let mutable i = 0
+
+ let ts = taskSeq {
+ yield 42
+ i <- i + 1
+ i <- i + 1
+ }
+
+ let! found = ts |> TaskSeq.existsAsync (fun x -> task { return x = 42 })
+ found |> should be True
+ i |> should equal 0 // because no MoveNext after found item, the last statements are not executed
+ }
+
+ []
+ let ``TaskSeq-exists _specialcase_ prove statement after yield is not evaluated`` () = task {
+ let mutable i = 0
+
+ let ts = taskSeq {
+ for _ in 0..9 do
+ yield i
+ i <- i + 1
+ }
+
+ let! found = ts |> TaskSeq.exists ((=) 0)
+ found |> should be True
+ i |> should equal 0 // notice that it should be one higher if the statement after 'yield' is evaluated
+
+ // find some next item. We do get a new iterator, but mutable state is now starting at '1'
+ let! found = ts |> TaskSeq.exists ((=) 4)
+ found |> should be True
+ i |> should equal 4 // only partial evaluation!
+ }
+
+ []
+ let ``TaskSeq-existsAsync _specialcase_ prove statement after yield is not evaluated`` () = task {
+ let mutable i = 0
+
+ let ts = taskSeq {
+ for _ in 0..9 do
+ yield i
+ i <- i + 1
+ }
+
+ let! found = ts |> TaskSeq.existsAsync (fun x -> task { return x = 0 })
+ found |> should be True
+ i |> should equal 0 // notice that it should be one higher if the statement after 'yield' is evaluated
+
+ // find some next item. We do get a new iterator, but mutable state is now starting at '1'
+ let! found = ts |> TaskSeq.existsAsync (fun x -> task { return x = 4 })
+ found |> should be True
+ i |> should equal 4 // only partial evaluation!
+ }