b13c84a91187
enforce 100% physical source coverage and inject desktop adapter (v0.6.0)
- time
- 2026-07-16 19:30 UTC · 3 months ago
- machine
- koh2
- agent
- minimax-m3
- session
- complete source coverage gate
- parent
- ed611667ffbb
↓ haven-b13c84a9.tar.gzatlas at this save
files changed5 files
README.md+12 −0Sources/Haven/Managers/WallpaperManager.swift+17 −7Sources/Haven/main.swift+1 −1Tests/HavenTests/ManagerTests.swift+20 −7coverage.sh+85 −0README.md+12 −0
@@ -42,6 +42,18 @@4242 swift run4343 ```4444 45+Run the full test suite and the checked-in 100% physical source-line coverage gate:46+47+```sh48+./coverage.sh49+```50+51+The coverage command combines `swift test --enable-code-coverage` with a52+smoke run of the executable so the real entry point is measured. Its physical53+source-line gate excludes blank, comment-only, and structural brace lines;54+the LLVM aggregate report printed above it also includes compiler-generated55+SwiftUI mappings and can therefore be lower.56+4557 Haven lives in the menu bar (it has no Dock icon). Click the menu bar icon to4658 open the popover.4759 Sources/Haven/Managers/WallpaperManager.swift+17 −7
@@ -7,6 +7,15 @@77 func saveToFolder(from sourceURL: URL, to folderURL: URL) throws88 }99 10+@MainActor11+protocol DesktopImageSetting {12+ func setDesktopImageURL(13+ _ url: URL, for screen: NSScreen, options: [NSWorkspace.DesktopImageOptionKey: Any]14+ ) throws15+}16+17+extension NSWorkspace: DesktopImageSetting {}18+1019 class WallpaperManager: WallpaperManaging {1120 static let shared = WallpaperManager()1221 @@ -15,15 +24,16 @@1524 1625 init(1726 session: URLSession = .shared,18- desktopSetter: @escaping @MainActor (URL, NSScreen) throws -> Void =19- WallpaperManager.applyDesktopImage27+ desktopSetter: (@MainActor (URL, NSScreen) throws -> Void)? = nil,28+ workspace: DesktopImageSetting = NSWorkspace.shared2029 ) {2130 self.session = session22- self.desktopSetter = desktopSetter23- }24-25- private static func applyDesktopImage(_ url: URL, _ screen: NSScreen) throws {26- try NSWorkspace.shared.setDesktopImageURL(url, for: screen, options: [:])31+ self.desktopSetter =32+ desktopSetter ?? { url, screen in33+ try workspace.setDesktopImageURL(34+ url, for: screen, options: [:]35+ )36+ }2737 }2838 2939 /// Downloads the file to a temporary location and returns the local URL.Sources/Haven/main.swift+1 −1
@@ -6,4 +6,4 @@66 delegate: delegate,77 shouldRun: ProcessInfo.processInfo.environment["HAVEN_COVERAGE_SMOKE"] != "1",88 setDelegate: { app.delegate = $0 },9- run: { app.run() })9+ run: app.run)Tests/HavenTests/ManagerTests.swift+20 −7
@@ -38,6 +38,17 @@3838 "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII="3939 )!4040 41+@MainActor42+private final class DesktopImageStub: DesktopImageSetting {43+ var receivedURLs: [URL] = []44+45+ func setDesktopImageURL(46+ _ url: URL, for screen: NSScreen, options: [NSWorkspace.DesktopImageOptionKey: Any]47+ ) throws {48+ receivedURLs.append(url)49+ }50+}51+4152 @Suite("Favorites persistence", .serialized)4253 struct FavoritesManagerTests {4354 private let defaultsKey = "favoriteWallpapers"@@ -194,14 +205,16 @@194205 #expect(received[0] === screen)195206 }196207 197- @Test("Default desktop adapter reports invalid local files")198- func defaultDesktopAdapter() {208+ @Test("Default desktop adapter forwards the image to its workspace")209+ func defaultDesktopAdapter() throws {199210 guard let screen = NSScreen.screens.first else { return }200- let manager = WallpaperManager()201- #expect(throws: Error.self) {202- try manager.setDesktopImage(203- from: URL(fileURLWithPath: "/definitely-missing-haven-wallpaper.jpg"), screen: screen)204- }211+ let workspace = DesktopImageStub()212+ let manager = WallpaperManager(workspace: workspace)213+ let url = URL(fileURLWithPath: "/tmp/test-wallpaper.jpg")214+215+ try manager.setDesktopImage(from: url, screen: screen)216+217+ #expect(workspace.receivedURLs == [url])205218 }206219 207220 @Test("Set wallpaper composes download and desktop update")coverage.sh+85 −0
@@ -0,0 +1,85 @@1+#!/bin/bash2+# Run the full Haven test suite and enforce physical source-line coverage.3+set -euo pipefail4+5+REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"6+cd "${REPO_ROOT}"7+8+workdir="$(mktemp -d "${TMPDIR:-/tmp}/haven-coverage.XXXXXX")"9+cleanup() { trash "${workdir}"; }10+trap cleanup EXIT11+12+swift test --enable-code-coverage13+14+binary=".build/debug/Haven"15+test_profile=".build/debug/codecov/default.profdata"16+smoke_profile="${workdir}/smoke.profraw"17+merged_profile="${workdir}/merged.profdata"18+19+LLVM_PROFILE_FILE="${smoke_profile}" HAVEN_COVERAGE_SMOKE=1 "${binary}"20+test -s "${smoke_profile}"21+xcrun llvm-profdata merge -sparse "${test_profile}" "${smoke_profile}" -o "${merged_profile}"22+23+printf '\nLLVM aggregate report (compiler-generated mappings included):\n'24+xcrun llvm-cov report "${binary}" \25+ -instr-profile="${merged_profile}" \26+ --ignore-filename-regex='(Tests|\\.build)'27+28+xcrun llvm-cov export "${binary}" \29+ -instr-profile="${merged_profile}" \30+ -format=text > "${workdir}/coverage.json"31+32+REPO_ROOT="${REPO_ROOT}" COVERAGE_JSON="${workdir}/coverage.json" python3 <<'PY'33+import json34+import os35+from pathlib import Path36+37+repo_root = Path(os.environ["REPO_ROOT"]).resolve()38+repo_prefix = f"{repo_root.as_posix().rstrip('/')}/"39+coverage = json.loads(Path(os.environ["COVERAGE_JSON"]).read_text())40+41+covered = 042+total = 043+missed = []44+45+for entry in coverage["data"][0]["files"]:46+ source_path = Path(entry["filename"]).resolve()47+ source_text = source_path.as_posix()48+ if not source_text.casefold().startswith(repo_prefix.casefold()):49+ continue50+ relative_path = Path(source_text[len(repo_prefix) :])51+ if relative_path.parts[:2] != ("Sources", "Haven"):52+ continue53+54+ source_lines = source_path.read_text().splitlines()55+ line_counts = {}56+ for segment in entry["segments"]:57+ line, _, count, has_count, *_ = segment58+ if has_count:59+ line_counts[line] = max(line_counts.get(line, 0), count)60+61+ for line, count in sorted(line_counts.items()):62+ if line > len(source_lines):63+ continue64+ text = source_lines[line - 1].strip()65+ if (66+ not text67+ or text.startswith("//")68+ or text.startswith("/*")69+ or text.startswith("*")70+ or text.startswith("*/")71+ or not any(character.isalnum() for character in text)72+ ):73+ continue74+ total += 175+ if count > 0:76+ covered += 177+ else:78+ missed.append(f"{relative_path}:{line}: {text}")79+80+print(f"\nPhysical repository source lines: {covered}/{total} covered")81+if missed:82+ print("Uncovered physical source lines:")83+ print("\n".join(missed))84+ raise SystemExit(1)85+PY