Refresh puter UI, power telemetry and demand-aware monitoring
Build and test / macos (push) Waiting to run
Signed release / release (push) Waiting to run

This commit is contained in:
2026-09-22 20:03:16 -04:00
parent 0da94715be
commit 4bfa239aa0
38 changed files with 1728 additions and 492 deletions
@@ -0,0 +1,77 @@
import XCTest
@testable import puter
final class BatteryRegistryTests: XCTestCase {
func testChargingSeparatesLoadInputAndCapability() {
let result = BatteryRegistryReader.parse([
"BatteryInstalled": true, "ExternalConnected": true, "IsCharging": true,
"CurrentCapacity": 77, "Voltage": 12_500, "Amperage": 3_600,
"PowerTelemetryData": ["SystemLoad": 15_000, "SystemPowerIn": 61_000],
"AdapterDetails": ["Name": "140W USB-C Power Adapter", "Watts": 94,
"AdapterVoltage": 20_000, "Current": 4_700,
"UsbHvcMenu": [["MaxVoltage": 20_000, "MaxCurrent": 4_700]]]
])
XCTAssertTrue(result.isPresent)
XCTAssertEqual(result.systemPowerWatts, 15)
XCTAssertEqual(result.adapterInputWatts, 61)
XCTAssertEqual(result.measuredBatteryWatts, 45)
XCTAssertEqual(result.batteryFlowTitle, "Battery charging")
XCTAssertEqual(result.adapter?.negotiatedWatts, 94)
XCTAssertEqual(result.adapter?.profiles.count, 1)
}
func testUnsignedNegativeCurrentAndDisconnectedStaleAdapter() {
let result = BatteryRegistryReader.parse([
"BatteryInstalled": true, "ExternalConnected": false, "Voltage": 12_000,
"Amperage": NSNumber(value: UInt64(bitPattern: -2_000)),
"PowerTelemetryData": ["SystemPowerIn": 50_000],
"AdapterDetails": ["Watts": 94]
])
XCTAssertEqual(result.currentAmps, -2)
XCTAssertEqual(result.measuredBatteryWatts, 24)
XCTAssertEqual(result.batteryFlowTitle, "Battery discharge")
XCTAssertNil(result.adapter)
XCTAssertFalse(result.hasAdapterInput)
XCTAssertEqual(result.adapterInputWatts, 0)
}
func testZeroIsDifferentFromMissing() {
let idle = BatteryRegistryReader.parse(["BatteryInstalled": true, "Voltage": 12_000, "Amperage": 0])
XCTAssertEqual(idle.measuredBatteryWatts, 0)
XCTAssertEqual(idle.batteryFlowTitle, "Battery idle")
let absent = BatteryRegistryReader.parse([:])
XCTAssertNil(absent.measuredBatteryWatts)
XCTAssertFalse(absent.hasSystemPower)
XCTAssertEqual(absent.powerSourceDescription, "External power")
}
func testNestedCapacityOnNewerBatteryRegistry() {
let result = BatteryRegistryReader.parse(["BatteryInstalled": true,
"BatteryData": ["NominalChargeCapacity": 5630, "DesignCapacity": 6249, "RemainingCapacity": 4600]])
XCTAssertEqual(result.fullChargeCapacityMAh, 5630)
XCTAssertEqual(result.designCapacityMAh, 6249)
XCTAssertEqual(result.currentCapacityMAh, 4600)
XCTAssertEqual(result.healthPercent, 90.09, accuracy: 0.01)
XCTAssertFalse(result.hasBatteryTemperature)
}
func testInvalidPowerAndCurrentAreNotMeasurements() {
let result = BatteryRegistryReader.parse([
"BatteryInstalled": true, "Voltage": 12_000, "Amperage": 999_999,
"PowerTelemetryData": ["SystemLoad": Double.nan, "SystemPowerIn": -10]
])
XCTAssertNil(result.measuredBatteryWatts)
XCTAssertFalse(result.hasSystemPower)
XCTAssertFalse(result.hasAdapterInput)
}
func testOpenDropdownRequestsPowerButNotFullInventory() {
let demand = SamplingDemand(active: false, section: .processes, speed: .normal,
recording: false, alerts: false, menuBar: true, powerMenu: false,
menuPresented: true)
XCTAssertTrue(demand.hardware)
XCTAssertTrue(demand.telemetry)
XCTAssertFalse(demand.processInventory)
XCTAssertEqual(demand.interval, .seconds(5))
}
}
@@ -0,0 +1,37 @@
import XCTest
@testable import puter
final class ProcessGroupingTests: XCTestCase {
@MainActor
func testPrecomputedGroupsPreserveMemberSearchAndTotals() {
let records = [record(41, path: "/Applications/Example.app/Contents/MacOS/Example"),
record(42, path: "/Applications/Example.app/Contents/Helpers/Worker"),
record(43, path: "/usr/bin/tool")]
let groups = ProcessGrouping.groups(from: records, searchText: "")
XCTAssertEqual(groups.count, 2)
let app = ProcessGrouping.filtered(groups, searchText: "Example")
XCTAssertEqual(app.count, 1)
XCTAssertEqual(app.first?.processes.count, 2)
XCTAssertEqual(app.first?.cpu, 4)
let member = ProcessGrouping.filtered(groups, searchText: "42")
XCTAssertEqual(member.first?.processes.map(\.pid), [42])
XCTAssertEqual(member.first?.id, app.first?.id)
XCTAssertTrue(ProcessGrouping.filtered(groups, searchText: "unmatched").isEmpty)
}
@MainActor
func testPathCachePreservesSingletonsAndFreshTelemetry() {
let first = ProcessGrouping.groups(from: [record(41, path: "/usr/bin/tool")], searchText: "")
let second = ProcessGrouping.groups(from: [record(42, path: "/usr/bin/tool")], searchText: "")
XCTAssertNotEqual(first.first?.id, second.first?.id)
let mixedCase = ProcessGrouping.groups(from: [record(43, path: "/Applications/Test.APP/Contents/MacOS/Test")], searchText: "")
XCTAssertEqual(mixedCase.first?.appPath, "/Applications/Test.app")
}
private func record(_ pid: Int32, path: String) -> ProcessRecord {
ProcessRecord(pid: pid, parentPID: 1, name: "worker", executablePath: path,
user: "tester", cpu: 2, memoryPercent: 1, residentBytes: 1024,
state: "S", elapsed: "00:01", cpuTime: 0, threadCount: 1,
openFileCount: 0, architecture: "ARM64", priority: 31, nice: 0)
}
}
@@ -0,0 +1,66 @@
import XCTest
@testable import puter
final class SamplingDemandTests: XCTestCase {
func testNoConsumerMeansNoTimer() {
let demand = make(active: false)
XCTAssertNil(demand.interval)
XCTAssertFalse(demand.processInventory)
XCTAssertFalse(demand.hardware)
XCTAssertFalse(demand.services)
}
func testBackgroundMenuUsesLightweightCountersOnly() {
let demand = make(active: false, menu: true)
XCTAssertEqual(demand.interval, .seconds(10))
XCTAssertTrue(demand.telemetry)
XCTAssertFalse(demand.processInventory)
XCTAssertFalse(demand.services)
XCTAssertFalse(demand.hardware)
}
func testSettingsWithoutConsumersIsIdle() {
XCTAssertNil(make(section: .settings).interval)
}
func testServicesOnlyScansVisibleServices() {
let demand = make(section: .services)
XCTAssertTrue(demand.services)
XCTAssertFalse(demand.telemetry)
XCTAssertFalse(demand.processInventory)
XCTAssertEqual(demand.interval, .seconds(3))
}
func testRecordingKeepsBackgroundTelemetry() {
let demand = make(active: false, recording: true)
XCTAssertTrue(demand.processInventory)
XCTAssertTrue(demand.telemetry)
XCTAssertTrue(demand.hardware)
XCTAssertEqual(demand.interval, UpdateSpeed.normal.interval)
}
func testPauseStopsEvenRecordingTimer() {
XCTAssertNil(make(speed: .paused, recording: true, menu: true).interval)
}
func testPowerMenuOnlyNeedsHardware() {
let demand = make(active: false, menu: true, power: true)
XCTAssertTrue(demand.hardware)
XCTAssertFalse(demand.telemetry)
XCTAssertFalse(demand.processInventory)
}
func testAlertsRetainSystemSamplingWithoutProcessScan() {
let demand = make(active: false, alerts: true)
XCTAssertTrue(demand.telemetry)
XCTAssertFalse(demand.processInventory)
XCTAssertNotNil(demand.interval)
}
private func make(active: Bool = true, section: TaskSection = .processes,
speed: UpdateSpeed = .normal, recording: Bool = false,
alerts: Bool = false, menu: Bool = false, power: Bool = false) -> SamplingDemand {
SamplingDemand(active: active, section: section, speed: speed,
recording: recording, alerts: alerts, menuBar: menu, powerMenu: power)
}
}