First commit
This commit is contained in:
+229
@@ -0,0 +1,229 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Tests fuer den Protokoll-Layer, gepruefte Referenz ist das Handbuch.
|
||||
|
||||
python3 -m unittest -v test_migra
|
||||
"""
|
||||
|
||||
import unittest
|
||||
|
||||
import coords
|
||||
import migra
|
||||
from display import Display
|
||||
from transport import FakeTransport
|
||||
|
||||
|
||||
class TestTelegramm(unittest.TestCase):
|
||||
|
||||
def test_handbuch_beispiel_mit_pruefsumme(self):
|
||||
"""Handbuch 3.10, Beispiel 2: Zeichen 'A' an Anzeige mit Adresse 1.
|
||||
|
||||
Master: 02 81 80 83 F0 F1 41 FA F6 03
|
||||
"""
|
||||
frame = migra.build_telegram(b"A", dest=1, src=0, checksum=True, response=True)
|
||||
self.assertEqual(frame, bytes.fromhex("02818083F0F141FAF603"))
|
||||
|
||||
def test_handbuch_beispiel_ohne_pruefsumme(self):
|
||||
"""Handbuch 3.10, Beispiel 1: ohne Pruefsumme, mit Antwort.
|
||||
|
||||
Ohne Pruefsumme duerfen LEN-H/L gerade *nicht* mitgesendet werden.
|
||||
"""
|
||||
frame = migra.build_telegram(b"Hallo Welt", dest=1, src=0,
|
||||
checksum=False, response=True)
|
||||
self.assertEqual(frame[:4], bytes([0x02, 0x81, 0x80, 0x81]))
|
||||
self.assertEqual(frame[4:-1], b"Hallo Welt")
|
||||
self.assertEqual(frame[-1], 0x03)
|
||||
|
||||
def test_frame_control_bits(self):
|
||||
def fc(checksum, response):
|
||||
return migra.build_telegram(b"x", checksum=checksum, response=response)[3]
|
||||
|
||||
self.assertEqual(fc(False, False), 0x80)
|
||||
self.assertEqual(fc(False, True), 0x81) # so faehrt das alte C-Programm
|
||||
self.assertEqual(fc(True, False), 0x82)
|
||||
self.assertEqual(fc(True, True), 0x83)
|
||||
|
||||
def test_data_unit_zu_lang(self):
|
||||
with self.assertRaises(migra.MigraError):
|
||||
migra.build_telegram(b"x" * 231)
|
||||
|
||||
|
||||
class TestDataUnit(unittest.TestCase):
|
||||
|
||||
def test_trennzeichen_nach_esc_sequenz(self):
|
||||
"""Handbuch 3.9: Data-Unit = 1B 'Z01' 1B 'C002003' 1B 'A301' 1F Text."""
|
||||
du = (migra.DataUnit()
|
||||
.charset(1, spaced=False)
|
||||
.cursor(2, 3)
|
||||
.attributes(fg=migra.YELLOW, bg=migra.BLACK, blink=migra.BLINKING)
|
||||
.text("Online-Text"))
|
||||
self.assertEqual(
|
||||
du.bytes(),
|
||||
b"\x1bZ01\x1bC002003\x1bA301\x1fOnline-Text",
|
||||
)
|
||||
|
||||
def test_kein_trennzeichen_zwischen_esc_sequenzen(self):
|
||||
du = migra.DataUnit().fill(migra.BLACK).charset(0)
|
||||
self.assertEqual(du.bytes(), b"\x1bF0\x1bz00")
|
||||
|
||||
def test_trennzeichen_nur_einmal_pro_textblock(self):
|
||||
du = migra.DataUnit().cursor(0, 0).text("AB").text("CD")
|
||||
self.assertEqual(du.bytes(), b"\x1bC000000\x1fABCD")
|
||||
|
||||
def test_cursor_ist_ascii_codiert(self):
|
||||
"""Handbuch 3.7: Position 123 wird als '1' '2' '3' uebertragen."""
|
||||
self.assertEqual(migra.DataUnit().cursor(123, 45).bytes(), b"\x1bC123045")
|
||||
|
||||
def test_loeschen_und_helligkeit(self):
|
||||
self.assertEqual(migra.DataUnit().fill(migra.BLACK).bytes(), b"\x1bF0")
|
||||
self.assertEqual(migra.DataUnit().brightness(100, migra.RED).bytes(), b"\x1bH2100")
|
||||
self.assertEqual(migra.DataUnit().brightness(80, migra.RED).bytes(), b"\x1bH2080")
|
||||
|
||||
def test_helligkeit_ausserhalb_bereich(self):
|
||||
with self.assertRaises(migra.MigraError):
|
||||
migra.DataUnit().brightness(101)
|
||||
|
||||
def test_text_encoding_latin1(self):
|
||||
self.assertEqual(migra.encode_text("+45°12'"), b"+45\xb012'")
|
||||
self.assertEqual(migra.encode_text("✓"), b"?") # nicht darstellbar
|
||||
|
||||
|
||||
class TestAntwort(unittest.TestCase):
|
||||
|
||||
def test_ok(self):
|
||||
frame = bytes([0x02, 0x80, 0x81, 0x80, ord("0"), 0x03])
|
||||
self.assertEqual(migra.parse_response(frame), "0")
|
||||
|
||||
def test_fehlercode_wirft(self):
|
||||
frame = bytes([0x02, 0x80, 0x81, 0x80, ord("3"), 0x03])
|
||||
with self.assertRaises(migra.MigraError) as ctx:
|
||||
migra.parse_response(frame)
|
||||
self.assertIn("ESC-Sequenz", str(ctx.exception))
|
||||
|
||||
def test_timeout_wirft(self):
|
||||
with self.assertRaises(migra.MigraError):
|
||||
migra.parse_response(b"")
|
||||
|
||||
|
||||
class TestKoordinaten(unittest.TestCase):
|
||||
|
||||
def test_ra_formate_werden_erkannt(self):
|
||||
for text in ("12h34m56s", "12:34:56", "12 34 56"):
|
||||
self.assertEqual(coords.parse_ra(text), (12, 34, 56))
|
||||
|
||||
def test_ra_dezimal(self):
|
||||
self.assertEqual(coords.parse_ra("12.5"), (12, 30, 0))
|
||||
|
||||
def test_dec_mit_vorzeichen(self):
|
||||
self.assertEqual(coords.parse_dec("+45d12m30s"), ("+", 45, 12, 30))
|
||||
self.assertEqual(coords.parse_dec("-07:15:00"), ("-", 7, 15, 0))
|
||||
|
||||
def test_dec_ohne_vorzeichen_ist_positiv(self):
|
||||
self.assertEqual(coords.parse_dec("45:12:30"), ("+", 45, 12, 30))
|
||||
|
||||
def test_bereichsgrenzen(self):
|
||||
with self.assertRaises(ValueError):
|
||||
coords.parse_ra("24:00:01")
|
||||
with self.assertRaises(ValueError):
|
||||
coords.parse_dec("+91:00:00")
|
||||
|
||||
def test_formatierung_passt_sich_der_breite_an(self):
|
||||
self.assertEqual(coords.format_ra("12h34m56s", width=9), "12h34m56s")
|
||||
self.assertEqual(coords.format_ra("12h34m56s", width=8), "12:34:56")
|
||||
self.assertEqual(coords.format_dec("+45d12m30s", width=10), "+45°12'30\"")
|
||||
self.assertEqual(coords.format_dec("+45d12m30s", width=9), "+45°12'30") # 9: Grad, ohne "
|
||||
self.assertEqual(coords.format_dec("+45d12m30s", width=7), "+45°12'") # 7: ohne Bogensekunden
|
||||
|
||||
|
||||
class TestDisplay(unittest.TestCase):
|
||||
|
||||
def test_zeilen_ergeben_ein_telegramm(self):
|
||||
t = FakeTransport(echo=False)
|
||||
Display(t, response=True).show_lines("12:34:56", "+45:12:30", clear=True)
|
||||
|
||||
self.assertEqual(len(t.frames), 1)
|
||||
frame = t.frames[0]
|
||||
self.assertEqual(frame[:4], bytes([0x02, 0x81, 0x80, 0x81]))
|
||||
self.assertEqual(frame[-1], 0x03)
|
||||
|
||||
data = frame[4:-1]
|
||||
self.assertIn(b"\x1bF0", data) # mit clear=True: vorher loeschen
|
||||
self.assertIn(b"\x1bC000000\x1f12:34:56", data) # Zeile 1 bei y=0
|
||||
self.assertIn(b"\x1bC000009\x1f+45:12:30", data) # Zeile 2 bei y=9
|
||||
|
||||
def test_ohne_clear_kein_fill_aber_aufgefuellt(self):
|
||||
"""Standard (clear=False): kein Vollbild-Loeschen, Zeilen auf volle Breite."""
|
||||
t = FakeTransport(echo=False)
|
||||
Display(t, response=True).show_lines("12:34:56", clear=False)
|
||||
data = t.frames[0][4:-1]
|
||||
self.assertNotIn(b"\x1bF0", data)
|
||||
# auf CHARS_PER_LINE mit Leerzeichen aufgefuellt
|
||||
import config
|
||||
padded = "12:34:56".ljust(config.CHARS_PER_LINE).encode()
|
||||
self.assertIn(padded, data)
|
||||
|
||||
def test_gradzeichen_via_zeichensatz(self):
|
||||
"""Gradzeichen wird durch kurzen Wechsel auf Zeichensatz 1 erzeugt."""
|
||||
t = FakeTransport(echo=False)
|
||||
Display(t, response=True).show_lines("12h34m56s", "+45°12'30\"")
|
||||
data = t.frames[0][4:-1]
|
||||
# Umschalten auf Zeichensatz 1, "/", zurueck auf Zeichensatz 0
|
||||
self.assertIn(b"\x1bz01\x1f/\x1bz00", data)
|
||||
|
||||
def test_oberste_zeile_wird_zuletzt_gezeichnet(self):
|
||||
"""Wegen der Home-Zellen-Stoerung muss y=0 nach y=9 im Telegramm stehen."""
|
||||
t = FakeTransport(echo=False)
|
||||
Display(t, response=True).show_lines("12h34m56s", "+45°12'30\"")
|
||||
data = t.frames[0][4:-1]
|
||||
self.assertLess(data.index(b"C000009"), data.index(b"C000000"))
|
||||
|
||||
def test_gradzeichen_fallback_ohne_zeichensatz(self):
|
||||
"""Ist DEGREE_CHARSET None, wird der Fallbacktext statt der Umschaltung genutzt."""
|
||||
import config
|
||||
t = FakeTransport(echo=False)
|
||||
alt = config.DEGREE_CHARSET
|
||||
try:
|
||||
config.DEGREE_CHARSET = None
|
||||
Display(t, response=True).show_lines("+45°12'30\"")
|
||||
finally:
|
||||
config.DEGREE_CHARSET = alt
|
||||
data = t.frames[0][4:-1]
|
||||
self.assertNotIn(b"\x1bz01", data)
|
||||
self.assertIn(config.DEGREE_FALLBACK.encode(), data)
|
||||
|
||||
def test_fehlercode_der_anzeige_wirft(self):
|
||||
t = FakeTransport(echo=False)
|
||||
t._response = bytes([0x02, 0x80, 0x81, 0x80, ord("4"), 0x03])
|
||||
with self.assertRaises(migra.MigraError):
|
||||
Display(t, response=True).clear()
|
||||
|
||||
def test_show_line_nur_eine_zeile(self):
|
||||
"""show_line schreibt nur die angegebene Zeile, ohne Vollbild-Loeschen."""
|
||||
t = FakeTransport(echo=False)
|
||||
Display(t, response=True).show_line(0, "18h36m56s")
|
||||
data = t.frames[0][4:-1]
|
||||
self.assertNotIn(b"\x1bF0", data) # kein Loeschen
|
||||
self.assertIn(b"\x1bC000000", data) # Cursor auf Zeile 1 (y=0)
|
||||
self.assertNotIn(b"C000009", data) # Zeile 2 unberuehrt
|
||||
|
||||
def test_show_line_ungueltiger_index(self):
|
||||
t = FakeTransport(echo=False)
|
||||
with self.assertRaises(ValueError):
|
||||
Display(t, response=True).show_line(5, "x")
|
||||
|
||||
def test_ohne_antwort_fc_bit0_ist_null(self):
|
||||
"""Standardbetrieb ohne Antwort: FC = 0x80, kein Fehlercode wird gelesen."""
|
||||
import config
|
||||
alt = config.QUIET_TIME
|
||||
try:
|
||||
config.QUIET_TIME = 0.0
|
||||
t = FakeTransport(echo=False)
|
||||
# selbst wenn die (ignorierte) Antwort einen Fehler meldet, darf nichts fliegen
|
||||
t._response = bytes([0x02, 0x80, 0x81, 0x80, ord("4"), 0x03])
|
||||
Display(t, response=False).clear()
|
||||
finally:
|
||||
config.QUIET_TIME = alt
|
||||
self.assertEqual(t.frames[0][3], 0x80) # FC ohne Antwort-Bit
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
Reference in New Issue
Block a user