@@ -72,15 +72,39 @@ extension Test.Case {
7272 /// - Parameters:
7373 /// - collection: The collection of argument values for which test cases
7474 /// should be generated.
75+ /// - parameters: The parameters of the test function for which test cases
76+ /// should be generated.
7577 /// - testFunction: The test function to which each generated test case
7678 /// passes an argument value from `collection`.
79+ ///
80+ /// This initializer is disfavored since it relies on `Mirror` to
81+ /// de-structure elements of tuples. Other initializers which are
82+ /// specialized to handle collections of tuple types more efficiently should
83+ /// be preferred.
84+ @_disfavoredOverload
7785 init (
7886 arguments collection: S ,
87+ parameters: [ Test . ParameterInfo ] ,
7988 testFunction: @escaping @Sendable ( S . Element) async throws -> Void
8089 ) where S: Collection {
81- self . init ( sequence: collection) { element in
82- Test . Case ( arguments: [ element] ) {
83- try await testFunction ( element)
90+ if parameters. count > 1 {
91+ self . init ( sequence: collection) { element in
92+ let mirror = Mirror ( reflecting: element)
93+ let values : [ any Sendable ] = if mirror. displayStyle == . tuple {
94+ mirror. children. map { unsafeBitCast ( $0. value, to: ( any Sendable ) . self) }
95+ } else {
96+ [ element]
97+ }
98+
99+ return Test . Case ( values: values, parameters: parameters) {
100+ try await testFunction ( element)
101+ }
102+ }
103+ } else {
104+ self . init ( sequence: collection) { element in
105+ Test . Case ( values: [ element] , parameters: parameters) {
106+ try await testFunction ( element)
107+ }
84108 }
85109 }
86110 }
@@ -93,34 +117,136 @@ extension Test.Case {
93117 /// cases should be generated.
94118 /// - collection2: The second collection of argument values for which test
95119 /// cases should be generated.
120+ /// - parameters: The parameters of the test function for which test cases
121+ /// should be generated.
96122 /// - testFunction: The test function to which each generated test case
97123 /// passes an argument value from `collection`.
98124 init < C1, C2> (
99125 arguments collection1: C1 , _ collection2: C2 ,
126+ parameters: [ Test . ParameterInfo ] ,
100127 testFunction: @escaping @Sendable ( C1 . Element, C2 . Element) async throws -> Void
101128 ) where S == CartesianProduct < C1 , C2 > {
102129 self . init ( sequence: cartesianProduct ( collection1, collection2) ) { element in
103- Test . Case ( arguments : [ element. 0 , element. 1 ] ) {
130+ Test . Case ( values : [ element. 0 , element. 1 ] , parameters : parameters ) {
104131 try await testFunction ( element. 0 , element. 1 )
105132 }
106133 }
107134 }
108135
136+ /// Initialize an instance of this type that iterates over the specified
137+ /// sequence of 2-tuple argument values.
138+ ///
139+ /// - Parameters:
140+ /// - sequence: The sequence of 2-tuple argument values for which test
141+ /// cases should be generated.
142+ /// - parameters: The parameters of the test function for which test cases
143+ /// should be generated.
144+ /// - testFunction: The test function to which each generated test case
145+ /// passes an argument value from `sequence`.
146+ ///
147+ /// This initializer overload is specialized for sequences of 2-tuples to
148+ /// efficiently de-structure their elements when appropriate.
149+ ///
150+ /// @Comment {
151+ /// - Bug: The testing library should support variadic generics.
152+ /// ([103416861](rdar://103416861))
153+ /// }
154+ private init < E1, E2> (
155+ sequence: S ,
156+ parameters: [ Test . ParameterInfo ] ,
157+ testFunction: @escaping @Sendable ( ( E1, E2) ) async throws -> Void
158+ ) where S. Element == ( E1 , E2 ) , E1: Sendable , E2: Sendable {
159+ if parameters. count > 1 {
160+ self . init ( sequence: sequence) { element in
161+ Test . Case ( values: [ element. 0 , element. 1 ] , parameters: parameters) {
162+ try await testFunction ( element)
163+ }
164+ }
165+ } else {
166+ self . init ( sequence: sequence) { element in
167+ Test . Case ( values: [ element] , parameters: parameters) {
168+ try await testFunction ( element)
169+ }
170+ }
171+ }
172+ }
173+
174+ /// Initialize an instance of this type that iterates over the specified
175+ /// collection of 2-tuple argument values.
176+ ///
177+ /// - Parameters:
178+ /// - collection: The collection of 2-tuple argument values for which test
179+ /// cases should be generated.
180+ /// - parameters: The parameters of the test function for which test cases
181+ /// should be generated.
182+ /// - testFunction: The test function to which each generated test case
183+ /// passes an argument value from `collection`.
184+ ///
185+ /// This initializer overload is specialized for collections of 2-tuples to
186+ /// efficiently de-structure their elements when appropriate.
187+ ///
188+ /// @Comment {
189+ /// - Bug: The testing library should support variadic generics.
190+ /// ([103416861](rdar://103416861))
191+ /// }
192+ init < E1, E2> (
193+ arguments collection: S ,
194+ parameters: [ Test . ParameterInfo ] ,
195+ testFunction: @escaping @Sendable ( ( E1, E2) ) async throws -> Void
196+ ) where S: Collection , S. Element == ( E1 , E2 ) {
197+ self . init ( sequence: collection, parameters: parameters, testFunction: testFunction)
198+ }
199+
109200 /// Initialize an instance of this type that iterates over the specified
110201 /// zipped sequence of argument values.
111202 ///
112203 /// - Parameters:
113204 /// - zippedCollections: A zipped sequence of argument values for which
114205 /// test cases should be generated.
206+ /// - parameters: The parameters of the test function for which test cases
207+ /// should be generated.
115208 /// - testFunction: The test function to which each generated test case
116209 /// passes an argument value from `zippedCollections`.
117210 init < C1, C2> (
118211 arguments zippedCollections: Zip2Sequence < C1 , C2 > ,
212+ parameters: [ Test . ParameterInfo ] ,
119213 testFunction: @escaping @Sendable ( ( C1 . Element, C2 . Element) ) async throws -> Void
120- ) where S == Zip2Sequence < C1 , C2 > {
121- self . init ( sequence: zippedCollections) { element in
122- Test . Case ( arguments: [ element] ) {
123- try await testFunction ( element)
214+ ) where S == Zip2Sequence < C1 , C2 > , C1: Collection , C2: Collection {
215+ self . init ( sequence: zippedCollections, parameters: parameters, testFunction: testFunction)
216+ }
217+
218+ /// Initialize an instance of this type that iterates over the specified
219+ /// dictionary of argument values.
220+ ///
221+ /// - Parameters:
222+ /// - dictionary: A dictionary of argument values for which test cases
223+ /// should be generated.
224+ /// - parameters: The parameters of the test function for which test cases
225+ /// should be generated.
226+ /// - testFunction: The test function to which each generated test case
227+ /// passes an argument value from `dictionary`.
228+ ///
229+ /// This initializer overload is specialized for dictionary collections, to
230+ /// efficiently de-structure their elements (which are known to be 2-tuples)
231+ /// when appropriate. This overload is distinct from those for other
232+ /// collections of 2-tuples because the `Element` tuple type for
233+ /// `Dictionary` includes labels (`(key: Key, value: Value)`).
234+ init < Key, Value> (
235+ arguments dictionary: Dictionary < Key , Value > ,
236+ parameters: [ Test . ParameterInfo ] ,
237+ testFunction: @escaping @Sendable ( ( Key, Value) ) async throws -> Void
238+ ) where S == Dictionary < Key , Value > {
239+ if parameters. count > 1 {
240+ self . init ( sequence: dictionary) { element in
241+ Test . Case ( values: [ element. key, element. value] , parameters: parameters) {
242+ try await testFunction ( element)
243+ }
244+ }
245+ } else {
246+ self . init ( sequence: dictionary) { element in
247+ Test . Case ( values: [ element] , parameters: parameters) {
248+ try await testFunction ( element)
249+ }
124250 }
125251 }
126252 }
0 commit comments