krz/hutch

an ios client for sourcehut

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

main: HutchTests/BuildListViewModelTests.swift · raw

  1import Foundation
  2import Testing
  3@testable import Hutch
  4
  5@MainActor
  6struct BuildListViewModelTests {
  7
  8    @Test
  9    func filteredJobsReturnsAllWhenSearchTextIsEmpty() {
 10        let jobs = [makeJob(id: 1, tags: ["ci"]), makeJob(id: 2, tags: [])]
 11        let filtered = filterJobs(jobs, query: "")
 12
 13        #expect(filtered.count == 2)
 14    }
 15
 16    @Test
 17    func filteredJobsMatchesByTag() {
 18        let jobs = [makeJob(id: 1, tags: ["ci", "deploy"]), makeJob(id: 2, tags: ["lint"])]
 19        let filtered = filterJobs(jobs, query: "deploy")
 20
 21        #expect(filtered.map(\.id) == [1])
 22    }
 23
 24    @Test
 25    func filteredJobsMatchesByJobId() {
 26        let jobs = [makeJob(id: 42, tags: []), makeJob(id: 99, tags: [])]
 27        let filtered = filterJobs(jobs, query: "42")
 28
 29        #expect(filtered.map(\.id) == [42])
 30    }
 31
 32    @Test
 33    func filteredJobsMatchesByStatus() {
 34        let jobs = [
 35            makeJob(id: 1, status: .running, tags: []),
 36            makeJob(id: 2, status: .success, tags: [])
 37        ]
 38
 39        let filtered = filterJobs(jobs, query: "running")
 40
 41        #expect(filtered.map(\.id) == [1])
 42    }
 43
 44    @Test
 45    func buildFilterPrioritizesActionableStates() {
 46        let jobs = [
 47            makeJob(id: 1, status: .success, tags: []),
 48            makeJob(id: 2, status: .failed, tags: []),
 49            makeJob(id: 3, status: .running, tags: []),
 50            makeJob(id: 4, status: .cancelled, tags: [])
 51        ]
 52
 53        let attention = BuildListViewModel.filterJobs(
 54            jobs,
 55            filter: .attention,
 56            lookbackDays: BuildListViewModel.defaultLookbackDays
 57        )
 58        let active = BuildListViewModel.filterJobs(
 59            jobs,
 60            filter: .active,
 61            lookbackDays: BuildListViewModel.defaultLookbackDays
 62        )
 63        let failed = BuildListViewModel.filterJobs(
 64            jobs,
 65            filter: .failed,
 66            lookbackDays: BuildListViewModel.defaultLookbackDays
 67        )
 68
 69        #expect(attention.map(\.id) == [2, 3])
 70        #expect(active.map(\.id) == [3])
 71        #expect(failed.map(\.id) == [2])
 72    }
 73
 74    @Test
 75    func buildFilterRestrictsJobsToSelectedLookbackWindow() {
 76        let now = Date(timeIntervalSince1970: 60 * 60 * 24 * 20)
 77        let jobs = [
 78            makeJob(
 79                id: 1,
 80                status: .failed,
 81                tags: [],
 82                updated: now.addingTimeInterval(-(60 * 60 * 24))
 83            ),
 84            makeJob(
 85                id: 2,
 86                status: .running,
 87                tags: [],
 88                updated: now.addingTimeInterval(-(60 * 60 * 24 * 8))
 89            ),
 90            makeJob(
 91                id: 3,
 92                status: .success,
 93                tags: [],
 94                updated: now.addingTimeInterval(-(60 * 60 * 24 * 2))
 95            ),
 96        ]
 97
 98        let filtered = BuildListViewModel.filterJobs(
 99            jobs,
100            filter: .all,
101            lookbackDays: 3,
102            now: now,
103            calendar: Calendar(identifier: .gregorian)
104        )
105
106        #expect(filtered.map(\.id) == [1, 3])
107    }
108
109    private func filterJobs(_ jobs: [JobSummary], query: String) -> [JobSummary] {
110        BuildListViewModel.searchJobs(jobs, matching: query)
111    }
112
113    private func makeJob(
114        id: Int,
115        status: JobStatus = .success,
116        tags: [String],
117        updated: Date = Date()
118    ) -> JobSummary {
119        JobSummary(
120            id: id,
121            created: updated,
122            updated: updated,
123            status: status,
124            note: nil,
125            tags: tags,
126            visibility: nil,
127            image: nil,
128            tasks: []
129        )
130    }
131}