Files
gentpan c9d722f20d 账号同步、磁盘工具、IP 归属地数据源与纯净度、弹窗与设置调整
- 账号与同步:GitHub / Google / Apple 登录后把菜单栏项目与风格等偏好同步到 getopenstats.com,换一台 Mac 登录即恢复(AccountSync 模块、SyncController、SettingsDocument、账号设置页,openstats:// 回调)
- 磁盘页成为工具页:已用 / 可清除 / 可用分段容量条、空间分析、文件系统检查、本地快照清理(辅助工具协议 v4)、其他磁盘推出
- 公网 IP:归属地数据源可选 CleanIP.io / ipapi.is / DB-IP / ipinfo.io / 本地 GeoLite2,每台 Mac 自己查、本地缓存 7 天;IPv4 / IPv6 双栈各自查询与切换;弹窗显示 ASN、运营方、原生 / 住宅等徽章与纯净度评分色带;接口区块可重置上传 / 下载统计
- 弹窗:右上角按钮改为该指标自己的图标 + 总设置;主窗口页面标题栏的开关点不动已修复;滚动条改为悬浮式,内容不再偏左;网络弹窗卡片被标题行撑宽的问题已修复
- 设置:⌘ 拖动排序说明;每个菜单栏项目单独选风格并带实时预览;网络与磁盘的进程榜单固定 5 行并平滑排序;CPU 持续高负载通知
- 设计系统:分段条、评分色带、标签徽章、胶囊切换、刷新按钮等组件与徽章配色 token
- 更新日志、架构说明、README 与译文同步
2026-09-15 03:37:24 +05:00

77 lines
3.8 KiB
Swift

import Foundation
import Testing
@testable import Cleaner
@Suite struct LocalSnapshotsTests {
@Test func parsesTmutilOutput() {
let output = """
Snapshots for disk /:
com.apple.TimeMachine.2026-09-14-120000.local
com.apple.TimeMachine.2026-09-15-083015.local
com.apple.os.update-ABC
"""
let snapshots = LocalSnapshots.parse(output)
#expect(snapshots.map(\.identifier) == ["2026-09-15-083015", "2026-09-14-120000"])
#expect(snapshots.allSatisfy { $0.date != nil })
#expect(LocalSnapshots.parse("Snapshots for disk /:\n").isEmpty)
}
}
@Suite struct VolumeVerifierTests {
@Test func interpretsDiskutilOutput() {
let ok = VolumeVerifier.interpret(status: 0, output: "Checking the fsroot tree\nThe volume /dev/rdisk3s1 appears to be OK\nFile system check exit code is 0\n")
#expect(ok.ok)
let bad = VolumeVerifier.interpret(status: 8, output: "Checking the fsroot tree\nerror: btn: invalid key order\nFile system check exit code is 8\n")
#expect(!bad.ok)
#expect(bad.summary.contains("invalid key order"))
}
}
@Suite struct SpaceScannerTests {
private func scratch() throws -> URL {
let url = FileManager.default.temporaryDirectory.appendingPathComponent("openstats-space-\(UUID().uuidString)")
try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true)
return url
}
private func write(_ url: URL, bytes: Int) throws {
try FileManager.default.createDirectory(at: url.deletingLastPathComponent(), withIntermediateDirectories: true)
try Data(repeating: 0xAB, count: bytes).write(to: url)
}
@Test func sizesFoldersAndFindsLargestFiles() throws {
let root = try scratch()
defer { try? FileManager.default.removeItem(at: root) }
let big = 60_000_000
try write(root.appendingPathComponent("Movies/holiday.mov"), bytes: big)
try write(root.appendingPathComponent("Documents/notes.txt"), bytes: 1_000)
try write(root.appendingPathComponent("Documents/Photos.photoslibrary/data/1.jpg"), bytes: big)
try write(root.appendingPathComponent("Documents/Photos.photoslibrary/data/2.jpg"), bytes: big)
try write(root.appendingPathComponent("loose.bin"), bytes: big)
nonisolated(unsafe) var reports = 0
let result = try SpaceScanner.scan(root: root) { _ in reports += 1 }
#expect(result.folders.first?.name == "Documents")
#expect(result.folders.map(\.name).contains("Movies"))
#expect(result.totalBytes >= UInt64(4 * big))
#expect(reports > 0)
// 图库按整体算一个,里面的照片不单独出现
let names = result.largestFiles.map(\.name)
#expect(names.first == "Photos.photoslibrary")
#expect(names.contains("holiday.mov") && names.contains("loose.bin"))
#expect(!names.contains("1.jpg"))
#expect(!names.contains("notes.txt"))
}
@Test func trashRulesStayInsideHomeAndAwayFromLibrary() {
let home = URL(fileURLWithPath: "/Users/tester")
#expect(SpaceScanner.canTrash(home.appendingPathComponent("Downloads/big.dmg"), home: home))
#expect(SpaceScanner.canTrash(home.appendingPathComponent("Movies/a/b.mov"), home: home))
#expect(!SpaceScanner.canTrash(home.appendingPathComponent("Library/Caches/x"), home: home))
#expect(!SpaceScanner.canTrash(home.appendingPathComponent("Downloads"), home: home))
#expect(!SpaceScanner.canTrash(home.appendingPathComponent(".docker/data.raw"), home: home))
#expect(!SpaceScanner.canTrash(URL(fileURLWithPath: "/Applications/Xcode.app"), home: home))
#expect(!SpaceScanner.canTrash(home.appendingPathComponent("Downloads/../../other/file"), home: home))
}
}