gitbayTests/OrgLabelMilestoneTests.swift

v1.14.1
gitbay-ios/gitbayTests/OrgLabelMilestoneTests.swift history · blame · raw

119 lines · 4534 bytes

  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 argvOf(_ seen: StubProtocol.Seen) throws -> [String] {
 16    let body = try #require(try JSONSerialization.jsonObject(with: seen.body) as? [String: Any])
 17    return try #require(body["argv"] as? [String])
 18}
 19
 20private let okJSON = #"{"protocol_version":1,"data":{},"exit_code":0}"#
 21
 22private let orgLabelsJSON = """
 23    {"protocol_version":1,"data":[\
 24    {"name":"bug","color":"#cf222e","org":true,"issues":18},\
 25    {"name":"ci","org":true,"issues":2}],"exit_code":0}
 26    """
 27
 28private let orgMilestonesJSON = """
 29    {"protocol_version":1,"data":[\
 30    {"title":"v2.0.0","state":"open","org":true,"open":3,"closed":9}],"exit_code":0}
 31    """
 32
 33struct LabelOwnerTests {
 34
 35    /// A repository's set is `label <verb> <repo>`; an org's is
 36    /// `org label <verb> <org>`. Milestones follow the same shape.
 37    @Test func eachOwnerSpellsItsOwnCommand() {
 38        #expect(LabelOwner.repo("krz/gitbay").argv("label", "set") == ["label", "set", "krz/gitbay"])
 39        #expect(LabelOwner.org("krz").argv("label", "set") == ["org", "label", "set", "krz"])
 40        #expect(LabelOwner.org("krz").argv("milestone", "list") == ["org", "milestone", "list", "krz"])
 41        #expect(LabelOwner.repo("krz/gitbay").isOrg == false)
 42        #expect(LabelOwner.org("krz").isOrg)
 43    }
 44}
 45
 46@MainActor
 47struct OrgLabelListTests {
 48
 49    @Test func anOrgListsItsLabelsThroughOrgLabel() async throws {
 50        let (client, stub) = try makeClient()
 51        stub.enqueue(.init(status: 200, json: orgLabelsJSON))
 52        let model = LabelListViewModel(client: client, owner: .org("krz"))
 53
 54        await model.load()
 55
 56        #expect(stub.seen.first?.url.query() == "argv=org&argv=label&argv=list&argv=krz")
 57        #expect(model.state.value?.map(\.name) == ["bug", "ci"])
 58        #expect(model.state.value?.allSatisfy(\.org) == true)
 59    }
 60
 61    @Test func setAndRemoveUseTheOrgCommands() async throws {
 62        let (client, stub) = try makeClient()
 63        stub.enqueue(.init(status: 200, json: orgLabelsJSON))
 64        let model = LabelListViewModel(client: client, owner: .org("krz"))
 65        await model.load()
 66        for _ in 0..<2 {
 67            stub.enqueue(.init(status: 200, json: okJSON, match: "cmd"))
 68            stub.enqueue(.init(status: 200, json: orgLabelsJSON, match: "argv=list"))
 69        }
 70
 71        await model.setLabel("bug", color: "cf222e")
 72        await model.remove("ci")
 73
 74        let writes = try stub.seen.filter { $0.method == "POST" }.map(argvOf)
 75        #expect(writes == [
 76            ["org", "label", "set", "krz", "bug", "--color", "cf222e"],
 77            ["org", "label", "remove", "krz", "ci"],
 78        ])
 79    }
 80}
 81
 82@MainActor
 83struct OrgMilestoneListTests {
 84
 85    @Test func anOrgListsItsMilestonesWithTheState() async throws {
 86        let (client, stub) = try makeClient()
 87        stub.enqueue(.init(status: 200, json: orgMilestonesJSON))
 88        let model = MilestoneListViewModel(client: client, owner: .org("krz"))
 89
 90        await model.load()
 91
 92        #expect(stub.seen.first?.url.query()
 93            == "argv=org&argv=milestone&argv=list&argv=krz&argv=--state&argv=open")
 94        #expect(model.state.value?.map(\.title) == ["v2.0.0"])
 95    }
 96
 97    @Test func createCloseAndReopenUseTheOrgCommands() async throws {
 98        let (client, stub) = try makeClient()
 99        stub.enqueue(.init(status: 200, json: orgMilestonesJSON))
100        let model = MilestoneListViewModel(client: client, owner: .org("krz"))
101        await model.load()
102        for _ in 0..<3 {
103            stub.enqueue(.init(status: 200, json: okJSON, match: "cmd"))
104            stub.enqueue(.init(status: 200, json: orgMilestonesJSON, match: "argv=list"))
105        }
106
107        let ok = await model.create(title: "v2.1.0", description: "next", due: "2026-10-01")
108        await model.close("v2.0.0")
109        await model.reopen("v2.0.0")
110
111        #expect(ok)
112        let writes = try stub.seen.filter { $0.method == "POST" }.map(argvOf)
113        #expect(writes == [
114            ["org", "milestone", "create", "krz", "v2.1.0", "--description", "next", "--due", "2026-10-01"],
115            ["org", "milestone", "close", "krz", "v2.0.0"],
116            ["org", "milestone", "reopen", "krz", "v2.0.0"],
117        ])
118    }
119}