@@ -166,7 +166,9 @@ class FixItApplierApplyEditsTests: XCTestCase {
166166 . init( range: 3 ..< 7 , replacement: " cd " ) ,
167167 ] ,
168168 // The second edit is skipped.
169- possibleOutputs: [ " aboo = 1 " , " varcd = 1 " ]
169+ outputs: [
170+ . init( oneOf: " aboo = 1 " , " varcd = 1 " )
171+ ]
170172 )
171173 }
172174
@@ -180,19 +182,36 @@ class FixItApplierApplyEditsTests: XCTestCase {
180182 . init( range: 0 ..< 5 , replacement: " _ " ) ,
181183 . init( range: 0 ..< 3 , replacement: " let " ) ,
182184 ] ,
183- possibleOutputs: [ " _ = 11 " , " let x = 11 " ]
185+ outputs: [
186+ . init( oneOf: " _ = 11 " , " let x = 11 " )
187+ ]
184188 )
185189 }
186190
187191 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+
188203 assertAppliedEdits (
189204 to: " x = 1 " ,
190205 edits: [
191206 . init( range: 0 ..< 0 , replacement: " var " ) ,
192207 . init( range: 0 ..< 0 , replacement: " var " ) ,
208+ . init( range: 4 ..< 5 , replacement: " 2 " ) ,
193209 . init( range: 0 ..< 0 , replacement: " var " ) ,
194210 ] ,
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+ ]
196215 )
197216 }
198217
@@ -214,47 +233,105 @@ class FixItApplierApplyEditsTests: XCTestCase {
214233 . init( range: 2 ..< 2 , replacement: " a " ) , // Insertion
215234 ] ,
216235 // 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+ ]
218239 )
219240 }
220241}
221242
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`.
224278private func assertAppliedEdits(
225279 to tree: SourceFileSyntax ,
226280 edits: [ SourceEdit ] ,
227- possibleOutputs: [ String ] ,
228- line: UInt = #line
281+ outputs: [ OutputExpectation ]
229282) {
230- precondition ( !possibleOutputs . isEmpty)
283+ precondition ( !outputs . isEmpty)
231284
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+ }
235292
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] }
248299
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+ }
252328 }
253329 }
254330}
255331
256332/// 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`.
258335private func assertAppliedEdits(
259336 to tree: SourceFileSyntax ,
260337 edits: [ SourceEdit ] ,
@@ -264,8 +341,9 @@ private func assertAppliedEdits(
264341 assertAppliedEdits (
265342 to: tree,
266343 edits: edits,
267- possibleOutputs: [ output] ,
268- line: line
344+ outputs: [
345+ . init( deterministic: output, allowDuplicateInsertions: nil , line: line)
346+ ]
269347 )
270348}
271349
0 commit comments