def test_program(success): # prepare calls = [] fpga = TinyFPGAB(None, lambda *a: calls.append(('progress', a))) # patching methods fpga.erase = lambda *a: calls.append(('erase', a)) fpga.write = lambda *a: calls.append(('write', a)) if success: fpga.read = lambda *a: calls.append(('read', a)) or DATA else: fpga.read = lambda *a: calls.append(('read', a)) or 'This is a fail' # run output = fpga.program(0x123456, DATA) # check assert output == success expected_calls = [ ('progress', ('Erasing designated flash pages', )), ('erase', (0x123456, 35)), ('progress', ('Writing bitstream', )), ('write', (0x123456, DATA)), ('progress', ('Verifying bitstream', )), ('read', (0x123456, 35)), ] if success: expected_calls.extend([ ('progress', ('Success!',)), ]) else: expected_calls.extend([ ('progress', ('Need to rewrite some pages...',)), ('progress', ('len: 000023 00000e',)), ('progress', ('rewriting page 123456',)), ('erase', (1193046, 35)), ('write', (1193046, b'Thequickbrownfoxjumpsoverthelazydog')), ('read', (1193046, 35)), ('erase', (1193046, 35)), ('write', (1193046, b'Thequickbrownfoxjumpsoverthelazydog')), ('read', (1193046, 35)), ('erase', (1193046, 35)), ('write', (1193046, b'Thequickbrownfoxjumpsoverthelazydog')), ('read', (1193046, 35)), ('erase', (1193046, 35)), ('write', (1193046, b'Thequickbrownfoxjumpsoverthelazydog')), ('read', (1193046, 35)), ('erase', (1193046, 35)), ('write', (1193046, b'Thequickbrownfoxjumpsoverthelazydog')), ('read', (1193046, 35)), ('erase', (1193046, 35)), ('write', (1193046, b'Thequickbrownfoxjumpsoverthelazydog')), ('read', (1193046, 35)), ('progress', ('Verification Failed!',)), ]) assert calls == expected_calls
def test_program(success): # prepare calls = [] fpga = TinyFPGAB(None, lambda *a: calls.append(('progress', a))) # patching methods fpga.erase = lambda *a: calls.append(('erase', a)) fpga.write = lambda *a: calls.append(('write', a)) if success: fpga.read = lambda *a: calls.append(('read', a)) or DATA else: fpga.read = lambda *a: calls.append(('read', a)) or 'This is a fail' # run output = fpga.program(0x123456, DATA) # check assert output == success expected_calls = [ ('progress', ('Erasing designated flash pages', )), ('erase', (0x123456, 35)), ('progress', ('Writing bitstream', )), ('write', (0x123456, DATA)), ('progress', ('Verifying bitstream', )), ('read', (0x123456, 35)), ] if success: expected_calls.extend([ ('progress', ('Success!', )), ]) else: expected_calls.extend([ ('progress', ('Need to rewrite some pages...', )), ('progress', ('len: 000023 00000e', )), ('progress', ('rewriting page 123456', )), ('erase', (1193046, 35)), ('write', (1193046, 'Thequickbrownfoxjumpsoverthelazydog')), ('read', (1193046, 35)), ('erase', (1193046, 35)), ('write', (1193046, 'Thequickbrownfoxjumpsoverthelazydog')), ('read', (1193046, 35)), ('erase', (1193046, 35)), ('write', (1193046, 'Thequickbrownfoxjumpsoverthelazydog')), ('read', (1193046, 35)), ('erase', (1193046, 35)), ('write', (1193046, 'Thequickbrownfoxjumpsoverthelazydog')), ('read', (1193046, 35)), ('erase', (1193046, 35)), ('write', (1193046, 'Thequickbrownfoxjumpsoverthelazydog')), ('read', (1193046, 35)), ('erase', (1193046, 35)), ('write', (1193046, 'Thequickbrownfoxjumpsoverthelazydog')), ('read', (1193046, 35)), ('progress', ('Verification Failed!', )), ]) assert calls == expected_calls
def test_program_bitstream(success): # prepare calls = [] fpga = TinyFPGAB(None, lambda *a: calls.append(('progress', a))) # patching methods fpga.wake = lambda *a: calls.append(('wake', a)) fpga.read_sts = lambda *a: calls.append(('read_sts', a)) fpga.read = lambda *a: calls.append(('read', a)) if success: fpga.program = lambda *a: calls.append(('program', a)) or True else: fpga.program = lambda *a: calls.append(('program', a)) or False fpga.boot = lambda *a: calls.append(('boot', a)) # run output = fpga.program_bitstream(0x123456, DATA) # check assert output == success expected_calls = [ ('progress', ('Waking up SPI flash', )), ('progress', ('35 bytes to program', )), ('program', (0x123456, DATA)), ] if success: expected_calls.append(('boot', ())) assert calls == expected_calls
def test_read(length, serial_outs): # prepare serial = FakeSerial(DATA[:length]) fpga = TinyFPGAB(serial) # run output = fpga.read(0x123456, length) # check assert output == DATA[:length] assert not serial.read_data serial.assert_written([d.decode('hex') for d in serial_outs])
def test_read(length, serial_outs): # prepare serial = FakeSerial(DATA[:length]) fpga = TinyFPGAB(serial) # run output = fpga.read(0x123456, length) # check assert output == DATA[:length] assert not serial.read_data serial.assert_written([bytearray.fromhex(d) for d in serial_outs])
def test_program(success): # prepare calls = [] fpga = TinyFPGAB(None, lambda *a: calls.append(('progress', a))) # patching methods fpga.erase = lambda *a: calls.append(('erase', a)) fpga.write = lambda *a: calls.append(('write', a)) if success: fpga.read = lambda *a: calls.append(('read', a)) or DATA else: fpga.read = lambda *a: calls.append(('read', a)) or 'This is a fail' # run output = fpga.program(0x123456, DATA) # check assert output == success assert calls == [ ('progress', ('Erasing designated flash pages', )), ('erase', (0x123456, 35)), ('progress', ('Writing bitstream', )), ('write', (0x123456, DATA)), ('progress', ('Verifying bitstream', )), ('read', (0x123456, 35)), ('progress', ('Success!' if success else 'Verification Failed!', )), ]
def test_is_bootloader_active(success_after): # prepare calls = [] fpga = TinyFPGAB(None) read_id = ['ABC'] * success_after + ['\x1f\x84\x01'] # patching methods fpga.wake = lambda *a: calls.append(('wake', a)) fpga.read = lambda *a: calls.append(('read', a)) fpga.read_id = lambda *a: calls.append(('read_id', a)) or read_id.pop(0) # run output = fpga.is_bootloader_active() # check assert output == (success_after < 6) expected_calls = [ ('wake', ()), ('read', (0, 16)), ('wake', ()), ('read_id', ()), ] * min(success_after + 1, 6) assert calls == expected_calls
def test_is_bootloader_active(success_after): # prepare calls = [] fpga = TinyFPGAB(None) read_id = ['ABC'] * success_after + [b'\x1f\x84\x01'] # patching methods fpga.wake = lambda *a: calls.append(('wake', a)) fpga.read = lambda *a: calls.append(('read', a)) fpga.read_id = lambda *a: calls.append(('read_id', a)) or read_id.pop(0) # run output = fpga.is_bootloader_active() # check assert output == (success_after < 6) expected_calls = [ ('wake', ()), ('read', (0, 16)), ('wake', ()), ('read_id', ()), ] * min(success_after + 1, 6) assert calls == expected_calls
def test_erase(offset, length, block_len, serial_outs): # prepare calls = [] serial = FakeSerial() fpga = TinyFPGAB(serial) fpga.write_enable = lambda: None # patch write_enable fpga.wait_while_busy = lambda: None # patch wait_while_busy fpga.read = lambda *a: calls.append(('read', a)) \ or DATA_4096[a[0] % 4096:][:a[1]] fpga.write = lambda *a: calls.append(('write', a)) # run assert fpga.erase(offset, length) is None # check assert not serial.read_data serial.assert_written([d.decode('hex') for d in serial_outs]) expected_calls = [] restore_first_block = None if offset % block_len > 0: # restore start of first block restore_offset = offset & ~(block_len - 1) restore_len = offset % block_len expected_calls.append(('read', (restore_offset, restore_len))) expected_calls.append( ('write', (restore_offset, DATA_4096[:restore_len]))) restore_first_block = restore_offset if (offset + length) % block_len > 0: # restore end of last block restore_offset = offset + length restore_len = block_len - (restore_offset % block_len) read_call = ('read', (restore_offset, restore_len)) if restore_first_block == ((offset + length) & ~(block_len - 1)): # restore before and after erase in same block expected_calls.insert(1, read_call) # 2nd read before 1st write else: expected_calls.append(read_call) # 2nd read after 1st write expected_calls.append( ('write', (restore_offset, DATA_4096[restore_offset % block_len:]))) assert calls == expected_calls
def test_erase(offset, length, block_len, serial_outs): # prepare calls = [] serial = FakeSerial() fpga = TinyFPGAB(serial) fpga.write_enable = lambda: None # patch write_enable fpga.wait_while_busy = lambda: None # patch wait_while_busy fpga.read = lambda *a: calls.append(('read', a)) \ or DATA_4096[a[0] % 4096:][:a[1]] fpga.write = lambda *a: calls.append(('write', a)) # run assert fpga.erase(offset, length) is None # check assert not serial.read_data serial.assert_written([bytearray.fromhex(d) for d in serial_outs]) expected_calls = [] restore_first_block = None if offset % block_len > 0: # restore start of first block restore_offset = offset & ~(block_len - 1) restore_len = offset % block_len expected_calls.append(( 'read', (restore_offset, restore_len))) expected_calls.append(( 'write', (restore_offset, DATA_4096[:restore_len]))) restore_first_block = restore_offset if (offset + length) % block_len > 0: # restore end of last block restore_offset = offset + length restore_len = block_len - (restore_offset % block_len) read_call = ('read', (restore_offset, restore_len)) if restore_first_block == ((offset + length) & ~(block_len - 1)): # restore before and after erase in same block expected_calls.insert(1, read_call) # 2nd read before 1st write else: expected_calls.append(read_call) # 2nd read after 1st write expected_calls.append(( 'write', (restore_offset, DATA_4096[restore_offset % block_len:]))) assert calls == expected_calls