"""Tests for the standard OBD services + trip/performance (no hardware).""" import os import sys sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from obdcore import obdservices as svc from obdcore.trip import TripComputer, PerformanceMeter, KMH_PER_MPH def test_decode_vin(): vin = "1FMZU73E12ZA12345" data = [0x49, 0x02, 0x01] + [ord(c) for c in vin] assert svc.decode_vin(data) == vin assert svc.decode_vin([0x41, 0x00]) is None # not a mode-09 response print(" VIN decode: OK") def test_decode_readiness(): # A=MIL off/0 DTCs, B=3 continuous supported+ready, C=Cat/O2/O2htr supported, # D=O2 sensor incomplete r = svc.decode_readiness([0x00, 0x07, 0x61, 0x20]) assert r["mil"] is False and r["dtc_count"] == 0 and r["ignition"] == "spark" by = {m["name"]: m["ready"] for m in r["monitors"]} assert by["Misfire"] and by["Fuel System"] and by["Components"] assert by["Catalyst"] is True and by["O2 Sensor"] is False assert r["total"] == 6 and r["ready_count"] == 5 # diesel flag rc = svc.decode_readiness([0x80, 0x0F, 0x00, 0x00]) assert rc["mil"] is True and rc["ignition"] == "compression" print(f" readiness decode: {r['ready_count']}/{r['total']} ready, O2 not ready: OK") def test_trip_computer(): tc = TripComputer() t = 0.0 for _ in range(360): # 6 min at 1 Hz, 96.56 km/h (60 mph), 12 g/s tc.update(t, 96.56, 12.0) t += 1.0 s = tc.stats() assert 5.5 < s["distance_mi"] < 6.5, s # 60mph * 0.1h = 6 mi assert s["avg_mpg"] > 5 and s["avg_mpg"] < 60, s inst = tc.instant_mpg(96.56, 12.0) assert inst > 0 print(f" trip: {s['distance_mi']}mi, {s['avg_mpg']} avg mpg, " f"{inst:.1f} inst: OK") def test_performance_meter(): pm = PerformanceMeter() t = 0.0 # parked for _ in range(3): pm.update(t, 0.0); t += 0.5 # accelerate 0 -> 70 mph over 7s (mph), then cruise to cover 1/4 mile for i in range(1, 200): t = 1.5 + i * 0.1 mph = min(70.0, (t - 1.5) * 10.0) # 10 mph/s pm.update(t, mph * KMH_PER_MPH) assert pm.best_0_60 is not None, "should have timed 0-60" assert 5.0 < pm.best_0_60 < 8.0, pm.best_0_60 # ~6s at 10mph/s assert pm.best_quarter is not None, "should have timed 1/4 mile" print(f" performance: 0-60 {pm.best_0_60}s, 1/4mi {pm.best_quarter}s: OK") if __name__ == "__main__": for fn in [test_decode_vin, test_decode_readiness, test_trip_computer, test_performance_meter]: fn() print("\nALL SERVICE TESTS PASS")