feat: AndrOBD-протокол — 1:1 копия стейт-машины + тест против мока
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Тест AndrOBD-протокола против Mock ELM327 v2.
|
||||
|
||||
Проверяет что ответы НЕ перемешаны:
|
||||
- 0902 → VIN (не "AUTO" от ATSP0)
|
||||
- 03 → DTC (не "OK" от ATE0)
|
||||
- 010C → RPM (не VIN-ответ)
|
||||
"""
|
||||
|
||||
import logging
|
||||
import socket
|
||||
import time
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, ".")
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format="%(name)s: %(message)s")
|
||||
|
||||
|
||||
class FakeSerial:
|
||||
"""TCP-заглушка для тестирования AndrOBD без pyserial."""
|
||||
def __init__(self, host, port):
|
||||
self.sock = socket.socket()
|
||||
self.sock.connect((host, port))
|
||||
self.sock.setblocking(False)
|
||||
self.sock.settimeout(0.1)
|
||||
self.is_open = True
|
||||
|
||||
@property
|
||||
def in_waiting(self):
|
||||
import select
|
||||
r, _, _ = select.select([self.sock], [], [], 0)
|
||||
return 4096 if r else 0
|
||||
|
||||
def read(self, n):
|
||||
try:
|
||||
return self.sock.recv(n)
|
||||
except Exception:
|
||||
return b""
|
||||
|
||||
def write(self, data):
|
||||
self.sock.sendall(data)
|
||||
|
||||
def flush(self):
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
self.sock.close()
|
||||
|
||||
|
||||
def test():
|
||||
"""Запускает AndrOBD против мока и проверяет ответы."""
|
||||
|
||||
from elmer.androbd import AndrOBD, AdaptiveTiming
|
||||
|
||||
# Создаём протокол и подменяем serial на TCP-заглушку
|
||||
elm = AndrOBD("mock")
|
||||
elm._ser = FakeSerial("127.0.0.1", 35000)
|
||||
|
||||
print("=== 1. ИНИТ ===")
|
||||
elm.init()
|
||||
|
||||
print("\n=== 2. VIN (0902) ===")
|
||||
# Дадим моку дообработать ответы после инита
|
||||
time.sleep(0.5)
|
||||
vin = elm.send("0902")
|
||||
print(f" VIN ответ: [{vin}]")
|
||||
assert "490201" in vin.replace(" ", ""), f"VIN ответ не содержит 490201: {vin}"
|
||||
|
||||
print("\n=== 3. DTC (03) ===")
|
||||
dtc = elm.send("03")
|
||||
print(f" DTC ответ: {dtc}")
|
||||
assert "43" in dtc.replace(" ", ""), f"DTC ответ не содержит 43: {dtc}"
|
||||
|
||||
print("\n=== 4. RPM (010C) ===")
|
||||
rpm = elm.send("010C")
|
||||
print(f" RPM ответ: {rpm}")
|
||||
assert "410C" in rpm.replace(" ", ""), f"RPM ответ не содержит 410C: {rpm}"
|
||||
|
||||
print("\n=== 5. ОЖ (0105) ===")
|
||||
ect = elm.send("0105")
|
||||
print(f" ОЖ ответ: {ect}")
|
||||
assert "4105" in ect.replace(" ", ""), f"ОЖ ответ не содержит 4105: {ect}"
|
||||
|
||||
print("\n=== 6. ПРОВЕРКА: ответы не перепутаны ===")
|
||||
# VIN не должен быть "OK" или "AUTO"
|
||||
assert "AUTO" not in vin, f"VIN ответ содержит AUTO (чужой ответ!): {vin}"
|
||||
assert "OK" not in vin, f"VIN ответ содержит OK (чужой ответ!): {vin}"
|
||||
# DTC не должен быть OK
|
||||
assert "OK" not in dtc, f"DTC ответ содержит OK (чужой ответ!): {dtc}"
|
||||
# RPM — чистый PID-ответ
|
||||
assert "OK" not in rpm, f"RPM ответ содержит OK (чужой ответ!): {rpm}"
|
||||
|
||||
elm._ser.close()
|
||||
print("\n✅ ВСЕ ТЕСТЫ ПРОЙДЕНЫ — ответы не перемешаны!")
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
test()
|
||||
except AssertionError as e:
|
||||
print(f"\n❌ ТЕСТ ПРОВАЛЕН: {e}")
|
||||
sys.exit(1)
|
||||
Reference in New Issue
Block a user