Commit ac81a4d179

ac81a4d179fae9ec7631b4587c5909352c532077

parent: 982ec60b32

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-07 02:22 UTC

Guard direct stub.seen indexing with #require

A raw stub.seen[n] crashes the whole test process the moment a
regression leaves fewer requests than expected, instead of failing
just that one test. Replace every unguarded index (and aliases of
stub.seen) with #require(stub.seen.dropFirst(n).first), which throws
a legible per-test failure instead.

Layout: unified · split

gitbayTests/BlameEditTests.swift +2 −1
@@ -64,7 +64,8 @@ struct BlameViewModelTests {
6464 await model.loadMore()
6565 #expect(model.hunks.count == 2)
6666 #expect(!model.hasMore)
67 #expect(stub.seen[1].url.query()?.contains("argv=--from&argv=1001") == true)
67 let second = try #require(stub.seen.dropFirst().first)
68 #expect(second.url.query()?.contains("argv=--from&argv=1001") == true)
6869
6970 // Nothing further to ask for.
7071 await model.loadMore()
gitbayTests/ExploreRefLogTests.swift +2 −1
@@ -84,7 +84,8 @@ struct ExploreTests {
8484 await list.loadMore()
8585 #expect(list.state.value?.count == 3)
8686 #expect(!list.hasMore)
87 #expect(stub.seen[1].url.query()?.contains("argv=--cursor&argv=ZXhwbG9yZTpr") == true)
87 let second = try #require(stub.seen.dropFirst().first)
88 #expect(second.url.query()?.contains("argv=--cursor&argv=ZXhwbG9yZTpr") == true)
8889 }
8990
9091 @Test func ownerAndNameSplitForDisplay() {
gitbayTests/GitbayClientTests.swift +6 −3
@@ -101,8 +101,10 @@ struct GitbayClientReadTests {
101101 #expect(first[0].path == "krz/gitbay")
102102 let requests = stub.seen
103103 #expect(requests.count == 2)
104 #expect(requests[0].headers["If-None-Match"] == nil)
105 #expect(requests[1].headers["If-None-Match"] == etag)
104 let firstRequest = try #require(requests.first)
105 #expect(firstRequest.headers["If-None-Match"] == nil)
106 let secondRequest = try #require(requests.dropFirst().first)
107 #expect(secondRequest.headers["If-None-Match"] == etag)
106108 }
107109
108110 @Test func changedBodyReplacesTheCachedValidator() async throws {
@@ -117,7 +119,8 @@ struct GitbayClientReadTests {
117119
118120 #expect(refreshed.isEmpty)
119121 #expect(revalidated.isEmpty)
120 #expect(stub.seen[2].headers["If-None-Match"] == "\"bb\"")
122 let third = try #require(stub.seen.dropFirst(2).first)
123 #expect(third.headers["If-None-Match"] == "\"bb\"")
121124 }
122125
123126 @Test func absentDataDecodesAsEmptyList() async throws {
gitbayTests/MRViewModelTests.swift +6 −5
@@ -185,7 +185,8 @@ struct MRListViewModelTests {
185185 }
186186
187187 #expect(stub.seen.count == 2)
188 #expect(stub.seen[1].url.query()?.contains("argv=merged") == true)
188 let second = try #require(stub.seen.dropFirst().first)
189 #expect(second.url.query()?.contains("argv=merged") == true)
189190 guard case .empty = model.state else {
190191 Issue.record("expected .empty after filtering, got \(model.state)")
191192 return
@@ -264,7 +265,7 @@ struct MRDetailViewModelTests {
264265
265266 await model.review(.approve)
266267
267 let write = stub.seen[3]
268 let write = try #require(stub.seen.dropFirst(3).first)
268269 #expect(write.method == "POST")
269270 #expect(write.url.path() == "/api/v1/cmd")
270271 let body = try #require(try JSONSerialization.jsonObject(with: write.body) as? [String: Any])
@@ -282,7 +283,7 @@ struct MRDetailViewModelTests {
282283
283284 await model.comment("long review text\nwith lines")
284285
285 let write = stub.seen[3]
286 let write = try #require(stub.seen.dropFirst(3).first)
286287 let body = try #require(try JSONSerialization.jsonObject(with: write.body) as? [String: Any])
287288 #expect(body["argv"] as? [String] == ["mr", "comment", "krz/gitbay", "7", "--file", "-"])
288289 #expect(body["stdin"] as? String == "long review text\nwith lines")
@@ -311,7 +312,7 @@ struct MRDetailViewModelTests {
311312
312313 await model.setResolved(thread, true)
313314
314 let write = stub.seen[3]
315 let write = try #require(stub.seen.dropFirst(3).first)
315316 let body = try #require(try JSONSerialization.jsonObject(with: write.body) as? [String: Any])
316317 #expect(body["argv"] as? [String] == ["mr", "resolve", "krz/gitbay", "7", "3"])
317318 }
@@ -326,7 +327,7 @@ struct MRDetailViewModelTests {
326327
327328 await model.reply(to: thread, "because 5xx is transient")
328329
329 let write = stub.seen[3]
330 let write = try #require(stub.seen.dropFirst(3).first)
330331 let body = try #require(try JSONSerialization.jsonObject(with: write.body) as? [String: Any])
331332 #expect(body["argv"] as? [String] ==
332333 ["mr", "diff-comment", "krz/gitbay", "7", "--reply", "3", "--file", "-"])
gitbayTests/PagedListTests.swift +8 −4
@@ -38,9 +38,11 @@ struct ClientPagingTests {
3838 #expect(first.next == "abc")
3939 #expect(second.items == [Row(number: 3)])
4040 #expect(second.next == nil)
41 #expect(stub.seen[0].url.query() ==
41 let firstSeen = try #require(stub.seen.first)
42 #expect(firstSeen.url.query() ==
4243 "argv=issue&argv=list&argv=krz/gitbay&argv=--limit&argv=2")
43 #expect(stub.seen[1].url.query() ==
44 let secondSeen = try #require(stub.seen.dropFirst().first)
45 #expect(secondSeen.url.query() ==
4446 "argv=issue&argv=list&argv=krz/gitbay&argv=--limit&argv=2&argv=--cursor&argv=abc")
4547 }
4648}
@@ -77,8 +79,10 @@ struct PagedListModelTests {
7779 // Further calls are no-ops, not requests.
7880 await list.loadMore()
7981 #expect(stub.seen.count == 3)
80 #expect(stub.seen[1].url.query()?.contains("argv=--cursor&argv=c1") == true)
81 #expect(stub.seen[2].url.query()?.contains("argv=--cursor&argv=c2") == true)
82 let second = try #require(stub.seen.dropFirst().first)
83 #expect(second.url.query()?.contains("argv=--cursor&argv=c1") == true)
84 let third = try #require(stub.seen.dropFirst(2).first)
85 #expect(third.url.query()?.contains("argv=--cursor&argv=c2") == true)
8286 }
8387
8488 @Test func anEmptyFirstPageIsAnEmptyState() async throws {
gitbayTests/ProfileCommitTests.swift +2 −1
@@ -59,7 +59,8 @@ struct ProfileAggregateTests {
5959 #expect(profile.activityTotal == 15)
6060 // One read builds the whole page.
6161 #expect(stub.seen.count == 1)
62 #expect(stub.seen[0].url.query() == "argv=profile&argv=show&argv=cmc")
62 let first = try #require(stub.seen.first)
63 #expect(first.url.query() == "argv=profile&argv=show&argv=cmc")
6364 }
6465
6566 @Test func anOrgProfileCarriesMembersInsteadOfOrgs() async throws {
gitbayTests/RefsMilestoneTests.swift +2 −1
@@ -120,7 +120,8 @@ struct MilestoneListViewModelTests {
120120 }
121121
122122 #expect(stub.seen.count == 2)
123 #expect(stub.seen[1].url.query()?.contains("argv=closed") == true)
123 let second = try #require(stub.seen.dropFirst().first)
124 #expect(second.url.query()?.contains("argv=closed") == true)
124125 }
125126}
126127