Skip to content

Commit

Permalink
Ht1621 tests using state machine mocking (#72)
Browse files Browse the repository at this point in the history
* HT1621 device mocking tests
* Tweaked DocStrings for QA
  • Loading branch information
Gadgetoid authored and rm-hull committed Sep 7, 2018
1 parent 0e2ff07 commit af948e8
Showing 1 changed file with 149 additions and 172 deletions.
321 changes: 149 additions & 172 deletions tests/test_ht1621.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,205 +10,182 @@
from luma.lcd.device import ht1621
from luma.core.virtual import sevensegment

from helpers import call, Mock # noqa: F401

gpio = Mock(unsafe=True)
class MockHT1621:
"""
Mock the HT1621 internal state machine.
Decodes the 3-pin serial data back into
the expected data packets.
"""

HIGH = 1
LOW = 0
OUT = 1
IN = 0

def __init__(self, WR=11, DAT=10, CS=8):
self._pin_wr = WR
self._pin_dat = DAT
self._pin_cs = CS
self.reset_mock()

def command(self, data):
"""
Build a command representation.
"""
return ('cmd', data)

def data(self, data):
"""
Built a data representation.
"""
return ('data', data)

def setup(self, pin, state):
"""
Mock GPIO.setup.
"""
self._pin_states[pin] = state

def output(self, pin, state):
"""
Mock GPIO.output.
"""
if pin == self._pin_wr:
if self._state_wr == 0 and state == 1: # Rising edge
self._data <<= 1
self._data |= self._state_dat
self._bit_count += 1
self._state_wr = state

if pin == self._pin_dat and self._state_wr == 0:
self._state_dat = state

# Handle 4-bit command SOF
if self._bit_count == 4 and self._state == 'none' and self._data == 0b1000:
self._state = 'cmd'
self._data = 0
self._bit_count = 0

# Handle 3-bit data SOF
if self._bit_count == 3 and self._state == 'none' and self._data == 0b101:
self._state = 'addr'
self._data = 0
self._bit_count = 0

# Discard 6-bit address (it's always 0)
if self._bit_count == 6 and self._state == 'addr':
self._state = 'data'
self._data = 0
self._bit_count = 0

# If we hit 8 bits, treat it as one packet
if self._bit_count == 8:
self._values.append((self._state, self._data))
self._data = 0
self._bit_count = 0

# Reset state machine on CS rising edge
if pin == self._pin_cs:
if self._state_cs == 0 and state == 1: # Rising edge
self._data = 0
self._bit_count = 0
self._state = 'none'

def reset_mock(self):
"""
Reset state machine.
"""
self._state_wr = 0 # Read/Write State
self._state_dat = 0 # Data state
self._state_cs = 0 # Chip-select state
self._data = 0 # Current value
self._bit_count = 0 # Count of bits in _data
self._values = [] # All clocked-in values
self._pin_states = {} # Pin IO states
self._state = 'none' # Current state

def cleanup(self):
"""
Mock GPIO.cleanup.
"""
self.reset_mock()

def get_data(self):
"""
Return stored values.
"""
return self._values

def get_pin_states(self):
"""
Return stored pin output states.
"""
return self._pin_states


gpio = MockHT1621()


def setup_function(function):
"""
Called before a test runs.
"""
gpio.reset_mock()
gpio.command.side_effect = None
gpio.OUT = 23
gpio.HIGH = 7
gpio.LOW = 4


def test_init_6x8():
ht1621(gpio, WR=99, DAT=88, CS=77)
gpio.setup.assert_has_calls([
call(99, 23),
call(88, 23),
call(77, 23)
])

gpio.output.assert_has_calls([
call(77, 4), call(99, 4), call(88, 7), call(99, 7), call(99, 4),
call(88, 4), call(99, 7), call(99, 4), call(88, 4), call(99, 7),
call(99, 4), call(88, 4), call(99, 7), call(99, 4), call(88, 4),
call(99, 7), call(99, 4), call(88, 4), call(99, 7), call(99, 4),
call(88, 7), call(99, 7), call(99, 4), call(88, 7), call(99, 7),
call(99, 4), call(88, 4), call(99, 7), call(99, 4), call(88, 4),
call(99, 7), call(99, 4), call(88, 4), call(99, 7), call(99, 4),
call(88, 4), call(99, 7), call(77, 7), call(77, 4), call(99, 4),
call(88, 7), call(99, 7), call(99, 4), call(88, 4), call(99, 7),
call(99, 4), call(88, 4), call(99, 7), call(99, 4), call(88, 4),
call(99, 7), call(99, 4), call(88, 4), call(99, 7), call(99, 4),
call(88, 7), call(99, 7), call(99, 4), call(88, 4), call(99, 7),
call(99, 4), call(88, 7), call(99, 7), call(99, 4), call(88, 4),
call(99, 7), call(99, 4), call(88, 4), call(99, 7), call(99, 4),
call(88, 7), call(99, 7), call(99, 4), call(88, 4), call(99, 7),
call(77, 7), call(77, 4), call(99, 4), call(88, 7), call(99, 7),
call(99, 4), call(88, 4), call(99, 7), call(99, 4), call(88, 4),
call(99, 7), call(99, 4), call(88, 4), call(99, 7), call(99, 4),
call(88, 4), call(99, 7), call(99, 4), call(88, 4), call(99, 7),
call(99, 4), call(88, 4), call(99, 7), call(99, 4), call(88, 4),
call(99, 7), call(99, 4), call(88, 4), call(99, 7), call(99, 4),
call(88, 4), call(99, 7), call(99, 4), call(88, 7), call(99, 7),
call(99, 4), call(88, 4), call(99, 7), call(77, 7), call(77, 4),
call(99, 4), call(88, 7), call(99, 7), call(99, 4), call(88, 4),
call(99, 7), call(99, 4), call(88, 7), call(99, 7), call(99, 4),
call(88, 4), call(99, 7), call(99, 4), call(88, 4), call(99, 7),
call(99, 4), call(88, 4), call(99, 7), call(99, 4), call(88, 4),
call(99, 7), call(99, 4), call(88, 4), call(99, 7), call(99, 4),
call(88, 4), call(99, 7), call(99, 4), call(88, 4), call(99, 7),
call(99, 4), call(88, 4), call(99, 7), call(99, 4), call(88, 4),
call(99, 7), call(99, 4), call(88, 4), call(99, 7), call(99, 4),
call(88, 4), call(99, 7), call(99, 4), call(88, 4), call(99, 7),
call(99, 4), call(88, 4), call(99, 7), call(99, 4), call(88, 4),
call(99, 7), call(99, 4), call(88, 4), call(99, 7), call(99, 4),
call(88, 4), call(99, 7), call(99, 4), call(88, 4), call(99, 7),
call(99, 4), call(88, 4), call(99, 7), call(99, 4), call(88, 4),
call(99, 7), call(99, 4), call(88, 4), call(99, 7), call(99, 4),
call(88, 4), call(99, 7), call(99, 4), call(88, 4), call(99, 7),
call(99, 4), call(88, 4), call(99, 7), call(99, 4), call(88, 4),
call(99, 7), call(99, 4), call(88, 4), call(99, 7), call(99, 4),
call(88, 4), call(99, 7), call(99, 4), call(88, 4), call(99, 7),
call(99, 4), call(88, 4), call(99, 7), call(99, 4), call(88, 4),
call(99, 7), call(99, 4), call(88, 4), call(99, 7), call(99, 4),
call(88, 4), call(99, 7), call(99, 4), call(88, 4), call(99, 7),
call(99, 4), call(88, 4), call(99, 7), call(99, 4), call(88, 4),
call(99, 7), call(99, 4), call(88, 4), call(99, 7), call(99, 4),
call(88, 4), call(99, 7), call(99, 4), call(88, 4), call(99, 7),
call(99, 4), call(88, 4), call(99, 7), call(99, 4), call(88, 4),
call(99, 7), call(99, 4), call(88, 4), call(99, 7), call(99, 4),
call(88, 4), call(99, 7), call(99, 4), call(88, 4), call(99, 7),
call(99, 4), call(88, 4), call(99, 7), call(99, 4), call(88, 4),
call(99, 7), call(99, 4), call(88, 4), call(99, 7), call(99, 4),
call(88, 4), call(99, 7), call(99, 4), call(88, 4), call(99, 7),
call(99, 4), call(88, 4), call(99, 7), call(99, 4), call(88, 4),
call(99, 7), call(99, 4), call(88, 4), call(99, 7), call(99, 4),
call(88, 4), call(99, 7), call(99, 4), call(88, 4), call(99, 7),
call(99, 4), call(88, 4), call(99, 7), call(99, 4), call(88, 4),
call(99, 7), call(77, 7), call(77, 4), call(99, 4), call(88, 7),
call(99, 7), call(99, 4), call(88, 4), call(99, 7), call(99, 4),
call(88, 4), call(99, 7), call(99, 4), call(88, 4), call(99, 7),
call(99, 4), call(88, 4), call(99, 7), call(99, 4), call(88, 4),
call(99, 7), call(99, 4), call(88, 4), call(99, 7), call(99, 4),
call(88, 4), call(99, 7), call(99, 4), call(88, 4), call(99, 7),
call(99, 4), call(88, 7), call(99, 7), call(99, 4), call(88, 7),
call(99, 7), call(99, 4), call(88, 4), call(99, 7), call(77, 7)
])
ht1621(gpio)

assert gpio.get_pin_states() == {
11: gpio.OUT,
10: gpio.OUT,
8: gpio.OUT}

assert gpio.get_data() == [
gpio.command(0x30), # Internal RC oscillator @ 256KHz
gpio.command(0x52), # 1/2 Bias and 4 commons
gpio.command(0x02), # System enable
gpio.data(0), # Column Data
gpio.data(0), # "
gpio.data(0), #
gpio.data(0), #
gpio.data(0), #
gpio.data(0), #
gpio.command(0x06)] # Display On


def test_cleanup():
device = ht1621(gpio)
gpio.reset_mock()
device.cleanup()
assert gpio.get_data() == [] # No activity unless persist is True


def test_hide():
device = ht1621(gpio)
gpio.reset_mock()
device.hide()
gpio.output.assert_has_calls([
call(8, 4), call(11, 4), call(10, 7), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 4), call(11, 7), call(11, 4), call(10, 4),
call(11, 7), call(11, 4), call(10, 4), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 4), call(11, 7), call(11, 4), call(10, 7),
call(11, 7), call(11, 4), call(10, 4), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(8, 7)
])
assert gpio.get_data() == [gpio.command(0x04)] # Display Off


def test_show():
device = ht1621(gpio)
gpio.reset_mock()
device.show()
gpio.output.assert_has_calls([
call(8, 4), call(11, 4), call(10, 7), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 4), call(11, 7), call(11, 4), call(10, 4),
call(11, 7), call(11, 4), call(10, 4), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 4), call(11, 7), call(11, 4), call(10, 7),
call(11, 7), call(11, 4), call(10, 7), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(8, 7)
])
assert gpio.get_data() == [gpio.command(0x06)] # Display On


def test_display():
device = ht1621(gpio)
gpio.reset_mock()

sevensegment(device).text = "HELLO"
gpio.output.assert_has_calls([
call(8, 4), call(11, 4), call(10, 7), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(11, 4), call(10, 7), call(11, 7),
call(11, 4), call(10, 4), call(11, 7), call(11, 4), call(10, 4),
call(11, 7), call(11, 4), call(10, 4), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 4), call(11, 7), call(11, 4), call(10, 4),
call(11, 7), call(11, 4), call(10, 4), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 4), call(11, 7), call(11, 4), call(10, 4),
call(11, 7), call(11, 4), call(10, 4), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 4), call(11, 7), call(11, 4), call(10, 4),
call(11, 7), call(11, 4), call(10, 4), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 4), call(11, 7), call(11, 4), call(10, 4),
call(11, 7), call(11, 4), call(10, 4), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 4), call(11, 7), call(11, 4), call(10, 4),
call(11, 7), call(11, 4), call(10, 4), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 4), call(11, 7), call(11, 4), call(10, 4),
call(11, 7), call(11, 4), call(10, 4), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 4), call(11, 7), call(11, 4), call(10, 4),
call(11, 7), call(11, 4), call(10, 4), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 4), call(11, 7), call(11, 4), call(10, 4),
call(11, 7), call(11, 4), call(10, 4), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 4), call(11, 7), call(11, 4), call(10, 4),
call(11, 7), call(11, 4), call(10, 4), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 4), call(11, 7), call(11, 4), call(10, 4),
call(11, 7), call(11, 4), call(10, 4), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(8, 7), call(8, 4), call(11, 4),
call(10, 7), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 7), call(11, 7), call(11, 4), call(10, 4),
call(11, 7), call(11, 4), call(10, 4), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 4), call(11, 7), call(11, 4), call(10, 4),
call(11, 7), call(11, 4), call(10, 4), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 4), call(11, 7), call(11, 4), call(10, 4),
call(11, 7), call(11, 4), call(10, 4), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 4), call(11, 7), call(11, 4), call(10, 7),
call(11, 7), call(11, 4), call(10, 7), call(11, 7), call(11, 4),
call(10, 7), call(11, 7), call(11, 4), call(10, 7), call(11, 7),
call(11, 4), call(10, 7), call(11, 7), call(11, 4), call(10, 4),
call(11, 7), call(11, 4), call(10, 7), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 4), call(11, 7), call(11, 4), call(10, 4),
call(11, 7), call(11, 4), call(10, 7), call(11, 7), call(11, 4),
call(10, 7), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 7), call(11, 7), call(11, 4), call(10, 4),
call(11, 7), call(11, 4), call(10, 4), call(11, 7), call(11, 4),
call(10, 4), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 7), call(11, 7), call(11, 4), call(10, 7),
call(11, 7), call(11, 4), call(10, 4), call(11, 7), call(11, 4),
call(10, 7), call(11, 7), call(11, 4), call(10, 4), call(11, 7),
call(11, 4), call(10, 4), call(11, 7), call(11, 4), call(10, 4),
call(11, 7), call(11, 4), call(10, 7), call(11, 7), call(11, 4),
call(10, 7), call(11, 7), call(11, 4), call(10, 7), call(11, 7),
call(11, 4), call(10, 7), call(11, 7), call(11, 4), call(10, 7),
call(11, 7), call(11, 4), call(10, 4), call(11, 7), call(11, 4),
call(10, 7), call(11, 7), call(11, 4), call(10, 7), call(11, 7),
call(11, 4), call(10, 4), call(11, 7), call(11, 4), call(10, 4),
call(11, 7), call(11, 4), call(10, 7), call(11, 7), call(11, 4),
call(10, 7), call(11, 7), call(11, 4), call(10, 7), call(11, 7),
call(8, 7)
])

assert gpio.get_data() == [
gpio.data(0), gpio.data(0), gpio.data(0), # _ _ _
gpio.data(0), gpio.data(0), gpio.data(0), # _ _ _
gpio.data(0), gpio.data(125), gpio.data(13), # _ O L
gpio.data(13), gpio.data(31), gpio.data(103) # L E H
]

0 comments on commit af948e8

Please sign in to comment.