| @@ -135,6 +135,21 @@ struct RepoActionsTests { |
| 135 | == ["repo", "fork", "krz/gitbay", "--name", "mine"]) |
135 | == ["repo", "fork", "krz/gitbay", "--name", "mine"]) |
| 136 | } |
136 | } |
| 137 | |
137 | |
| |
138 | /// Surrounding whitespace must not reach the server — the name is |
| |
139 | /// trimmed, not just tested for blankness. |
| |
140 | @Test func forkingWithSurroundingWhitespaceTrimsTheName() async throws { |
| |
141 | let (client, stub) = try makeClient() |
| |
142 | stub.enqueue(.init(status: 200, json: """ |
| |
143 | {"protocol_version":1,"data":{"path":"cmc/mine","fork_of":"krz/gitbay"},\ |
| |
144 | "exit_code":0} |
| |
145 | """)) |
| |
146 | let model = RepoActionsViewModel(client: client, repoPath: "krz/gitbay") |
| |
147 | _ = await model.fork(named: " mine ") |
| |
148 | |
| |
149 | #expect(try argvOf(try #require(stub.seen.last)) |
| |
150 | == ["repo", "fork", "krz/gitbay", "--name", "mine"]) |
| |
151 | } |
| |
152 | |
| 138 | /// A blank name must not send an empty flag value. |
153 | /// A blank name must not send an empty flag value. |
| 139 | @Test func forkingWithABlankNameOmitsTheFlag() async throws { |
154 | @Test func forkingWithABlankNameOmitsTheFlag() async throws { |
| 140 | let (client, stub) = try makeClient() |
155 | let (client, stub) = try makeClient() |
| @@ -182,4 +197,39 @@ struct RepoActionsTests { |
| 182 | #expect(model.notice == nil) |
197 | #expect(model.notice == nil) |
| 183 | #expect(model.actionError?.isEmpty == false) |
198 | #expect(model.actionError?.isEmpty == false) |
| 184 | } |
199 | } |
| |
200 | |
| |
201 | /// A 0-exit fork whose envelope carries no `data` must not fail |
| |
202 | /// silently — the caller needs to know nothing came back. |
| |
203 | @Test func aForkThatReportsNothingBackSetsAnError() async throws { |
| |
204 | let (client, stub) = try makeClient() |
| |
205 | stub.enqueue(.init(status: 200, json: """ |
| |
206 | {"protocol_version":1,"exit_code":0} |
| |
207 | """)) |
| |
208 | let model = RepoActionsViewModel(client: client, repoPath: "krz/gitbay") |
| |
209 | let result = await model.fork(named: nil) |
| |
210 | |
| |
211 | #expect(result == nil) |
| |
212 | #expect(model.actionError?.isEmpty == false) |
| |
213 | } |
| |
214 | |
| |
215 | /// A bookmark write must be followed by a re-read of `repo |
| |
216 | /// bookmarks` — that re-read is what keeps `isBookmarked` honest |
| |
217 | /// instead of an optimistic local guess. |
| |
218 | @Test func bookmarkingRereadsTheListingAfterTheWrite() async throws { |
| |
219 | let (client, stub) = try makeClient() |
| |
220 | stub.enqueue(.init(status: 200, json: bookmarks)) |
| |
221 | let model = RepoActionsViewModel(client: client, repoPath: "krz/other") |
| |
222 | await model.loadBookmarkState() |
| |
223 | #expect(model.isBookmarked == false) |
| |
224 | |
| |
225 | stub.enqueue(.init(status: 200, json: ok)) |
| |
226 | stub.enqueue(.init(status: 200, json: bookmarks)) |
| |
227 | await model.setBookmarked(true) |
| |
228 | |
| |
229 | let calls = stub.seen.suffix(2) |
| |
230 | let write = try #require(calls.first) |
| |
231 | let reread = try #require(calls.last) |
| |
232 | #expect(try argvOf(write) == ["repo", "bookmark", "krz/other"]) |
| |
233 | #expect(argvFrom(reread.url) == ["repo", "bookmarks"]) |
| |
234 | } |
| 185 | } |
235 | } |