import Testing import CoreGraphics import AppKit @testable import MetricsProvider // SF Symbols kennt fünf Füllstufen und keine Blitz-Varianten außer bei 100 %. // Beides passt nicht zu dem, was macOS selbst zeigt: eine stufenlose Füllung // und einen Blitz **im** Akku. Also selbst gezeichnet. @Suite("Akkuglyph") struct BatteryGlyphTests { private let inner: CGFloat = 20 @Test("Die Füllung folgt dem Ladestand stufenlos") func fillIsProportional() { // Der eigentliche Gewinn gegenüber fünf festen Stufen: 60 % sieht aus // wie 60 % und nicht wie 50 %. #expect(BatteryGlyph.fillWidth(charge: 0.5, inner: inner) == 10) #expect(BatteryGlyph.fillWidth(charge: 1.0, inner: inner) == 20) } @Test("Ein leerer Akku bleibt leer") func emptyStaysEmpty() { #expect(BatteryGlyph.fillWidth(charge: 0, inner: inner) == 0) } @Test("Ein fast leerer Akku ist trotzdem zu sehen") func nearlyEmptyIsStillVisible() { // Zwei Prozent ergäben 0,4 Punkte — unsichtbar, und damit // ununterscheidbar von „leer". Ein Rest bleibt stehen. let width = BatteryGlyph.fillWidth(charge: 0.02, inner: inner) #expect(width >= BatteryGlyph.minimumFill) } @Test("Über hundert Prozent läuft nichts über") func neverOverflows() { #expect(BatteryGlyph.fillWidth(charge: 2, inner: inner) == inner) #expect(BatteryGlyph.fillWidth(charge: -1, inner: inner) == 0) } @Test("Wenig Ladung gilt als kritisch") func lowIsFlagged() { // Dieselbe Schwelle wie in macOS: ab zwanzig Prozent abwärts wird die // Farbe zum Signal. #expect(BatteryGlyph.isLow(charge: 0.19)) #expect(!BatteryGlyph.isLow(charge: 0.21)) } @Test("Beim Laden gilt nichts als kritisch") func chargingIsNeverLow() { // Ein roter Akku, der gerade lädt, wäre eine Warnung vor etwas, das // sich schon erledigt. #expect(!BatteryGlyph.isLow(charge: 0.05, isCharging: true)) } @Test("Das Glyph hat die Maße der Menüleiste") func sizeFitsMenuBar() { // Breiter als hoch, wie ein Akku aussieht — und niedrig genug, dass es // in die 22 Punkte der Leiste passt. #expect(BatteryGlyph.size.width > BatteryGlyph.size.height) #expect(BatteryGlyph.size.height <= 14) } } // Am Netz, aber es tut sich nichts — weil das Ladelimit erreicht ist. Ohne // eigenes Zeichen sieht das genauso aus wie Akkubetrieb, und man fragt sich, // ob das Kabel wirklich steckt. @Suite("Ladezustand im Glyph") struct BatteryIndicatorTests { @Test("Beim Laden der Blitz") func chargingShowsBolt() { #expect(BatteryGlyph.indicator(isCharging: true, isPluggedIn: true) == .bolt) } @Test("Am Netz ohne Laden der Stecker") func pluggedButIdleShowsPlug() { // Der Fall, um den es geht: Ladelimit erreicht. #expect(BatteryGlyph.indicator(isCharging: false, isPluggedIn: true) == .plug) } @Test("Im Akkubetrieb gar nichts") func onBatteryShowsNothing() { #expect(BatteryGlyph.indicator(isCharging: false, isPluggedIn: false) == .none) } @Test("Laden schlägt alles andere") func chargingWins() { // Sollte der Netzzustand einmal widersprüchlich gemeldet werden, ist // „lädt" die Auskunft, die zählt. #expect(BatteryGlyph.indicator(isCharging: true, isPluggedIn: false) == .bolt) } @Test("Jedes Zeichen gibt es auch wirklich") func everyIndicatorResolves() { for indicator in BatteryGlyph.Indicator.allCases { guard let name = indicator.symbolName else { continue } #expect(NSImage(systemSymbolName: name, accessibilityDescription: nil) != nil, "\(name) gibt es nicht") } } }