gitbayTests/AccountDeleteTests.swift
89 lines · 4040 bytes
9 symbols in this file
1import Foundation
2import Testing
3@testable import gitbay
4
5private func makeClient() throws -> (GitbayClient, StubProtocol.Box) {
6 let box = StubProtocol.box()
7 let client = GitbayClient(
8 instance: try GitbayInstance(url: "https://gitbay.org"),
9 token: "test-token",
10 session: box.session()
11 )
12 return (client, box)
13}
14
15private func posted(_ stub: StubProtocol.Box) throws -> [[String]] {
16 try stub.seen.filter { $0.method == "POST" }.map { seen in
17 let body = try #require(try JSONSerialization.jsonObject(with: seen.body) as? [String: Any])
18 return try #require(body["argv"] as? [String])
19 }
20}
21
22private func scratchDefaults() -> UserDefaults {
23 UserDefaults(suiteName: "gb-test-\(UUID().uuidString)")!
24}
25
26@MainActor
27struct AccountDeleteTests {
28
29 @Test func aRequestIsRememberedForTheLinksDayAndNoLonger() async throws {
30 let (client, stub) = try makeClient()
31 stub.enqueue(.init(status: 200, json: #"{"protocol_version":1,"data":{"user":"sim","mailed":"sim@example.test"},"exit_code":0}"#, match: "cmd"))
32 let defaults = scratchDefaults()
33 await AccountViewModel(client: client, defaults: defaults).requestDeletion(username: "sim")
34
35 let later = AccountViewModel(client: client, defaults: defaults)
36 later.loadPendingDeletion(username: "sim", now: .now.addingTimeInterval(60 * 60))
37 #expect(later.deletionMailedTo == "sim@example.test")
38
39 let tooLate = AccountViewModel(client: client, defaults: defaults)
40 tooLate.loadPendingDeletion(username: "sim", now: .now.addingTimeInterval(25 * 60 * 60))
41 #expect(tooLate.deletionMailedTo == nil)
42 }
43
44 @Test func withdrawingWhenNothingIsPendingClearsTheNotice() async throws {
45 let (client, stub) = try makeClient()
46 stub.enqueue(.init(status: 404, json: #"{"protocol_version":1,"error":"no deletion is pending for sim","exit_code":3}"#, match: "cmd"))
47 let model = AccountViewModel(client: client, defaults: scratchDefaults())
48
49 await model.cancelDeletion(username: "sim")
50
51 #expect(model.deletionMailedTo == nil)
52 #expect(model.actionError == nil)
53 }
54
55 @Test func askingMailsALinkToTheAddressTheServerNames() async throws {
56 let (client, stub) = try makeClient()
57 stub.enqueue(.init(status: 200, json: #"{"protocol_version":1,"data":{"user":"sim","mailed":"sim@example.test"},"exit_code":0}"#, match: "cmd"))
58 let model = AccountViewModel(client: client, defaults: scratchDefaults())
59
60 await model.requestDeletion(username: "sim")
61
62 #expect(try posted(stub) == [["account", "delete", "--confirm", "sim"]])
63 #expect(model.deletionMailedTo == "sim@example.test")
64 }
65
66 @Test func aRefusalSaysWhyAndNothingIsPending() async throws {
67 let (client, stub) = try makeClient()
68 stub.enqueue(.init(status: 403, json: #"{"protocol_version":1,"error":"you are the instance's only admin; promote another account first","exit_code":4}"#, match: "cmd"))
69 let model = AccountViewModel(client: client, defaults: scratchDefaults())
70
71 await model.requestDeletion(username: "sim")
72
73 #expect(model.deletionMailedTo == nil)
74 #expect(model.actionError == "you are the instance's only admin; promote another account first")
75 }
76
77 @Test func withdrawingSendsCancel() async throws {
78 let (client, stub) = try makeClient()
79 stub.enqueue(.init(status: 200, json: #"{"protocol_version":1,"data":{"user":"sim","mailed":"sim@example.test"},"exit_code":0}"#, match: "cmd"))
80 stub.enqueue(.init(status: 200, json: #"{"protocol_version":1,"data":{"user":"sim","cancelled":true},"exit_code":0}"#, match: "cmd"))
81 let model = AccountViewModel(client: client, defaults: scratchDefaults())
82 await model.requestDeletion(username: "sim")
83
84 await model.cancelDeletion(username: "sim")
85
86 #expect(try posted(stub).last == ["account", "delete", "--cancel"])
87 #expect(model.deletionMailedTo == nil)
88 }
89}