From ffc0ef0988b5e7d01951c23af85a1cf026b3da9f Mon Sep 17 00:00:00 2001 From: Christian Cleberg Date: Wed, 18 Mar 2026 22:56:34 -0500 Subject: add Home dashboard and repository build status indicators --- HutchTests/HomeViewModelTests.swift | 67 +++++++++++++++++++++++++++ HutchTests/RepositoryListViewModelTests.swift | 26 +++++++++++ 2 files changed, 93 insertions(+) create mode 100644 HutchTests/HomeViewModelTests.swift (limited to 'HutchTests') diff --git a/HutchTests/HomeViewModelTests.swift b/HutchTests/HomeViewModelTests.swift new file mode 100644 index 0000000..5475bdd --- /dev/null +++ b/HutchTests/HomeViewModelTests.swift @@ -0,0 +1,67 @@ +import Foundation +import Testing +@testable import Hutch + +struct HomeViewModelTests { + + @Test + func failedBuildsKeepsOnlyFailedAndTimedOutJobs() { + let jobs = [ + makeJob(id: 1, status: .success, created: Date(timeIntervalSince1970: 10)), + makeJob(id: 2, status: .failed, created: Date(timeIntervalSince1970: 20)), + makeJob(id: 3, status: .timeout, created: Date(timeIntervalSince1970: 30)), + makeJob(id: 4, status: .running, created: Date(timeIntervalSince1970: 40)) + ] + + let failedBuilds = HomeViewModel.failedBuilds(from: jobs) + + #expect(failedBuilds.map(\.job.id) == [2, 3]) + } + + @Test + func matchesCurrentUserAssigneeNormalizesCanonicalNameAndUsername() { + let currentUser = User( + id: 42, + username: "owner", + canonicalName: "~owner", + email: "owner@example.com", + avatar: nil + ) + + #expect(HomeViewModel.matchesCurrentUserAssignee(Entity(canonicalName: "~owner"), currentUser: currentUser)) + #expect(HomeViewModel.matchesCurrentUserAssignee(Entity(canonicalName: "owner"), currentUser: currentUser)) + #expect(HomeViewModel.matchesCurrentUserAssignee(Entity(canonicalName: currentUser.username), currentUser: currentUser)) + #expect(HomeViewModel.matchesCurrentUserAssignee(Entity(canonicalName: "~someone-else"), currentUser: currentUser) == false) + } + + @Test + func primaryRepositoryReferenceParsesManifestSourceURL() { + let manifest = """ + image: alpine/latest + sources: + - https://git.sr.ht/~owner/hutch + tasks: + - true + """ + + let repository = HomeViewModel.primaryRepositoryReference(in: manifest) + + #expect(repository?.ownerCanonicalName == "~owner") + #expect(repository?.name == "hutch") + } + + private func makeJob(id: Int, status: JobStatus, created: Date) -> HomeJobPayload { + HomeJobPayload( + id: id, + created: created, + updated: created, + status: status, + note: nil, + tags: [], + visibility: nil, + image: nil, + tasks: [], + manifest: nil + ) + } +} diff --git a/HutchTests/RepositoryListViewModelTests.swift b/HutchTests/RepositoryListViewModelTests.swift index d6e76bf..7bd9126 100644 --- a/HutchTests/RepositoryListViewModelTests.swift +++ b/HutchTests/RepositoryListViewModelTests.swift @@ -28,6 +28,32 @@ struct RepositoryListViewModelTests { #expect(descriptionMatches.map(\.id) == [2]) } + @Test + func buildStatusKeysParsesSourceHutRepositoryURLsFromManifest() { + let manifest = """ + image: alpine/latest + sources: + - https://git.sr.ht/~owner/hutch + - ssh://hg@hg.sr.ht/~owner/wiki + tasks: + - echo "build" + """ + + let keys = RepositoryListViewModel.buildStatusKeys(in: manifest) + + #expect(keys.contains("git|~owner|hutch")) + #expect(keys.contains("hg|~owner|wiki")) + } + + @Test + func repositoryBuildStatusMapsJobStatesToRowStates() { + #expect(RepositoryListViewModel.repositoryBuildStatus(for: .success) == .success) + #expect(RepositoryListViewModel.repositoryBuildStatus(for: .running) == .running) + #expect(RepositoryListViewModel.repositoryBuildStatus(for: .queued) == .running) + #expect(RepositoryListViewModel.repositoryBuildStatus(for: .failed) == .failed) + #expect(RepositoryListViewModel.repositoryBuildStatus(for: .timeout) == .failed) + } + @MainActor private func makeRepository( id: Int, -- cgit v1.2.3