@@ -79,6 +79,60 @@ type CustomComparersHashMapTests () =
7979 " ofSpan" , ( fun comparers -> comparers.ofSpan ( Span [| KeyValuePair ( " one" , " uno" ); KeyValuePair ( " ONE" , " abc" ) |]))
8080 |]
8181
82+ /// The members of the struct that take a sequence, by name, with the name of the sequence parameter and the member on a
83+ /// null sequence. The struct has comparers that differ from the default ones.
84+ static let nullSequenceMembers : Map < string , struct ( string * ( unit -> unit ))> =
85+ let comparers = HashMap.forComparers StringComparer.OrdinalIgnoreCase byLength
86+
87+ Map.ofArray [|
88+ " ofSeq of key/value pairs" ,
89+ struct ( " elements" ,
90+ fun () ->
91+ comparers.ofSeq ( Unchecked.defaultof< seq< KeyValuePair< string, string>>>)
92+ |> ignore)
93+ " ofSeq of reference tuples" ,
94+ struct ( " elements" ,
95+ fun () ->
96+ comparers.ofSeq ( Unchecked.defaultof< seq< string * string>>)
97+ |> ignore)
98+ " ofSeq of struct tuples" ,
99+ struct ( " elements" ,
100+ fun () ->
101+ comparers.ofSeq ( Unchecked.defaultof< seq< struct ( string * string)>>)
102+ |> ignore)
103+ " ofSeqBy" ,
104+ struct ( " source" ,
105+ fun () ->
106+ comparers.ofSeqBy id ( Unchecked.defaultof< seq< string>>)
107+ |> ignore)
108+ |]
109+
110+ /// The members of the struct that take a sequence, by name, with the name of the sequence parameter and the member on a
111+ /// default flat list that is given as the sequence. A default flat list converts to a sequence without a check and fails
112+ /// with InvalidOperationException when the sequence is enumerated. The last row gives a sequence of objects, which a
113+ /// default flat list of strings is by the covariance of seq: the element type of the sequence is not the one of the
114+ /// flat list.
115+ static let defaultSequenceMembers : Map < string , struct ( string * ( unit -> unit ))> =
116+ let comparers = HashMap.forComparers StringComparer.OrdinalIgnoreCase byLength
117+ let objectComparers : CustomComparersHashMap < obj , obj > =
118+ HashMap.forKeyComparer EqualityComparer< obj>. Default
119+ let defaultPairs = Unchecked.defaultof< FlatList< KeyValuePair< string, string>>> :> seq<_>
120+ let defaultTuples = Unchecked.defaultof< FlatList< string * string>> :> seq<_>
121+ let defaultStructTuples = Unchecked.defaultof< FlatList< struct ( string * string)>> :> seq<_>
122+ let defaultValues = Unchecked.defaultof< FlatList< string>> :> seq<_>
123+
124+ Map.ofArray [|
125+ " ofSeq of key/value pairs" , struct ( " elements" , fun () -> comparers.ofSeq defaultPairs |> ignore)
126+ " ofSeq of reference tuples" , struct ( " elements" , fun () -> comparers.ofSeq defaultTuples |> ignore)
127+ " ofSeq of struct tuples" , struct ( " elements" , fun () -> comparers.ofSeq defaultStructTuples |> ignore)
128+ " ofSeqBy" , struct ( " source" , fun () -> comparers.ofSeqBy id defaultValues |> ignore)
129+ " ofSeqBy (default flat list of strings as objects)" ,
130+ struct ( " source" ,
131+ fun () ->
132+ objectComparers.ofSeqBy id FlatListOracles.defaultStringsAsObjects
133+ |> ignore)
134+ |]
135+
82136 /// The comparer structs of the two paths of the span members, by name: the default comparer of the values wraps
83137 /// CreateRangeWithOverwrite, and any other comparer, even one that behaves like the default one, sets the bindings in a
84138 /// builder.
@@ -145,6 +199,12 @@ type CustomComparersHashMapTests () =
145199 /// test.
146200 static member EqualValueCreations = equalValueCreations.Keys
147201
202+ /// The names of the members that take a sequence and are given a null one, as the rows of their test.
203+ static member NullSequenceMembers = nullSequenceMembers.Keys
204+
205+ /// The names of the members that take a sequence and are given a default flat list, as the rows of their test.
206+ static member DefaultSequenceMembers = defaultSequenceMembers.Keys
207+
148208 [<TestMethod; DataRow " keyComparer" ; DataRow " valueComparer" >]
149209 member _. ``the constructor with both comparers rejects a null comparer`` ( nullParameter : string ) =
150210 let struct ( keyComparer , valueComparer ) = comparersWithNull nullParameter
@@ -198,6 +258,62 @@ type CustomComparersHashMapTests () =
198258
199259 Assert.AreEqual< string | null >( " keyComparer" , ex.ParamName, " HashMap.forKeyComparer must name the key comparer" )
200260
261+ [<TestMethod; DynamicData( nameof CustomComparersHashMapTests.NullSequenceMembers) >]
262+ member _. ``members reject a null sequence`` ( name : string ) =
263+ let struct ( paramName , call ) = nullSequenceMembers[ name]
264+ FlatListAssert.RejectsNull ( $" CustomComparersHashMap.%s {name}" , paramName, call)
265+
266+ [<TestMethod; DynamicData( nameof CustomComparersHashMapTests.DefaultSequenceMembers) >]
267+ member _. ``members reject a default flat list given as a sequence`` ( name : string ) =
268+ // The exception names the parameter of the member, not the one of the BCL member that it would have called
269+ let struct ( paramName , call ) = defaultSequenceMembers[ name]
270+ FlatListAssert.RejectsNull ( $" CustomComparersHashMap.%s {name}" , paramName, call)
271+
272+ [<TestMethod>]
273+ member _. ``members take a flat list that is not default as a sequence, also one of strings as a sequence of objects`` () =
274+ let flatList ( elements : 'T array ) = FlatList.ofArray elements :> seq< 'T>
275+ let comparers = HashMap.forKeyComparer StringComparer.OrdinalIgnoreCase
276+
277+ let sortedBindings ( table : HashMap < string , string >) =
278+ HashMap.toArray table
279+ |> Array.sortBy ( fun struct ( key , _ ) -> key)
280+
281+ CollectionAssert.AreEqual (
282+ [| struct ( " a" , " b" ) |],
283+ sortedBindings ( comparers.ofSeq ( flatList [| KeyValuePair ( " a" , " b" ) |])),
284+ " ofSeq must take the key/value pairs of a flat list"
285+ )
286+
287+ CollectionAssert.AreEqual (
288+ [| struct ( " a" , " b" ) |],
289+ sortedBindings ( comparers.ofSeq ( flatList [| ( " a" , " b" ) |])),
290+ " ofSeq must take the reference tuples of a flat list"
291+ )
292+
293+ CollectionAssert.AreEqual (
294+ [| struct ( " a" , " b" ) |],
295+ sortedBindings ( comparers.ofSeq ( flatList [| struct ( " a" , " b" ) |])),
296+ " ofSeq must take the struct tuples of a flat list"
297+ )
298+
299+ CollectionAssert.AreEqual (
300+ [| struct ( " ab" , " ab" ) |],
301+ sortedBindings ( comparers.ofSeqBy id ( flatList [| " ab" |])),
302+ " ofSeqBy must take the elements of a flat list"
303+ )
304+
305+ // A flat list of strings is a sequence of objects, which a type test for the flat list of objects does not see
306+ let objectComparers : CustomComparersHashMap < obj , obj > =
307+ HashMap.forKeyComparer EqualityComparer< obj>. Default
308+ let widened = FlatListOracles.stringsAsObjects ( FlatList.ofArray [| " ab" |])
309+
310+ CollectionAssert.AreEqual (
311+ [| " ab" :> obj |],
312+ HashMap.keys ( objectComparers.ofSeqBy id widened)
313+ |> Seq.toArray,
314+ " ofSeqBy must take the elements of a flat list of strings as objects"
315+ )
316+
201317 [<TestMethod>]
202318 member _. ``forComparers holds both comparers`` () =
203319 let comparers = HashMap.forComparers StringComparer.OrdinalIgnoreCase byLength
0 commit comments