@@ -166,7 +166,9 @@ class FixItApplierApplyEditsTests: XCTestCase {
166
166
. init( range: 3 ..< 7 , replacement: " cd " ) ,
167
167
] ,
168
168
// The second edit is skipped.
169
- possibleOutputs: [ " aboo = 1 " , " varcd = 1 " ]
169
+ outputs: [
170
+ . init( oneOf: " aboo = 1 " , " varcd = 1 " )
171
+ ]
170
172
)
171
173
}
172
174
@@ -180,19 +182,36 @@ class FixItApplierApplyEditsTests: XCTestCase {
180
182
. init( range: 0 ..< 5 , replacement: " _ " ) ,
181
183
. init( range: 0 ..< 3 , replacement: " let " ) ,
182
184
] ,
183
- possibleOutputs: [ " _ = 11 " , " let x = 11 " ]
185
+ outputs: [
186
+ . init( oneOf: " _ = 11 " , " let x = 11 " )
187
+ ]
184
188
)
185
189
}
186
190
187
191
func testOverlappingInsertions( ) {
192
+ assertAppliedEdits (
193
+ to: " x = 1 " ,
194
+ edits: [
195
+ . init( range: 1 ..< 1 , replacement: " y " ) ,
196
+ . init( range: 1 ..< 1 , replacement: " z " ) ,
197
+ ] ,
198
+ outputs: [
199
+ . init( oneOf: " xyz = 1 " , " xzy = 1 " )
200
+ ]
201
+ )
202
+
188
203
assertAppliedEdits (
189
204
to: " x = 1 " ,
190
205
edits: [
191
206
. init( range: 0 ..< 0 , replacement: " var " ) ,
192
207
. init( range: 0 ..< 0 , replacement: " var " ) ,
208
+ . init( range: 4 ..< 5 , replacement: " 2 " ) ,
193
209
. init( range: 0 ..< 0 , replacement: " var " ) ,
194
210
] ,
195
- output: " var var var x = 1 "
211
+ outputs: [
212
+ . init( deterministic: " var var var x = 2 " , allowDuplicateInsertions: true ) ,
213
+ . init( deterministic: " var x = 2 " , allowDuplicateInsertions: false ) ,
214
+ ]
196
215
)
197
216
}
198
217
@@ -214,47 +233,105 @@ class FixItApplierApplyEditsTests: XCTestCase {
214
233
. init( range: 2 ..< 2 , replacement: " a " ) , // Insertion
215
234
] ,
216
235
// FIXME: This behavior where these edits are not considered overlapping doesn't feel desirable
217
- possibleOutputs: [ " _x = 1 " , " _ a= 1 " ]
236
+ outputs: [
237
+ . init( oneOf: " _x = 1 " , " _ a= 1 " )
238
+ ]
218
239
)
219
240
}
220
241
}
221
242
222
- /// Asserts that at least one element in `possibleOutputs` matches the result
223
- /// of applying an array of edits to `input`, for all permutations of `edits`.
243
+ /// Represents an output expectation.
244
+ private struct OutputExpectation {
245
+ var possibleOutputs : [ String ]
246
+ var allowDuplicateInsertions : Bool ?
247
+ var line : UInt
248
+
249
+ /// Create a deterministic output expectation for the given value of
250
+ /// `allowDuplicateInsertions`. If `allowDuplicateInsertions` is `nil`,
251
+ /// the expectation holds for both `true` and `false`.
252
+ init (
253
+ deterministic output: String ,
254
+ allowDuplicateInsertions: Bool ? = nil ,
255
+ line: UInt = #line
256
+ ) {
257
+ self . possibleOutputs = [ output]
258
+ self . allowDuplicateInsertions = allowDuplicateInsertions
259
+ self . line = line
260
+ }
261
+
262
+ /// Create a "one of the given possible outputs" expectation for the given
263
+ /// value of `allowDuplicateInsertions`. If `allowDuplicateInsertions` is
264
+ /// `nil`, the expectation holds for both `true` and `false`.
265
+ init (
266
+ oneOf possibleOutputs: String ... ,
267
+ allowDuplicateInsertions: Bool ? = nil ,
268
+ line: UInt = #line
269
+ ) {
270
+ self . possibleOutputs = possibleOutputs
271
+ self . allowDuplicateInsertions = allowDuplicateInsertions
272
+ self . line = line
273
+ }
274
+ }
275
+
276
+ /// Asserts that the given outputs match the result of applying an array of
277
+ /// edits to `input`, for all permutations of `edits`.
224
278
private func assertAppliedEdits(
225
279
to tree: SourceFileSyntax ,
226
280
edits: [ SourceEdit ] ,
227
- possibleOutputs: [ String ] ,
228
- line: UInt = #line
281
+ outputs: [ OutputExpectation ]
229
282
) {
230
- precondition ( !possibleOutputs . isEmpty)
283
+ precondition ( !outputs . isEmpty)
231
284
232
- var indices = Array ( edits. indices)
233
- while true {
234
- let editsPermutation = indices. map { edits [ $0] }
285
+ NEXT_OUTPUT: for output in outputs {
286
+ let allowDuplicateInsertionsValues =
287
+ if let value = output. allowDuplicateInsertions {
288
+ [ value]
289
+ } else {
290
+ [ true , false ]
291
+ }
235
292
236
- let actualOutput = FixItApplier . apply ( edits: editsPermutation, to: tree)
237
- guard possibleOutputs. contains ( actualOutput) else {
238
- XCTFail (
239
- """
240
- Actual output \" \( actualOutput) \" does not match one of \( possibleOutputs)
241
- Edits:
242
- \( editsPermutation)
243
- """ ,
244
- line: line
245
- )
246
- return
247
- }
293
+ let possibleOutputs = output. possibleOutputs
294
+
295
+ // Check this output against all permutations of edits.
296
+ var indices = Array ( edits. indices)
297
+ while true {
298
+ let editsPermutation = indices. map { edits [ $0] }
248
299
249
- let keepGoing = indices. nextPermutation ( )
250
- guard keepGoing else {
251
- break
300
+ for allowDuplicateInsertionsValue in allowDuplicateInsertionsValues {
301
+ let actualOutput = FixItApplier . apply (
302
+ edits: editsPermutation,
303
+ to: tree,
304
+ allowDuplicateInsertions: allowDuplicateInsertionsValue
305
+ )
306
+
307
+ guard possibleOutputs. contains ( actualOutput) else {
308
+ XCTFail (
309
+ """
310
+ Actual output \" \( actualOutput) \" does not match one of \( possibleOutputs)
311
+ Edits:
312
+ \( editsPermutation)
313
+ allowDuplicateInsertions:
314
+ \( allowDuplicateInsertionsValue)
315
+ """ ,
316
+ line: output. line
317
+ )
318
+
319
+ // Fail once for all permutations to avoid excessive logging.
320
+ continue NEXT_OUTPUT
321
+ }
322
+ }
323
+
324
+ let keepGoing = indices. nextPermutation ( )
325
+ guard keepGoing else {
326
+ break
327
+ }
252
328
}
253
329
}
254
330
}
255
331
256
332
/// Asserts that `output` matches the result of applying an array of edits to
257
- /// `input`, for all permutations of `edits`.
333
+ /// `input`, for all permutations of `edits` and for `allowDuplicateInsertions`
334
+ /// both `true` and `false`.
258
335
private func assertAppliedEdits(
259
336
to tree: SourceFileSyntax ,
260
337
edits: [ SourceEdit ] ,
@@ -264,8 +341,9 @@ private func assertAppliedEdits(
264
341
assertAppliedEdits (
265
342
to: tree,
266
343
edits: edits,
267
- possibleOutputs: [ output] ,
268
- line: line
344
+ outputs: [
345
+ . init( deterministic: output, allowDuplicateInsertions: nil , line: line)
346
+ ]
269
347
)
270
348
}
271
349
0 commit comments