Files
ggbond268--mactools/Tests/App/MenuBarIconSettingsTests.swift
wehub-resource-sync 1d1286fadb
Build / Build and test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:18:38 +08:00

192 lines
7.7 KiB
Swift

import AppKit
import XCTest
@testable import MacTools
@MainActor
final class MenuBarIconSettingsTests: XCTestCase {
private var suiteName: String!
private var userDefaults: UserDefaults!
private var rootDirectory: URL!
override func setUpWithError() throws {
try super.setUpWithError()
suiteName = "MenuBarIconSettingsTests-\(UUID().uuidString)"
userDefaults = UserDefaults(suiteName: suiteName)!
rootDirectory = FileManager.default.temporaryDirectory
.appendingPathComponent("MenuBarIconSettingsTests-\(UUID().uuidString)", isDirectory: true)
}
override func tearDownWithError() throws {
if let suiteName {
UserDefaults(suiteName: suiteName)?.removePersistentDomain(forName: suiteName)
}
if let rootDirectory {
try? FileManager.default.removeItem(at: rootDirectory)
}
try super.tearDownWithError()
}
func testImportPersistsCustomIconAndRecentItem() throws {
let sourceURL = try makeImageFile(name: "status-icon.png", color: .systemBlue)
let settings = MenuBarIconSettings(userDefaults: userDefaults, rootDirectory: rootDirectory)
settings.importIcon(from: sourceURL, for: .light)
let payload = settings.imagePayload(for: NSAppearance(named: .aqua))
XCTAssertTrue(settings.hasCustomIcon)
XCTAssertNil(settings.lastErrorMessage)
XCTAssertEqual(settings.recentItems.first?.displayName, "status-icon")
XCTAssertFalse(payload.isTemplate)
XCTAssertEqual(payload.image.size, NSSize(width: 18, height: 18))
let reloadedSettings = MenuBarIconSettings(userDefaults: userDefaults, rootDirectory: rootDirectory)
XCTAssertTrue(reloadedSettings.hasCustomIcon)
XCTAssertEqual(reloadedSettings.recentItems.count, 1)
}
func testDarkAppearanceFallsBackToLightCustomIcon() throws {
let sourceURL = try makeImageFile(name: "shared.png", color: .systemRed)
let settings = MenuBarIconSettings(userDefaults: userDefaults, rootDirectory: rootDirectory)
settings.importIcon(from: sourceURL, for: .light)
XCTAssertTrue(settings.hasCustomIcon)
XCTAssertEqual(
settings.imagePayload(for: NSAppearance(named: .darkAqua)).image.size,
NSSize(width: 18, height: 18)
)
}
func testRenderedImageNormalizesNonSquareSourceToStandardHeight() throws {
let sourceURL = try makeImageFile(
name: "wide.png",
color: .systemOrange,
size: NSSize(width: 120, height: 36)
)
let sourceImage = try XCTUnwrap(NSImage(contentsOf: sourceURL))
let renderedImage = try XCTUnwrap(MenuBarIconProcessing.renderedImage(from: sourceImage))
XCTAssertEqual(renderedImage.size.height, MenuBarIconProcessing.standardIconPointSize)
XCTAssertGreaterThan(renderedImage.size.width, MenuBarIconProcessing.standardIconPointSize)
}
func testGalleryPreviewUsesTheSameStandardHeight() async throws {
let sourceURL = try makeImageFile(
name: "gallery-wide.png",
color: .systemOrange,
size: NSSize(width: 120, height: 36)
)
let baseURL = URL(fileURLWithPath: sourceURL.deletingLastPathComponent().path + "/", isDirectory: true)
let asset = MenuBarIconGalleryAsset(
id: "gallery-wide",
title: "Gallery Wide",
categoryID: "tests",
version: "1",
previewPath: sourceURL.lastPathComponent,
framePaths: nil,
framePathPattern: nil,
archivePath: nil,
archiveFramePathPattern: nil,
frameCount: 1,
frameDuration: 1.0 / 6.0
)
let store = MenuBarIconRemoteAssetStore(rootDirectory: rootDirectory)
let preview = try await store.loadPreviewImage(
for: asset,
contentBaseURL: baseURL,
allowsFileResources: true
)
XCTAssertEqual(preview.size.height, MenuBarIconProcessing.standardIconPointSize)
XCTAssertGreaterThan(preview.size.width, MenuBarIconProcessing.standardIconPointSize)
}
func testAnimatedFramesShareVisibleBounds() throws {
let firstFrame = NSImage(size: NSSize(width: 120, height: 36))
firstFrame.lockFocus()
NSColor.systemOrange.setFill()
NSRect(x: 0, y: 0, width: 60, height: 36).fill()
firstFrame.unlockFocus()
let secondFrame = NSImage(size: NSSize(width: 120, height: 36))
secondFrame.lockFocus()
NSColor.systemOrange.setFill()
NSRect(x: 60, y: 0, width: 60, height: 36).fill()
secondFrame.unlockFocus()
let renderedFrames = MenuBarIconProcessing.renderedImages(from: [firstFrame, secondFrame])
guard renderedFrames.count == 2 else {
return XCTFail("Expected both animation frames to render.")
}
XCTAssertEqual(renderedFrames[0].size, renderedFrames[1].size)
XCTAssertEqual(renderedFrames[0].size.height, MenuBarIconProcessing.standardIconPointSize)
}
func testResetToDefaultClearsCustomSelectionButKeepsRecents() throws {
let sourceURL = try makeImageFile(name: "reset.png", color: .systemGreen)
let settings = MenuBarIconSettings(userDefaults: userDefaults, rootDirectory: rootDirectory)
settings.importIcon(from: sourceURL, for: .light)
settings.resetToDefault()
XCTAssertFalse(settings.hasCustomIcon)
XCTAssertEqual(settings.recentItems.count, 1)
XCTAssertTrue(settings.imagePayload(for: NSAppearance(named: .aqua)).isTemplate)
}
func testRecentItemsKeepOnlyLatestSix() throws {
let settings = MenuBarIconSettings(userDefaults: userDefaults, rootDirectory: rootDirectory)
for index in 0..<7 {
let sourceURL = try makeImageFile(name: "recent-\(index).png", color: .systemBlue)
settings.importIcon(from: sourceURL)
}
XCTAssertEqual(settings.recentItems.count, 6)
XCTAssertEqual(settings.recentItems.first?.displayName, "recent-6")
XCTAssertFalse(settings.recentItems.contains { $0.displayName == "recent-0" })
}
func testAnimationSpeedPolicyClampsAndUsesSystemLoad() {
XCTAssertEqual(
MenuBarIconAnimationSpeedPolicy.normalizedManualMultiplier(9),
MenuBarIconAnimationSpeedPolicy.maximumMultiplier
)
let lowLoadMultiplier = MenuBarIconAnimationSpeedPolicy.multiplier(
mode: .adaptiveSystemLoad,
manualMultiplier: 1,
systemLoad: MenuBarIconAnimationSystemLoad(cpuUsage: 0.1, gpuUsage: nil, memoryUsage: 0.2)
)
let highLoadMultiplier = MenuBarIconAnimationSpeedPolicy.multiplier(
mode: .adaptiveSystemLoad,
manualMultiplier: 1,
systemLoad: MenuBarIconAnimationSystemLoad(cpuUsage: 0.9, gpuUsage: 0.8, memoryUsage: 0.7)
)
XCTAssertGreaterThan(highLoadMultiplier, lowLoadMultiplier)
XCTAssertLessThanOrEqual(highLoadMultiplier, MenuBarIconAnimationSpeedPolicy.maximumMultiplier)
}
private func makeImageFile(
name: String,
color: NSColor,
size: NSSize = NSSize(width: 32, height: 32)
) throws -> URL {
let directory = rootDirectory.appendingPathComponent("Fixtures", isDirectory: true)
try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
let url = directory.appendingPathComponent(name)
let image = NSImage(size: size)
image.lockFocus()
color.setFill()
NSRect(origin: .zero, size: size).fill()
image.unlockFocus()
let data = try XCTUnwrap(MenuBarIconProcessing.pngData(from: image))
try data.write(to: url)
return url
}
}