diff --git a/.github/workflows/test-setup.yml b/.github/workflows/test-setup.yml index 94581e4..a00668c 100644 --- a/.github/workflows/test-setup.yml +++ b/.github/workflows/test-setup.yml @@ -28,9 +28,9 @@ jobs: run: | sudo apt update && sudo apt install ${{matrix.apt-packages}} - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Grab the SDK - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: repository: 32blit/32blit-sdk path: 32blit-sdk diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4bae59c..0cd8ba8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,14 +4,14 @@ on: pull_request: push: branches: - - master + - main jobs: test: runs-on: ubuntu-latest strategy: matrix: - python: [3.7, 3.8] + python: ["3.7", "3.8", "3.9", "3.10", "3.11"] steps: # Linux deps @@ -19,9 +19,9 @@ jobs: if: runner.os == 'Linux' run: | sudo apt update && sudo apt install gcc-arm-none-eabi - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python }} - name: Install Dependencies diff --git a/Makefile b/Makefile index afa1c14..1f32359 100644 --- a/Makefile +++ b/Makefile @@ -64,7 +64,7 @@ python-dist: python-clean python-wheels python-sdist -python3 -m twine check src/dist/* python-testdeploy: python-dist - twine upload --repository-url https://test.pypi.org/legacy/ src/dist/* + twine upload --repository testpypi src/dist/* python-deploy: check python-dist twine upload src/dist/* diff --git a/README.md b/README.md index 43e1ef5..50b6964 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # 32blit Tools -[![Build Status](https://shields.io/github/workflow/status/32blit/32blit-tools/Python%20Tests.svg)](https://github.com/32blit/32blit-tools/actions/workflows/test.yml) -[![Coverage Status](https://coveralls.io/repos/github/32blit/32blit-tools/badge.svg?branch=master)](https://coveralls.io/github/32blit/32blit-tools?branch=master) +[![Build Status](https://img.shields.io/github/actions/workflow/status/32blit/32blit-tools/test.yml?branch=main)](https://github.com/32blit/32blit-tools/actions/workflows/test.yml) +[![Coverage Status](https://coveralls.io/repos/github/32blit/32blit-tools/badge.svg?branch=main)](https://coveralls.io/github/32blit/32blit-tools?branch=main) [![PyPi Package](https://img.shields.io/pypi/v/32blit.svg)](https://pypi.python.org/pypi/32blit) [![Python Versions](https://img.shields.io/pypi/pyversions/32blit.svg)](https://pypi.python.org/pypi/32blit) diff --git a/src/CHANGELOG.txt b/src/CHANGELOG.txt index a959a3f..85cd6c6 100644 --- a/src/CHANGELOG.txt +++ b/src/CHANGELOG.txt @@ -1,3 +1,10 @@ +0.7.4 +----- + +* Fix bug when deleting from flash - thanks @ali1234 +* Fix serial port in error message - thanks @ali1234 +* Fix image encoding - thanks @Daft-Freak + 0.7.3 ----- diff --git a/src/README.md b/src/README.md index 279ed51..bc1532a 100644 --- a/src/README.md +++ b/src/README.md @@ -1,7 +1,7 @@ # 32blit Tools -[![Build Status](https://shields.io/github/workflow/status/32blit/32blit-tools/Python%20Tests.svg)](https://github.com/32blit/32blit-tools/actions/workflows/test.yml) -[![Coverage Status](https://coveralls.io/repos/github/32blit/32blit-tools/badge.svg?branch=master)](https://coveralls.io/github/32blit/32blit-tools?branch=master) +[![Build Status](https://img.shields.io/github/actions/workflow/status/32blit/32blit-tools/test.yml?branch=main)](https://github.com/32blit/32blit-tools/actions/workflows/test.yml) +[![Coverage Status](https://coveralls.io/repos/github/32blit/32blit-tools/badge.svg?branch=main)](https://coveralls.io/github/32blit/32blit-tools?branch=main) [![PyPi Package](https://img.shields.io/pypi/v/32blit.svg)](https://pypi.python.org/pypi/32blit) [![Python Versions](https://img.shields.io/pypi/pyversions/32blit.svg)](https://pypi.python.org/pypi/32blit) @@ -118,6 +118,13 @@ Supported formats: # Changelog +0.7.4 +----- + +* Fix bug when deleting from flash - thanks @ali1234 +* Fix serial port in error message - thanks @ali1234 +* Fix image encoding - thanks @Daft-Freak + 0.7.3 ----- diff --git a/src/setup.cfg b/src/setup.cfg index d58ec57..aff3d79 100644 --- a/src/setup.cfg +++ b/src/setup.cfg @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- [metadata] name = 32blit -version = 0.7.3 +version = 0.7.4 author = Philip Howard author_email = phil@pimoroni.com description = 32Blit asset preparation and upload tools diff --git a/src/tests/resources/no_image.raw b/src/tests/resources/no_image.raw new file mode 100644 index 0000000..b4a7514 Binary files /dev/null and b/src/tests/resources/no_image.raw differ diff --git a/src/tests/test_blitserial.py b/src/tests/test_blitserial.py new file mode 100644 index 0000000..e3fc752 --- /dev/null +++ b/src/tests/test_blitserial.py @@ -0,0 +1,185 @@ +import io +import pathlib + +import mock +import pytest +from ttblit.core.blitserial import BlitSerial, BlitSerialException + + +def test_comport(): + """Test serial port discovery.""" + def comports(): + class Comport: + def __init__(self, vid, pid, device): + self.vid = vid + self.pid = pid + self.device = device + + for c in ((0, 0, "notblit"), (0, 0, "notblit"), (0x0483, 0x5740, "_fakeserial_"), (None, None, "_noidserial_")): + yield Comport(*c) + + with mock.patch("serial.tools.list_ports.comports", return_value=comports()): + BlitSerial.validate_comport("auto") + + with mock.patch("serial.tools.list_ports.comports", return_value=comports()): + BlitSerial.validate_comport("all") + + with mock.patch("serial.tools.list_ports.comports", return_value=comports()): + BlitSerial.validate_comport("_fakeserial_") + + with mock.patch("serial.tools.list_ports.comports", return_value=comports()): + BlitSerial.validate_comport("_noidserial_") + + with pytest.raises(RuntimeError): + # Without the mock, no blit should be connected. + BlitSerial.validate_comport("auto") + + with pytest.raises(RuntimeError): + # Without the mock, no blit should be connected. + BlitSerial.validate_comport("_fakeserial_") + + +class BlitSerialTester(BlitSerial): + """Mock wrapper around BlitSerial that uses BytesIO to simulate the hardware port.""" + def __init__(self, output): + self.__reader = io.BytesIO(output) + self.__writer = io.BytesIO() + + def read(self, n): + return self.__reader.read(n) + + def write(self, b): + return self.__writer.write(b) + + def sent_bytes(self): + return bytes(self.__writer.getbuffer()) + + def open(self): + raise BlitSerialException() + + @property + def in_waiting(self): + return 0 + + def flush(self): + pass + + def reset_output_buffer(self): + pass + + def close(self): + pass + + @property + def port(self): + return "_fakeserial_" + + +def test_status(): + b = BlitSerialTester(b"32BL_EXT") + + assert b.status == 'game' + assert b.sent_bytes() == b'32BLINFO\x00' + + +def test_reset(): + b = BlitSerialTester(b"") + with pytest.raises(RuntimeError): + b.reset() + assert b.sent_bytes() == b"32BL_RST\x00" + + +def test_send_file(test_resources): + f = pathlib.Path(test_resources / "doom-fire.blit") + f_data = f.read_bytes() + + b = BlitSerialTester(b'32BL__OK\x00\x00') + b.send_file(f, "flash", auto_launch=True) + assert b.sent_bytes() == b'32BLPROGdoom-fire.blit\x0026322\x00' + f_data + b'32BLLNCHflash:/0\x00' + + b = BlitSerialTester(b'32BL__OK\x00\x00') + b.send_file(f, "flash", auto_launch=False) + assert b.sent_bytes() == b'32BLPROGdoom-fire.blit\x0026322\x00' + f_data + + b = BlitSerialTester(b'32BL__OK\x00\x00') + b.send_file(f, "sd", auto_launch=True) + assert b.sent_bytes() == b'32BLSAVE//doom-fire.blit\x0026322\x00' + f_data + b'32BLLNCH//doom-fire.blit\x00' + + b = BlitSerialTester(b'32BL__OK\x00\x00') + b.send_file(f, "sd", auto_launch=False) + assert b.sent_bytes() == b'32BLSAVE//doom-fire.blit\x0026322\x00' + f_data + + with pytest.raises(TypeError): + b = BlitSerialTester(b'32BL__OK\x00\x00') + b.send_file(f, "no_such_drive") + + +def test_erase(): + b = BlitSerialTester(b"") + b.erase(0x12345678) + assert b.sent_bytes() == b'32BLERSE\x78\x56\x34\x12\x00' + + +def test_list(): + import struct + from ttblit.core.struct import struct_blit_meta_standalone + from ttblit.core.palette import Palette + + palette = Palette() + palette.get_entry(255, 255, 255, 255) + + # TODO: This should be a fixture or something + metadata = { + 'checksum': 0x12345678, + 'date': "date", + 'title': "title", + 'description': "description", + 'version': "version", + 'author': "author", + 'category': "category", + 'filetypes': "", + 'url': "", + 'icon': { + 'data': { + 'width': 8, + 'height': 8, + 'palette': palette.tostruct(), + 'pixels': b'\x00' * 8 * 8, + }, + }, + 'splash': { + 'data': { + 'width': 128, + 'height': 96, + 'palette': palette.tostruct(), + 'pixels': b'\x00' * 128 * 96, + }, + }, + } + + test_meta = struct_blit_meta_standalone.build({'data': metadata}) + + fake_offs = 0x50000 + fake_size = 0x15000 + + test_data = b''.join([ + struct.pack("