From 6595cf38f8d27897a2a505dc5d600dc768e0da07 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 21 Mar 2026 01:30:48 +0000 Subject: [PATCH 1/2] fix: null source raises ArgumentNullException for insertAt, removeAt, updateAt Previously, passing null to TaskSeq.insertAt, insertManyAt, removeAt, removeManyAt, and updateAt would throw a NullReferenceException from deep within the taskSeq builder, inconsistent with every other function in the library which eagerly raises ArgumentNullException via checkNonNull. - Add checkNonNull (nameof source) source to insertAt, removeAt, removeManyAt, updateAt - Add checkNonNull "values" values to insertAt when called with Many (insertManyAt) - Add null-source tests to TaskSeq.InsertAt, RemoveAt, UpdateAt test files - 5017 tests pass (4 new null-arg tests added) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- release-notes.txt | 1 + .../TaskSeq.InsertAt.Tests.fs | 12 ++++++++++++ .../TaskSeq.RemoveAt.Tests.fs | 6 ++++++ .../TaskSeq.UpdateAt.Tests.fs | 3 +++ src/FSharp.Control.TaskSeq/TaskSeqInternal.fs | 9 +++++++++ 5 files changed, 31 insertions(+) diff --git a/release-notes.txt b/release-notes.txt index 5bd4ac6d..70788402 100644 --- a/release-notes.txt +++ b/release-notes.txt @@ -2,6 +2,7 @@ Release notes: 1.0.0 + - fixes: TaskSeq.insertAt, insertManyAt, removeAt, removeManyAt, updateAt now raise ArgumentNullException (not NullReferenceException) when given a null source; insertManyAt also validates the values argument - refactor: simplify lengthBy and lengthBeforeMax to use while! and remove the redundant mutable 'go' and initial MoveNextAsync - adds TaskSeq.distinctUntilChangedWith and TaskSeq.distinctUntilChangedWithAsync, #345 - adds TaskSeq.withCancellation, #167 diff --git a/src/FSharp.Control.TaskSeq.Test/TaskSeq.InsertAt.Tests.fs b/src/FSharp.Control.TaskSeq.Test/TaskSeq.InsertAt.Tests.fs index ad8a8c83..b1983303 100644 --- a/src/FSharp.Control.TaskSeq.Test/TaskSeq.InsertAt.Tests.fs +++ b/src/FSharp.Control.TaskSeq.Test/TaskSeq.InsertAt.Tests.fs @@ -16,6 +16,18 @@ open FSharp.Control exception SideEffectPastEnd of string module EmptySeq = + [] + let ``Null source is invalid`` () = + assertNullArg <| fun () -> TaskSeq.insertAt 0 99 null + + assertNullArg + <| fun () -> TaskSeq.insertManyAt 0 TaskSeq.empty null + + [] + let ``Null values argument is invalid for insertManyAt`` () = + assertNullArg + <| fun () -> TaskSeq.insertManyAt 0 null (TaskSeq.ofList [ 1 ]) + [)>] let ``TaskSeq-insertAt(0) on empty input returns singleton`` variant = Gen.getEmptyVariant variant diff --git a/src/FSharp.Control.TaskSeq.Test/TaskSeq.RemoveAt.Tests.fs b/src/FSharp.Control.TaskSeq.Test/TaskSeq.RemoveAt.Tests.fs index 9c600524..56b332ef 100644 --- a/src/FSharp.Control.TaskSeq.Test/TaskSeq.RemoveAt.Tests.fs +++ b/src/FSharp.Control.TaskSeq.Test/TaskSeq.RemoveAt.Tests.fs @@ -16,6 +16,12 @@ open FSharp.Control exception SideEffectPastEnd of string module EmptySeq = + [] + let ``Null source is invalid`` () = + assertNullArg <| fun () -> TaskSeq.removeAt 0 null + + assertNullArg <| fun () -> TaskSeq.removeManyAt 0 1 null + [)>] let ``TaskSeq-removeAt(0) on empty input raises`` variant = fun () -> diff --git a/src/FSharp.Control.TaskSeq.Test/TaskSeq.UpdateAt.Tests.fs b/src/FSharp.Control.TaskSeq.Test/TaskSeq.UpdateAt.Tests.fs index 0bf7e9d2..ed93a489 100644 --- a/src/FSharp.Control.TaskSeq.Test/TaskSeq.UpdateAt.Tests.fs +++ b/src/FSharp.Control.TaskSeq.Test/TaskSeq.UpdateAt.Tests.fs @@ -15,6 +15,9 @@ open FSharp.Control exception SideEffectPastEnd of string module EmptySeq = + [] + let ``Null source is invalid`` () = assertNullArg <| fun () -> TaskSeq.updateAt 0 99 null + [)>] let ``TaskSeq-updateAt(0) on empty input should throw ArgumentException`` variant = fun () -> diff --git a/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs b/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs index bfcddc08..578c6edc 100644 --- a/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs +++ b/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs @@ -1369,6 +1369,12 @@ module internal TaskSeqInternal = /// InsertAt or InsertManyAt let insertAt index valueOrValues (source: TaskSeq<_>) = + checkNonNull (nameof source) source + + match valueOrValues with + | Many values -> checkNonNull "values" values + | One _ -> () + raiseCannotBeNegative (nameof index) index taskSeq { @@ -1394,6 +1400,7 @@ module internal TaskSeqInternal = } let removeAt index (source: TaskSeq<'T>) = + checkNonNull (nameof source) source raiseCannotBeNegative (nameof index) index taskSeq { @@ -1411,6 +1418,7 @@ module internal TaskSeqInternal = } let removeManyAt index count (source: TaskSeq<'T>) = + checkNonNull (nameof source) source raiseCannotBeNegative (nameof index) index taskSeq { @@ -1429,6 +1437,7 @@ module internal TaskSeqInternal = } let updateAt index value (source: TaskSeq<'T>) = + checkNonNull (nameof source) source raiseCannotBeNegative (nameof index) index taskSeq { From 282f2d218031e2306b08a61f9628b68b1eb9c62b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 21 Mar 2026 01:36:07 +0000 Subject: [PATCH 2/2] ci: trigger checks