import AppKit import Testing @testable import Conjure @Test @MainActor func iconsScaleWithTypographyWithoutEnlargingSymbolsToApplicationSize() throws { _ = NSApplication.shared let artwork = NSImage(size: NSSize(width: 128, height: 128), flipped: false) { rect in NSColor.white.setFill() rect.fill() return true } var rendered: [(application: CGFloat, symbol: CGFloat)] = [] for (textSize, expectedApplicationSize): (CGFloat, CGFloat) in [(14, 22), (28, 44)] { let host = NSView(frame: NSRect(x: 0, y: 0, width: 100, height: 100)) let icon = IconView(font: .systemFont(ofSize: textSize, weight: .medium)) host.addSubview(icon) NSLayoutConstraint.activate([ icon.centerXAnchor.constraint(equalTo: host.centerXAnchor), icon.centerYAnchor.constraint(equalTo: host.centerYAnchor) ]) host.layoutSubtreeIfNeeded() #expect(icon.frame.size == NSSize(width: expectedApplicationSize, height: expectedApplicationSize)) func artworkHeight() throws -> CGFloat { let bitmap = try #require(icon.bitmapImageRepForCachingDisplay(in: icon.bounds)) icon.cacheDisplay(in: icon.bounds, to: bitmap) var first = bitmap.pixelsHigh var last = -1 for y in 0.. 0.5 { first = min(first, y) last = max(last, y) } } return CGFloat(last - first + 1) * icon.bounds.height / CGFloat(bitmap.pixelsHigh) } icon.image = artwork let applicationHeight = try artworkHeight() // Reuse the same slot, as launcher cells do when switching to command/calculator results. icon.image = NSImage(systemSymbolName: "stop.circle", accessibilityDescription: nil) let symbolHeight = try artworkHeight() #expect(applicationHeight == expectedApplicationSize) #expect(symbolHeight > textSize * 0.75 && symbolHeight <= textSize) icon.image = artwork #expect(try artworkHeight() == applicationHeight) rendered.append((applicationHeight, symbolHeight)) } #expect(rendered[1].application == rendered[0].application * 2) #expect(abs(rendered[1].symbol - rendered[0].symbol * 2) <= 1) }