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)) } }