Files
onyx/Packages/OnyxKit/Tests/OnyxHelperProtocolTests/ChargePolicyTests.swift
T
ScarriffleandClaude Opus 5 f289d02c37 Der Akku bekommt ein Gedächtnis
Verlauf über 24 Stunden, sieben Tage und dreißig Tage, aufgezeichnet alle fünf
Minuten. Als Säulen und nicht als Linie: eine Linie verbindet auch dort, wo
nichts gemessen wurde, und ein zugeklappter Rechner hatte keinen Ladestand —
eine Linie darüber behauptet einen.

Dazu Segelmodus und Hitzeschutz als reine Regeln im Helfer. Beide haben zwei
Schwellen, eine zum Anhalten und eine zum Weitermachen. Ohne diesen Abstand
hinge der Akku am Limit und würde bei jedem verlorenen Prozent nachgeladen —
hunderte winzige Ladevorgänge am Tag, und genau die altern ihn.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 21:06:06 +02:00

90 lines
3.7 KiB
Swift

import Testing
@testable import OnyxHelperProtocol
@Suite("Segelmodus und Hitzeschutz")
struct ChargePolicyTests {
// MARK: - Segeln
@Test("Unter dem Limit wird geladen")
func chargesBelowLimit() {
#expect(ChargePolicy.shouldCharge(charge: 0.5, limit: 80, celsius: nil,
wasCharging: true))
}
@Test("Am Limit hört es auf")
func stopsAtLimit() {
#expect(!ChargePolicy.shouldCharge(charge: 0.80, limit: 80, celsius: nil,
wasCharging: true))
}
@Test("Nach dem Anhalten wird nicht sofort wieder geladen")
func doesNotResumeImmediately() {
// Der Kern des Segelns: ohne Abstand hinge der Akku am Limit und würde
// bei jedem verlorenen Prozent nachgeladen — hunderte winzige
// Ladevorgänge am Tag, und genau die altern ihn.
#expect(!ChargePolicy.shouldCharge(charge: 0.79, limit: 80, celsius: nil,
wasCharging: false))
#expect(!ChargePolicy.shouldCharge(charge: 0.76, limit: 80, celsius: nil,
wasCharging: false))
}
@Test("Erst unter dem Abstand geht es wieder los")
func resumesBelowHysteresis() {
#expect(ChargePolicy.shouldCharge(charge: 0.75, limit: 80, celsius: nil,
wasCharging: false))
}
@Test("Ohne Limit gilt nur der Hitzeschutz")
func noLimitMeansAlwaysCharge() {
#expect(ChargePolicy.shouldCharge(charge: 0.99, limit: 100, celsius: nil,
wasCharging: false))
}
// MARK: - Hitze
@Test("Zu heiß heißt: nicht laden")
func heatStopsCharging() {
#expect(!ChargePolicy.shouldCharge(charge: 0.3, limit: 100, celsius: 41,
wasCharging: true))
}
@Test("Nach dem Abkühlen nicht gleich an der Schwelle wieder los")
func heatHasHysteresisToo() {
// Genau an der Schwelle schaltete es sonst im Sekundentakt an und aus.
#expect(!ChargePolicy.shouldCharge(charge: 0.3, limit: 100, celsius: 37,
wasCharging: false))
#expect(ChargePolicy.shouldCharge(charge: 0.3, limit: 100, celsius: 35,
wasCharging: false))
}
@Test("Ohne Temperaturmessung kein Hitzeschutz")
func unknownTemperatureIsNotAnExcuse() {
// Eine Temperatur zu erfinden wäre schlimmer als keine zu haben.
#expect(ChargePolicy.shouldCharge(charge: 0.3, limit: 100, celsius: nil,
wasCharging: true))
}
// MARK: - Der Grund, den die Anzeige nennt
@Test("Der Grund unterscheidet Limit, Segeln und Hitze")
func reasonsAreDistinct() {
#expect(ChargePolicy.reason(charge: 0.5, limit: 80, celsius: nil,
wasCharging: true) == .charging)
#expect(ChargePolicy.reason(charge: 0.80, limit: 80, celsius: nil,
wasCharging: true) == .atLimit(80))
#expect(ChargePolicy.reason(charge: 0.78, limit: 80, celsius: nil,
wasCharging: false) == .sailing(80))
#expect(ChargePolicy.reason(charge: 0.3, limit: 100, celsius: 42,
wasCharging: true) == .tooHot(42))
}
@Test("Hitze schlägt jeden anderen Grund")
func heatWinsOverLimit() {
// Wer bei 42 Grad „am Limit" liest, sucht den Fehler an der falschen
// Stelle.
#expect(ChargePolicy.reason(charge: 0.95, limit: 80, celsius: 42,
wasCharging: true) == .tooHot(42))
}
}