krz/hutch

an ios client for sourcehut

clone: git clone https://gitbay.org/krz/hutch.git

remove-splash-highlighter: HutchTests/PatchsetTests.swift · raw

  1import Foundation
  2import Testing
  3@testable import Hutch
  4
  5struct PatchsetStatusTests {
  6
  7    @Test
  8    func statusRawValuesMatchTheGraphQLEnum() {
  9        // lists.sr.ht's PatchsetStatus enum values, which are sent verbatim to
 10        // updatePatchset.
 11        #expect(PatchsetStatus.unknown.rawValue == "UNKNOWN")
 12        #expect(PatchsetStatus.proposed.rawValue == "PROPOSED")
 13        #expect(PatchsetStatus.needsRevision.rawValue == "NEEDS_REVISION")
 14        #expect(PatchsetStatus.superseded.rawValue == "SUPERSEDED")
 15        #expect(PatchsetStatus.approved.rawValue == "APPROVED")
 16        #expect(PatchsetStatus.rejected.rawValue == "REJECTED")
 17        #expect(PatchsetStatus.applied.rawValue == "APPLIED")
 18    }
 19
 20    @Test
 21    func assignableStatusesExcludeServerManagedOnes() {
 22        // UNKNOWN is a sentinel and SUPERSEDED is set by the server when a newer
 23        // version lands, so neither should be offered as a reviewer choice.
 24        #expect(!PatchsetStatus.assignable.contains(.unknown))
 25        #expect(!PatchsetStatus.assignable.contains(.superseded))
 26        #expect(PatchsetStatus.assignable.contains(.approved))
 27        #expect(PatchsetStatus.assignable.contains(.rejected))
 28        #expect(PatchsetStatus.assignable.contains(.applied))
 29        #expect(PatchsetStatus.assignable.contains(.needsRevision))
 30        #expect(PatchsetStatus.assignable.contains(.proposed))
 31    }
 32
 33    @Test
 34    func openStatusesAreThoseAwaitingADecision() {
 35        #expect(PatchsetStatus.proposed.isOpen)
 36        #expect(PatchsetStatus.needsRevision.isOpen)
 37        #expect(!PatchsetStatus.applied.isOpen)
 38        #expect(!PatchsetStatus.rejected.isOpen)
 39        #expect(!PatchsetStatus.superseded.isOpen)
 40    }
 41
 42    @Test
 43    func statusDecodesFromTheWireFormat() throws {
 44        let decoded = try JSONDecoder().decode(PatchsetStatus.self, from: Data("\"NEEDS_REVISION\"".utf8))
 45        #expect(decoded == .needsRevision)
 46    }
 47}
 48
 49struct PatchsetSummaryTests {
 50
 51    @Test
 52    func versionLabelIsHiddenForFirstVersion() {
 53        let summary = PatchsetSummary(
 54            id: 1,
 55            subject: "[PATCH] fix the thing",
 56            version: 1,
 57            prefix: nil,
 58            status: .proposed
 59        )
 60
 61        #expect(summary.versionLabel == nil)
 62    }
 63
 64    @Test
 65    func versionLabelIsShownForRevisions() {
 66        let summary = PatchsetSummary(
 67            id: 1,
 68            subject: "[PATCH v3] fix the thing",
 69            version: 3,
 70            prefix: nil,
 71            status: .proposed
 72        )
 73
 74        #expect(summary.versionLabel == "v3")
 75    }
 76}
 77
 78@MainActor
 79struct PatchsetOrderingTests {
 80
 81    private func makePatch(id: Int, index: Int?, count: Int?) -> PatchsetEmail {
 82        PatchsetEmail(
 83            id: id,
 84            subject: "patch \(id)",
 85            date: nil,
 86            sender: Entity(canonicalName: "~someone"),
 87            contentBlocks: [],
 88            index: index,
 89            count: count
 90        )
 91    }
 92
 93    @Test
 94    func patchesAreOrderedBySeriesIndexNotReceiptOrder() {
 95        let patches = [
 96            makePatch(id: 30, index: 3, count: 3),
 97            makePatch(id: 10, index: 1, count: 3),
 98            makePatch(id: 20, index: 2, count: 3)
 99        ]
100
101        let ordered = PatchsetDetailViewModel.orderPatches(patches)
102
103        #expect(ordered.map(\.index) == [1, 2, 3])
104    }
105
106    @Test
107    func unindexedPatchesAreKeptAtTheEndRatherThanDropped() {
108        let patches = [
109            makePatch(id: 99, index: nil, count: nil),
110            makePatch(id: 20, index: 2, count: 2),
111            makePatch(id: 10, index: 1, count: 2)
112        ]
113
114        let ordered = PatchsetDetailViewModel.orderPatches(patches)
115
116        #expect(ordered.count == 3)
117        #expect(ordered.map(\.index) == [1, 2, nil])
118    }
119
120    @Test
121    func orderingIsStableForASingleUnindexedPatch() {
122        // A lone patch with no [PATCH n/m] prefix is the common one-off case.
123        let patches = [makePatch(id: 1, index: nil, count: nil)]
124
125        let ordered = PatchsetDetailViewModel.orderPatches(patches)
126
127        #expect(ordered.map(\.id) == [1])
128    }
129
130    @Test
131    func seriesLabelIsHiddenForSinglePatchSeries() {
132        let patch = makePatch(id: 1, index: 1, count: 1)
133        #expect(patch.seriesLabel == nil)
134    }
135
136    @Test
137    func seriesLabelShowsPositionForMultiPatchSeries() {
138        let patch = makePatch(id: 1, index: 2, count: 5)
139        #expect(patch.seriesLabel == "2/5")
140    }
141}