forked from tornikegomareli/gitdiff
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDiffParserTests.swift
More file actions
160 lines (148 loc) · 4.36 KB
/
DiffParserTests.swift
File metadata and controls
160 lines (148 loc) · 4.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import Testing
@testable import gitdiff
internal func makeLargeMultiHunkDiff(hunks: Int, linesPerHunk: Int) -> String {
var parts: [String] = []
parts.append("diff --git a/large.txt b/large.txt")
parts.append("index 7777777..8888888 100644")
parts.append("--- a/large.txt")
parts.append("+++ b/large.txt")
var oldStart = 1
var newStart = 1
for _ in 0..<hunks {
parts.append("@@ -\(oldStart),\(linesPerHunk) +\(newStart),\(linesPerHunk) @@")
// Add alternating context/removed/added to keep parser busy
for j in 0..<linesPerHunk {
if j % 3 == 0 {
parts.append(" context line \(j)")
oldStart += 1
newStart += 1
} else if j % 3 == 1 {
parts.append("-removed line \(j)")
oldStart += 1
} else {
parts.append("+added line \(j)")
newStart += 1
}
}
}
return parts.joined(separator: "\n")
}
struct DiffParserTests {
// MARK: - Helpers
private func makeSimpleSingleHunkDiff() -> String {
return """
diff --git a/foo.txt b/foo.txt
index 1111111..2222222 100644
--- a/foo.txt
+++ b/foo.txt
@@ -1,2 +1,3 @@
line1
-line2
+line2 changed
+line3
"""
}
private func makeTwoHunksDiff() -> String {
return """
diff --git a/bar.txt b/bar.txt
index 3333333..4444444 100644
--- a/bar.txt
+++ b/bar.txt
@@ -1,2 +1,2 @@
a
-b
+B
@@ -5,2 +5,3 @@
five
-six
+six!
+seven
"""
}
private func makeBinaryDiff() -> String {
return """
diff --git a/bin/file.bin b/bin/file.bin
index abcdef1..abcdef2 100644
Binary files a/bin/file.bin and b/bin/file.bin differ
"""
}
private func makeRenameDiff() -> String {
return """
diff --git a/old.txt b/new.txt
similarity index 100%
rename from old.txt
rename to new.txt
index 5555555..6666666 100644
--- a/old.txt
+++ b/new.txt
"""
}
// MARK: - Tests
@Test
func testParseEmptyReturnsEmpty() async throws {
let files = try await DiffParser.parse("")
#expect(files.count == 0)
}
@Test
func testParseSingleFileSingleHunk() async throws {
let diff = makeSimpleSingleHunkDiff()
let files = try await DiffParser.parse(diff)
#expect(files.count == 1)
let file = try #require(files.first)
#expect(file.oldPath == "foo.txt")
#expect(file.newPath == "foo.txt")
#expect(file.isBinary == false)
#expect(file.isRenamed == false)
#expect(file.hunks.count == 1)
let hunk = try #require(file.hunks.first)
#expect(hunk.header.trimmingCharacters(in: .whitespaces) == "@@ -1,2 +1,3 @@")
#expect(hunk.lines.count == 4)
#expect(hunk.lines[0].type == .context)
#expect(hunk.lines[0].content == "line1")
#expect(hunk.lines[1].type == .removed)
#expect(hunk.lines[1].content == "line2")
#expect(hunk.lines[2].type == .added)
#expect(hunk.lines[2].content == "line2 changed")
#expect(hunk.lines[3].type == .added)
#expect(hunk.lines[3].content == "line3")
}
@Test
func testParseMultipleHunksInOneFile() async throws {
let diff = makeTwoHunksDiff()
let files = try await DiffParser.parse(diff)
#expect(files.count == 1)
let file = try #require(files.first)
#expect(file.hunks.count == 2)
}
@Test
func testParseBinaryFile() async throws {
let diff = makeBinaryDiff()
let files = try await DiffParser.parse(diff)
#expect(files.count == 1)
let file = try #require(files.first)
#expect(file.isBinary)
#expect(file.hunks.count == 0)
}
@Test
func testParseRename() async throws {
let diff = makeRenameDiff()
let files = try await DiffParser.parse(diff)
#expect(files.count == 1)
let file = try #require(files.first)
#expect(file.isRenamed)
#expect(file.oldPath == "old.txt")
#expect(file.newPath == "new.txt")
}
@Test
func testCancellationThrowsCancellationError() async throws {
// Build a large diff to ensure the task doesn't finish instantly
let diff = makeLargeMultiHunkDiff(hunks: 40, linesPerHunk: 30)
let task = Task { () -> [DiffFile] in try await DiffParser.parse(diff) }
// Yield and then cancel shortly after to trigger cooperative cancellation
await Task.yield()
task.cancel()
await #expect(throws: CancellationError.self) {
_ = try await task.value
}
}
}