Skip to content

Commit 52a6726

Browse files
committed
Add CI testing
1 parent 1247367 commit 52a6726

4 files changed

Lines changed: 164 additions & 0 deletions

File tree

.github/workflows/test.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Test
2+
3+
on: ["pull_request", "push"]
4+
5+
jobs:
6+
Test:
7+
runs-on: ubuntu-latest
8+
strategy:
9+
matrix:
10+
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
11+
steps:
12+
- uses: actions/checkout@v4
13+
14+
- name: Set up Python ${{ matrix.python-version }}
15+
uses: actions/setup-python@v5
16+
with:
17+
python-version: ${{ matrix.python-version }}
18+
19+
- name: Install dependencies
20+
run: |
21+
python -m pip install --upgrade pip
22+
pip install pytest
23+
pip install -e .
24+
25+
- name: Run tests
26+
run: pytest -v

.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Byte-compiled / optimized files
2+
__pycache__/
3+
*.py[cod]
4+
5+
# Test / tooling caches
6+
.pytest_cache/
7+
8+
# Packaging artifacts
9+
build/
10+
dist/
11+
*.egg-info/

conftest.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"""Shared pytest fixtures.
2+
3+
The tests run without hardware by substituting a fake ``smbus`` module for the
4+
real one. The fake is injected into ``sys.modules`` here, before ``tmp119`` is
5+
imported anywhere, so the library's top-level ``import smbus`` resolves to this
6+
in-memory stand-in instead of a physical I2C bus.
7+
"""
8+
9+
import sys
10+
import types
11+
12+
import pytest
13+
14+
15+
class FakeSMBus:
16+
"""In-memory stand-in for ``smbus.SMBus`` used for hardware-free testing.
17+
18+
Registers are stored big-endian as ``[msb, lsb]``, matching how the TMP119
19+
transfers its 16-bit registers over I2C. Tests can read/modify ``regs`` to
20+
simulate device state.
21+
"""
22+
23+
def __init__(self, bus):
24+
self.bus = bus
25+
self.regs = {
26+
0x00: [0x00, 0x00], # TEMP
27+
0x01: [0x02, 0x20], # CONFIG (power-on default 0x0220)
28+
0x0F: [0x21, 0x17], # DEVICE_ID (0x2117)
29+
}
30+
31+
def read_i2c_block_data(self, address, register, length):
32+
return list(self.regs[register])[:length]
33+
34+
def write_i2c_block_data(self, address, register, data):
35+
self.regs[register] = list(data)
36+
37+
38+
_fake_smbus = types.ModuleType("smbus")
39+
_fake_smbus.SMBus = FakeSMBus
40+
sys.modules["smbus"] = _fake_smbus
41+
42+
43+
@pytest.fixture
44+
def sensor():
45+
"""A TMP119 backed by a fresh in-memory FakeSMBus."""
46+
import tmp119
47+
return tmp119.TMP119()

tests/test_tmp119.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import pytest
2+
3+
import tmp119
4+
5+
# Config register bit masks (mirrors the private constants in the driver)
6+
AVG_MASK = 0x0060
7+
CONV_MASK = 0x0380
8+
9+
10+
def test_device_id(sensor):
11+
assert sensor.get_device_id() == 0x2117
12+
13+
14+
def test_init_success_clears_avg_and_conv(sensor):
15+
assert sensor.init() is True
16+
assert sensor.get_config() & (AVG_MASK | CONV_MASK) == 0
17+
18+
19+
def test_init_preserves_unrelated_config_bits(sensor):
20+
# Set a bit outside the AVG/CONV masks; init() must leave it untouched.
21+
sensor._bus.regs[0x01] = [0x82, 0x20] # 0x8220
22+
assert sensor.init() is True
23+
assert sensor.get_config() == 0x8000
24+
25+
26+
def test_init_fails_on_wrong_device_id(sensor):
27+
sensor._bus.regs[0x0F] = [0x00, 0x00]
28+
assert sensor.init() is False
29+
30+
31+
def test_init_returns_false_without_bus(sensor):
32+
sensor._bus = None
33+
assert sensor.init() is False
34+
35+
36+
def test_read_returns_false_without_bus(sensor):
37+
sensor._bus = None
38+
assert sensor.read() is False
39+
40+
41+
def test_read_positive_temperature(sensor):
42+
sensor._bus.regs[0x00] = [0x0C, 0x80] # 3200 * 0.0078125 = 25.0 C
43+
assert sensor.read() is True
44+
assert sensor.temperature() == pytest.approx(25.0)
45+
46+
47+
def test_read_negative_temperature(sensor):
48+
sensor._bus.regs[0x00] = [0xFF, 0x00] # -256 * 0.0078125 = -2.0 C
49+
sensor.read()
50+
assert sensor.temperature() == pytest.approx(-2.0)
51+
52+
53+
def test_temperature_unit_conversions(sensor):
54+
sensor._bus.regs[0x00] = [0x0C, 0x80] # 25.0 C
55+
sensor.read()
56+
assert sensor.temperature(tmp119.UNITS_Centigrade) == pytest.approx(25.0)
57+
assert sensor.temperature(tmp119.UNITS_Fahrenheit) == pytest.approx(77.0)
58+
assert sensor.temperature(tmp119.UNITS_Kelvin) == pytest.approx(298.15)
59+
60+
61+
def test_set_averaging(sensor):
62+
assert sensor.set_averaging(tmp119.TMP119_AVERAGE_64X) is True
63+
assert sensor.get_config() & AVG_MASK == (3 << 5)
64+
65+
66+
def test_set_read_delay(sensor):
67+
assert sensor.set_read_delay(tmp119.TMP119_DELAY_16000_MS) is True
68+
assert sensor.get_config() & CONV_MASK == (7 << 7)
69+
70+
71+
def test_set_averaging_preserves_read_delay(sensor):
72+
sensor.set_read_delay(tmp119.TMP119_DELAY_8000_MS)
73+
sensor.set_averaging(tmp119.TMP119_AVERAGE_32X)
74+
assert sensor.get_config() & CONV_MASK == (6 << 7)
75+
assert sensor.get_config() & AVG_MASK == (2 << 5)
76+
77+
78+
def test_set_config_round_trips_16_bits(sensor):
79+
sensor.set_config(0xABCD)
80+
assert sensor.get_config() == 0xABCD

0 commit comments

Comments
 (0)