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) } }