@@ -91,3 +91,81 @@ module Immutable =
9191 let! result = TaskSeq.singleton 42 |> TaskSeq.lastOrDefault 0
9292 result |> should equal 42
9393 }
94+
95+
96+ module SideEffects =
97+ [<Fact>]
98+ let ``TaskSeq - firstOrDefault __special - case__ prove it does not read beyond first yield`` () = task {
99+ let mutable x = 42
100+
101+ let ts = taskSeq {
102+ yield x
103+ x <- x + 1 // we never get here
104+ }
105+
106+ let! fortyTwo = ts |> TaskSeq.firstOrDefault 0
107+ let! stillFortyTwo = ts |> TaskSeq.firstOrDefault 0 // the statement after 'yield' will never be reached
108+
109+ fortyTwo |> should equal 42
110+ stillFortyTwo |> should equal 42
111+ }
112+
113+ [<Fact>]
114+ let ``TaskSeq - firstOrDefault __special - case__ prove early side effect is executed`` () = task {
115+ let mutable x = 42
116+
117+ let ts = taskSeq {
118+ x <- x + 1
119+ x <- x + 1
120+ yield 42
121+ x <- x + 200 // we won't get here!
122+ }
123+
124+ let! result = ts |> TaskSeq.firstOrDefault 0
125+ result |> should equal 42
126+ x |> should equal 44
127+
128+ let! result = ts |> TaskSeq.firstOrDefault 0
129+ result |> should equal 42
130+ x |> should equal 46
131+ }
132+
133+ [<Fact>]
134+ let ``TaskSeq - lastOrDefault __special - case__ prove it reads the entire sequence`` () = task {
135+ let mutable x = 42
136+
137+ let ts = taskSeq {
138+ yield x
139+ x <- x + 1 // will be executed
140+ yield x
141+ x <- x + 1 // will be executed
142+ }
143+
144+ let! result = ts |> TaskSeq.lastOrDefault - 1
145+ result |> should equal 43
146+ x |> should equal 44
147+ }
148+
149+ [<Theory; ClassData( typeof< TestSideEffectTaskSeq>) >]
150+ let ``TaskSeq - firstOrDefault returns first item in a side - effect sequence`` variant = task {
151+ let ts = Gen.getSeqWithSideEffect variant
152+
153+ let! first = ts |> TaskSeq.firstOrDefault 0
154+ first |> should equal 1
155+
156+ // side effect: re-enumerating changes the first item
157+ let! secondFirst = ts |> TaskSeq.firstOrDefault 0
158+ secondFirst |> should not' ( equal 1 )
159+ }
160+
161+ [<Theory; ClassData( typeof< TestSideEffectTaskSeq>) >]
162+ let ``TaskSeq - lastOrDefault returns last item and exhausts the sequence`` variant = task {
163+ let ts = Gen.getSeqWithSideEffect variant
164+
165+ let! last = ts |> TaskSeq.lastOrDefault 0
166+ last |> should equal 10
167+
168+ // side effect: re-enumerating continues from mutated state
169+ let! secondLast = ts |> TaskSeq.lastOrDefault 0
170+ secondLast |> should equal 20
171+ }
0 commit comments