test: expand overlay coverage

This commit is contained in:
Peter Steinberger
2025-12-24 17:42:34 +01:00
parent 49e466dd40
commit f4fb80e523
9 changed files with 168 additions and 2 deletions

View File

@@ -631,3 +631,81 @@ enum CritterIconRenderer {
canvas.context.restoreGState()
}
}
#if DEBUG
@MainActor
extension CritterStatusLabel {
static func exerciseForTesting() async {
var label = CritterStatusLabel(
isPaused: false,
isSleeping: false,
isWorking: true,
earBoostActive: false,
blinkTick: 1,
sendCelebrationTick: 1,
gatewayStatus: .running(details: nil),
animationsEnabled: true,
iconState: .workingMain(.tool(.bash)))
_ = label.body
_ = label.iconImage
_ = label.tickTaskID
label.tick(Date())
label.resetMotion()
label.blink()
label.wiggle()
label.wiggleLegs()
label.wiggleEars()
label.scurry()
label.scheduleRandomTimers(from: Date())
_ = label.gatewayNeedsAttention
_ = label.gatewayBadgeColor
label.isPaused = true
_ = label.iconImage
label.isPaused = false
label.isSleeping = true
_ = label.iconImage
label.isSleeping = false
label.iconState = .idle
_ = label.iconImage
let failed = CritterStatusLabel(
isPaused: false,
isSleeping: false,
isWorking: false,
earBoostActive: false,
blinkTick: 0,
sendCelebrationTick: 0,
gatewayStatus: .failed("boom"),
animationsEnabled: false,
iconState: .idle)
_ = failed.gatewayNeedsAttention
_ = failed.gatewayBadgeColor
let stopped = CritterStatusLabel(
isPaused: false,
isSleeping: false,
isWorking: false,
earBoostActive: false,
blinkTick: 0,
sendCelebrationTick: 0,
gatewayStatus: .stopped,
animationsEnabled: false,
iconState: .idle)
_ = stopped.gatewayNeedsAttention
_ = stopped.gatewayBadgeColor
_ = CritterIconRenderer.makeIcon(
blink: 0.6,
legWiggle: 0.8,
earWiggle: 0.4,
earScale: 1.4,
earHoles: true,
eyesClosedLines: true,
badge: .init(symbolName: "gearshape.fill", prominence: .secondary))
}
}
#endif

View File

@@ -215,6 +215,7 @@ final class HoverHUDController {
}
private func installDismissMonitor() {
if ProcessInfo.processInfo.isRunningTests { return }
guard self.dismissMonitor == nil, let window else { return }
self.dismissMonitor = NSEvent.addGlobalMonitorForEvents(matching: [
.leftMouseDown,

View File

@@ -271,6 +271,9 @@ final class PermissionMonitor {
private func startMonitoring() {
Task { await self.checkStatus(force: true) }
if ProcessInfo.processInfo.isRunningTests {
return
}
self.monitorTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
guard let self else { return }
Task { @MainActor in

View File

@@ -25,6 +25,7 @@ final class VoicePushToTalkHotkey: @unchecked Sendable {
}
func setEnabled(_ enabled: Bool) {
if ProcessInfo.processInfo.isRunningTests { return }
self.withMainThread { [weak self] in
guard let self else { return }
if enabled {

View File

@@ -855,3 +855,51 @@ private final class TranscriptNSTextView: NSTextView {
super.keyDown(with: event)
}
}
#if DEBUG
@MainActor
extension VoiceWakeOverlayController {
static func exerciseForTesting() async {
let controller = VoiceWakeOverlayController(enableUI: false)
let token = controller.startSession(
source: .wakeWord,
transcript: "Hello",
attributed: nil,
forwardEnabled: true,
isFinal: false)
controller.updatePartial(token: token, transcript: "Hello world")
controller.presentFinal(token: token, transcript: "Final", autoSendAfter: nil)
controller.userBeganEditing()
controller.endEditing()
controller.updateText("Edited text")
_ = controller.makeAttributed(from: "Attributed")
_ = controller.targetFrame()
_ = controller.measuredHeight()
_ = controller.dismissTargetFrame(
for: NSRect(x: 0, y: 0, width: 120, height: 60),
reason: .empty,
outcome: .empty)
_ = controller.dismissTargetFrame(
for: NSRect(x: 0, y: 0, width: 120, height: 60),
reason: .explicit,
outcome: .sent)
_ = controller.dismissTargetFrame(
for: NSRect(x: 0, y: 0, width: 120, height: 60),
reason: .explicit,
outcome: .empty)
controller.beginSendUI(token: token, sendChime: .none)
try? await Task.sleep(nanoseconds: 350_000_000)
controller.scheduleAutoSend(token: token, after: 10)
controller.autoSendTask?.cancel()
controller.autoSendTask = nil
controller.autoSendToken = nil
controller.dismiss(token: token, reason: .explicit, outcome: .sent)
controller.bringToFrontIfVisible()
}
}
#endif

View File

@@ -230,6 +230,7 @@ final class WebChatSwiftUIWindowController {
}
private func installDismissMonitor() {
if ProcessInfo.processInfo.isRunningTests { return }
guard self.dismissMonitor == nil, self.window != nil else { return }
self.dismissMonitor = NSEvent.addGlobalMonitorForEvents(
matching: [.leftMouseDown, .rightMouseDown, .otherMouseDown])

View File

@@ -30,5 +30,8 @@ struct CritterIconRendererTests {
#expect(image.tiffRepresentation != nil)
}
}
@Test func critterStatusLabelExercisesHelpers() async {
await CritterStatusLabel.exerciseForTesting()
}
}

View File

@@ -0,0 +1,26 @@
import AppKit
import Testing
@testable import Clawdis
@Suite(.serialized)
@MainActor
struct HoverHUDControllerTests {
@Test func hoverHUDControllerPresentsAndDismisses() async {
let controller = HoverHUDController()
controller.setSuppressed(false)
controller.statusItemHoverChanged(
inside: true,
anchorProvider: { NSRect(x: 10, y: 10, width: 24, height: 24) })
try? await Task.sleep(nanoseconds: 260_000_000)
controller.panelHoverChanged(inside: true)
controller.panelHoverChanged(inside: false)
controller.statusItemHoverChanged(
inside: false,
anchorProvider: { NSRect(x: 10, y: 10, width: 24, height: 24) })
controller.dismiss(reason: "test")
controller.setSuppressed(true)
}
}

View File

@@ -5,7 +5,7 @@ import Testing
@Suite(.serialized)
@MainActor
struct VoiceWakeOverlayControllerTests {
@Test func overlayControllerLifecycleWithoutUI() {
@Test func overlayControllerLifecycleWithoutUI() async {
let controller = VoiceWakeOverlayController(enableUI: false)
let token = controller.startSession(
source: .wakeWord,
@@ -22,6 +22,7 @@ struct VoiceWakeOverlayControllerTests {
controller.updateLevel(token: token, -0.5)
#expect(controller.model.level == 0)
try? await Task.sleep(nanoseconds: 120_000_000)
controller.updateLevel(token: token, 2.0)
#expect(controller.model.level == 1)
@@ -60,4 +61,8 @@ struct VoiceWakeOverlayControllerTests {
controller.updateLevel(token: token, 0.9)
#expect(controller.model.level == 0.9)
}
@Test func overlayControllerExercisesHelpers() async {
await VoiceWakeOverlayController.exerciseForTesting()
}
}