@@ -14,33 +14,109 @@ import XCTest
1414import SwiftSyntax
1515import SwiftParser
1616
17+ /// Returns the `ConcurrentEdits`s to transition from `base` to `new`.
18+ func getConcurrentEdits( from base: String , to new: String ) -> ConcurrentEdits {
19+ let diffCollection = new. difference ( from: base)
20+
21+ let diffArray : [ ( offset: Int , isInsert: Bool ) ] =
22+ diffCollection
23+ . map { diff in
24+ switch diff {
25+ case . remove( offset: let offset, element: _, associatedWith: _) :
26+ return ( offset, false )
27+ case . insert( offset: let offset, element: _, associatedWith: _) :
28+ return ( offset, true )
29+ }
30+ }
31+ . sorted {
32+ // Change.remove should prior to Change.insert
33+ if $0. 0 < $1. 0 {
34+ return true
35+ } else if $0. 0 == $1. 0 {
36+ return !$0. 1
37+ } else {
38+ return false
39+ }
40+ }
41+
42+ let sourceEdits = diffArray. map ( {
43+ return $0. 1 ? SourceEdit ( offset: $0. 0 , length: 0 , replacementLength: 1 ) : SourceEdit ( offset: $0. 0 , length: 1 , replacementLength: 0 )
44+ } )
45+
46+ return ConcurrentEdits ( fromSequential: sourceEdits)
47+ }
48+
1749public class IncrementalParsingTests : XCTestCase {
1850
51+ public func testDiffOfTwoStringsSimple( ) throws {
52+ let s1 = " struct A { func f() { "
53+ let s2 = " struct AA { func f() { "
54+
55+ let diffs = getConcurrentEdits ( from: s1, to: s2)
56+ XCTAssertEqual ( diffs. edits. count, 1 )
57+
58+ let firstDiff = try XCTUnwrap ( diffs. edits. first)
59+ XCTAssert ( firstDiff == SourceEdit ( offset: 8 , length: 0 , replacementLength: 1 ) )
60+ XCTAssertEqual ( firstDiff, SourceEdit ( offset: 8 , length: 0 , replacementLength: 1 ) )
61+ }
62+
63+ public func testDiffOfTwoSameStrings( ) {
64+ let s1 = " 0123456 "
65+ let s2 = " 0123456 "
66+
67+ let diffs = getConcurrentEdits ( from: s1, to: s2)
68+ XCTAssert ( diffs. edits. isEmpty)
69+ }
70+
71+ public func testDiffOfTwoStrings( ) {
72+ let s1 = " 0123456 "
73+ let s2 = " x12456yz "
74+
75+ let diffs = getConcurrentEdits ( from: s1, to: s2)
76+
77+ let expectedDiffs : [ SourceEdit ] = [
78+ SourceEdit ( offset: 0 , length: 1 , replacementLength: 1 ) ,
79+ SourceEdit ( offset: 3 , length: 1 , replacementLength: 0 ) ,
80+ SourceEdit ( offset: 7 , length: 0 , replacementLength: 2 ) ,
81+ ]
82+
83+ XCTAssertEqual ( diffs. edits, expectedDiffs)
84+ }
85+
1986 public func testIncrementalInvalid( ) {
2087 let original = " struct A { func f() { "
21- let step : ( String , ( Int , Int , String ) ) =
22- ( " struct AA { func f() { " , ( 8 , 0 , " A " ) )
23-
24- var tree = Parser . parse ( source: original)
25- let sourceEdit = SourceEdit ( range: ByteSourceRange ( offset: step. 1 . 0 , length: step. 1 . 1 ) , replacementLength: step. 1 . 2 . utf8. count)
26- let lookup = IncrementalParseTransition ( previousTree: tree, edits: ConcurrentEdits ( sourceEdit) )
27- tree = Parser . parse ( source: step. 0 , parseTransition: lookup)
28- XCTAssertEqual ( " \( tree) " , step. 0 )
88+ let newSource = " struct AA { func f() { "
89+
90+ let concurrentEdits = getConcurrentEdits ( from: original, to: newSource)
91+
92+ let oldTree = Parser . parse ( source: original)
93+ let lookup = IncrementalParseTransition ( previousTree: oldTree, edits: concurrentEdits)
94+ let newTree = Parser . parse ( source: newSource, parseTransition: lookup)
95+
96+ XCTAssertEqual ( " \( newTree) " , " \( newSource) " )
2997 }
3098
3199 public func testReusedNode( ) throws {
32100 try XCTSkipIf ( true , " Swift parser does not handle node reuse yet " )
33101
34- let original = " struct A {} \n struct B {} \n "
35- let step : ( String , ( Int , Int , String ) ) =
36- ( " struct AA {} \n struct B {} \n " , ( 8 , 0 , " A " ) )
102+ let original =
103+ """
104+ struct A {}
105+ struct B {}
106+ """
107+
108+ let newSource =
109+ """
110+ struct A {}
111+ struct B {}
112+ """
37113
38114 let origTree = Parser . parse ( source: original)
39- let sourceEdit = SourceEdit ( range : ByteSourceRange ( offset : step . 1 . 0 , length : step . 1 . 1 ) , replacementLength : step . 1 . 2 . utf8 . count )
115+ let concurrentEdits = getConcurrentEdits ( from : original , to : newSource )
40116 let reusedNodeCollector = IncrementalParseReusedNodeCollector ( )
41- let transition = IncrementalParseTransition ( previousTree: origTree, edits: ConcurrentEdits ( sourceEdit ) , reusedNodeDelegate: reusedNodeCollector)
42- let newTree = Parser . parse ( source: step . 0 , parseTransition: transition)
43- XCTAssertEqual ( " \( newTree) " , step . 0 )
117+ let transition = IncrementalParseTransition ( previousTree: origTree, edits: concurrentEdits , reusedNodeDelegate: reusedNodeCollector)
118+ let newTree = Parser . parse ( source: newSource , parseTransition: transition)
119+ XCTAssertEqual ( " \( newTree) " , " \( newSource ) " )
44120
45121 let origStructB = origTree. statements [ 1 ]
46122 let newStructB = newTree. statements [ 1 ]
0 commit comments