Skip to content

Commit c487fb3

Browse files
xperiandriclaude
andcommitted
fixup! test: shared contracts of the sequence-like modules, run for FlatList
A default flat list given as a sequence throws `ArgumentNullException` that names the parameter: `concat`, `transpose`, `insertManyAt` and `except` are the rows of one test, and `addRange` and `for` have a test each. Rows and tests pin the order of the checks as well: `insertManyAt` checks its source first and its index before the values, and `except` checks the items before the array and also for an empty input, as the FSharp.Core functions do. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
1 parent 377bf02 commit c487fb3

3 files changed

Lines changed: 113 additions & 6 deletions

File tree

‎tests/FSharp.Collections.Immutable.Tests/FlatList/FlatListBuilderTests.fs‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,23 @@ type FlatListBuilderTests () =
2020
let array = FlatList.build (fun builder -> builder.AddRange Inputs.Several)
2121
CollectionAssert.AreEqual (Inputs.Several, FlatList.toArray array, "FlatList.build must return the added elements")
2222

23+
[<TestMethod>]
24+
member _.``addRange rejects a default flat list, which it takes as a sequence`` () =
25+
let ex =
26+
Assert.ThrowsExactly<ArgumentNullException>(
27+
Action (fun () ->
28+
FlatListBuilder.addRange (Unchecked.defaultof<FlatList<int>> :> seq<_>) (FlatList.builder<int>())
29+
|> ignore
30+
),
31+
"FlatListBuilder.addRange must reject a default flat list"
32+
)
33+
34+
Assert.AreEqual<string | null>(
35+
"values",
36+
ex.ParamName,
37+
"FlatListBuilder.addRange must name the parameter of the default flat list"
38+
)
39+
2340
[<TestMethod>]
2441
member _.``builder starts empty`` () =
2542
let builder = FlatList.builder<int>()

‎tests/FSharp.Collections.Immutable.Tests/FlatList/FlatListComputationExpressionTests.fs‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,22 @@ type FlatListComputationExpressionTests () =
7777

7878
CollectionAssert.AreEqual ([| 10; 20; 30 |], FlatList.toArray array, "flatList must run the body of for for each item")
7979

80+
[<TestMethod>]
81+
member _.``for rejects a default flat list, which it takes as a sequence`` () =
82+
let ex =
83+
Assert.ThrowsExactly<ArgumentNullException>(
84+
Action (fun () ->
85+
flatList {
86+
for item in defaultArray do
87+
yield item
88+
}
89+
|> ignore
90+
),
91+
"flatList must reject a default flat list in for"
92+
)
93+
94+
Assert.AreEqual<string | null>("source", ex.ParamName, "flatList must name the parameter of the default flat list")
95+
8096
[<TestMethod>]
8197
member _.``while adds the elements while the guard holds`` () =
8298
let mutable count = 0

‎tests/FSharp.Collections.Immutable.Tests/FlatList/FlatListTests.fs‎

Lines changed: 80 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@ type FlatListTests () =
1717
/// The array under a flat list, to tell whether two flat lists share their storage.
1818
static let underlying (array : FlatList<int>) = ImmutableCollectionsMarshal.AsArray array
1919

20+
/// Asserts that an action rejects a default flat list with an ArgumentNullException that names the parameter.
21+
static let assertRejectsDefault (name : string) (paramName : string) (actual : unit -> unit) =
22+
let ex =
23+
Assert.ThrowsExactly<ArgumentNullException>(Action actual, $"FlatList.%s{name} must reject a default flat list")
24+
25+
Assert.AreEqual<string | null>(
26+
paramName,
27+
ex.ParamName,
28+
$"FlatList.%s{name} must name the parameter of the default flat list"
29+
)
30+
2031
/// The functions that mirror an Array function, by name, with that function on a null array and the function on a
2132
/// default flat list. The rows of the test are the names: a function has no readable name in a row.
2233
static let arrayRejections =
@@ -209,6 +220,52 @@ type FlatListTests () =
209220
|> Array.map (fun struct (name, paramName, actual) -> name, struct (paramName, actual))
210221
|> Map.ofArray
211222

223+
/// The functions that take a sequence, by name, with the parameter that names a default flat list given as the
224+
/// sequence and the function on such a flat list. A default flat list converts to a sequence without a check and
225+
/// fails when the sequence is enumerated, so the other inputs are valid and the function would enumerate it.
226+
static let sequenceRejections =
227+
let defaultOuter = Unchecked.defaultof<FlatList<FlatList<int>>>
228+
229+
[|
230+
struct (nameof FlatList.concat, "arrays", (fun () -> FlatList.concat (defaultOuter :> seq<_>) |> ignore))
231+
struct (nameof FlatList.transpose, "arrays", (fun () -> FlatList.transpose (defaultOuter :> seq<_>) |> ignore))
232+
struct (nameof FlatList.insertManyAt,
233+
"values",
234+
(fun () ->
235+
FlatList.insertManyAt 1 (defaultArray :> seq<_>) (FlatList.ofArray Inputs.Several)
236+
|> ignore
237+
))
238+
// Array.insertManyAt checks the source before the values
239+
struct ($"%s{nameof FlatList.insertManyAt} (default source)",
240+
"source",
241+
(fun () ->
242+
FlatList.insertManyAt 1 (defaultArray :> seq<_>) defaultArray
243+
|> ignore
244+
))
245+
struct (nameof FlatList.except,
246+
"itemsToExclude",
247+
(fun () ->
248+
FlatList.except (defaultArray :> seq<_>) (FlatList.ofArray Inputs.Several)
249+
|> ignore
250+
))
251+
// Array.except returns an empty input without enumerating the items, but it checks the items for null first
252+
struct ($"%s{nameof FlatList.except} (empty array)",
253+
"itemsToExclude",
254+
(fun () ->
255+
FlatList.except (defaultArray :> seq<_>) FlatList.empty<int>
256+
|> ignore
257+
))
258+
// Array.except checks the items to exclude before the array
259+
struct ($"%s{nameof FlatList.except} (default array)",
260+
"itemsToExclude",
261+
(fun () ->
262+
FlatList.except (defaultArray :> seq<_>) defaultArray
263+
|> ignore
264+
))
265+
|]
266+
|> Array.map (fun struct (name, paramName, actual) -> name, struct (paramName, actual))
267+
|> Map.ofArray
268+
212269
/// The functions that take a range, by name, on the whole range of the input with several elements.
213270
static let wholeRanges : Map<string, FlatList<int> -> FlatList<int>> =
214271
Map.ofArray [|
@@ -245,6 +302,9 @@ type FlatListTests () =
245302
/// The names of the functions without an Array counterpart, as the rows of their test.
246303
static member OtherRejections = otherRejections.Keys
247304

305+
/// The names of the functions that take a sequence, as the rows of the test of a default flat list given as the sequence.
306+
static member SequenceRejections = sequenceRejections.Keys
307+
248308
/// The names of the functions that take a range, as the rows of the test of the whole range.
249309
static member WholeRanges = wholeRanges.Keys
250310

@@ -287,14 +347,28 @@ type FlatListTests () =
287347
[<TestMethod; DynamicData(nameof FlatListTests.OtherRejections)>]
288348
member _.``functions without an Array counterpart reject a default flat list`` (name : string) =
289349
let struct (paramName, actual) = otherRejections[name]
350+
assertRejectsDefault name paramName actual
290351

291-
let ex =
292-
Assert.ThrowsExactly<ArgumentNullException>(Action actual, $"FlatList.%s{name} must reject a default flat list")
352+
[<TestMethod; DynamicData(nameof FlatListTests.SequenceRejections)>]
353+
member _.``functions that take a sequence reject a default flat list given as the sequence`` (name : string) =
354+
let struct (paramName, actual) = sequenceRejections[name]
355+
assertRejectsDefault name paramName actual
293356

294-
Assert.AreEqual<string | null>(
295-
paramName,
296-
ex.ParamName,
297-
$"FlatList.%s{name} must name the parameter of the default flat list"
357+
[<TestMethod; DataRow -1; DataRow 9>]
358+
member _.``insertManyAt rejects an index out of range before default values as Array.insertManyAt does`` (index : int) =
359+
// The input has 8 elements, so the indices -1 and 9 are out of range. Array.insertManyAt checks the index
360+
// before it enumerates the values
361+
ExceptionAssert.Same (
362+
id,
363+
(fun () ->
364+
Array.insertManyAt index Unchecked.defaultof<seq<int>> Inputs.Several
365+
|> ignore
366+
),
367+
(fun () ->
368+
FlatList.insertManyAt index (defaultArray :> seq<_>) (FlatList.ofArray Inputs.Several)
369+
|> ignore
370+
),
371+
"FlatList.insertManyAt must check the index before the values as Array.insertManyAt does"
298372
)
299373

300374
[<TestMethod>]

0 commit comments

Comments
 (0)