Add testing mocks

This commit is contained in:
Thomas Farstrike
2026-03-17 21:19:33 +01:00
parent 8ac4016e33
commit 7ac6502e62
2 changed files with 354 additions and 0 deletions
+4
View File
@@ -1,6 +1,10 @@
0.9.0
=====
Builtin Apps:
- Hotspot Settings
- WebServer Settings
Frameworks:
- AudioManager: add support for multiple speakers and microphones
- AudioManager: add support for ADC-based microphone (adc_mic)
+350
View File
@@ -0,0 +1,350 @@
class MockSharedPreferences:
"""Mock SharedPreferences for testing."""
_all_data = {} # Class-level storage
def __init__(self, app_id, filename=None):
self.app_id = app_id
self.filename = filename
if app_id not in MockSharedPreferences._all_data:
MockSharedPreferences._all_data[app_id] = {}
def _get_value(self, key, default):
return MockSharedPreferences._all_data.get(self.app_id, {}).get(key, default)
def get_dict(self, key):
return self._get_value(key, {})
def get_list(self, key, default=None):
return self._get_value(key, default)
def get_bool(self, key, default=False):
value = self._get_value(key, default)
return bool(value)
def get_string(self, key, default=""):
value = self._get_value(key, default)
return value if value is not None else default
def get_int(self, key, default=0):
value = self._get_value(key, default)
try:
return int(value)
except (TypeError, ValueError):
return default
def edit(self):
return MockEditor(self)
@classmethod
def reset_all(cls):
cls._all_data = {}
class MockEditor:
"""Mock editor for SharedPreferences."""
def __init__(self, prefs):
self.prefs = prefs
self.pending = {}
def put_dict(self, key, value):
self.pending[key] = value
def put_list(self, key, value):
self.pending[key] = value
def put_bool(self, key, value):
self.pending[key] = bool(value)
def put_string(self, key, value):
self.pending[key] = value
def put_int(self, key, value):
self.pending[key] = int(value)
def commit(self):
if self.prefs.app_id not in MockSharedPreferences._all_data:
MockSharedPreferences._all_data[self.prefs.app_id] = {}
MockSharedPreferences._all_data[self.prefs.app_id].update(self.pending)
class MockMpos:
"""Mock mpos module with config and time."""
class config:
@staticmethod
def SharedPreferences(app_id):
return MockSharedPreferences(app_id)
class time:
@staticmethod
def sync_time():
pass # No-op for testing
class HotspotMockNetwork:
"""Mock network module with AP/STA support for hotspot tests."""
STA_IF = 0
AP_IF = 1
AUTH_OPEN = 0
AUTH_WPA_PSK = 1
AUTH_WPA2_PSK = 2
AUTH_WPA_WPA2_PSK = 3
class MockWLAN:
def __init__(self, interface):
self.interface = interface
self._active = False
self._connected = False
self._config = {}
self._scan_results = []
self._ifconfig = ("0.0.0.0", "0.0.0.0", "0.0.0.0", "0.0.0.0")
def active(self, is_active=None):
if is_active is None:
return self._active
self._active = is_active
return None
def isconnected(self):
return self._connected
def connect(self, ssid, password):
self._connected = True
self._config["essid"] = ssid
def disconnect(self):
self._connected = False
def config(self, *args, **kwargs):
if kwargs:
self._config.update(kwargs)
return None
if args:
return self._config.get(args[0])
return self._config
def ifconfig(self, cfg=None):
if cfg is None:
return self._ifconfig
self._ifconfig = cfg
return None
def ipconfig(self, key=None):
config = self.ifconfig()
mapping = {
"addr4": config[0],
"netmask4": config[1],
"gw4": config[2],
"dns4": config[3],
}
if key is None:
return mapping
return mapping.get(key)
def scan(self):
return self._scan_results
def __init__(self):
self._wlan_instances = {}
def WLAN(self, interface):
if interface not in self._wlan_instances:
self._wlan_instances[interface] = self.MockWLAN(interface)
return self._wlan_instances[interface]
class MockADC:
"""Mock ADC for testing."""
ATTN_11DB = 3
def __init__(self, pin):
self.pin = pin
self._atten = None
self._read_value = 2048
def atten(self, value):
self._atten = value
def read(self):
return self._read_value
def set_read_value(self, value):
"""Test helper to set ADC reading."""
self._read_value = value
class MockPin:
"""Mock Pin for testing."""
def __init__(self, pin_num):
self.pin_num = pin_num
class MockMachineADC:
"""Mock machine module with ADC/Pin."""
ADC = MockADC
Pin = MockPin
class MockWifiService:
"""Mock WifiService for testing."""
wifi_busy = False
_connected = False
_temporarily_disabled = False
@classmethod
def is_connected(cls):
return cls._connected
@classmethod
def disconnect(cls):
cls._connected = False
@classmethod
def temporarily_disable(cls):
"""Temporarily disable WiFi and return whether it was connected."""
if cls.wifi_busy:
raise RuntimeError("Cannot disable WiFi: WifiService is already busy")
was_connected = cls._connected
cls.wifi_busy = True
cls._connected = False
cls._temporarily_disabled = True
return was_connected
@classmethod
def temporarily_enable(cls, was_connected):
"""Re-enable WiFi and reconnect if it was connected before."""
cls.wifi_busy = False
cls._temporarily_disabled = False
if was_connected:
cls._connected = True
@classmethod
def reset(cls):
"""Test helper to reset state."""
cls.wifi_busy = False
cls._connected = False
cls._temporarily_disabled = False
class MockI2C:
"""Mock I2C bus for testing."""
def __init__(self, bus_id, sda=None, scl=None):
self.bus_id = bus_id
self.sda = sda
self.scl = scl
self.memory = {}
def readfrom_mem(self, addr, reg, nbytes):
"""Read from memory (simulates I2C read)."""
if addr not in self.memory:
raise OSError("I2C device not found")
if reg not in self.memory[addr]:
return bytes([0] * nbytes)
return bytes(self.memory[addr][reg])
def writeto_mem(self, addr, reg, data):
"""Write to memory (simulates I2C write)."""
if addr not in self.memory:
self.memory[addr] = {}
self.memory[addr][reg] = list(data)
class MockQMI8658:
"""Mock QMI8658 IMU sensor."""
def __init__(self, i2c_bus, address=0x6B, accel_scale=0b10, gyro_scale=0b100):
self.i2c = i2c_bus
self.address = address
self.accel_scale = accel_scale
self.gyro_scale = gyro_scale
@property
def temperature(self):
"""Return mock temperature."""
return 25.5
@property
def acceleration(self):
"""Return mock acceleration (in G)."""
return (0.0, 0.0, 1.0)
@property
def gyro(self):
"""Return mock gyroscope (in deg/s)."""
return (0.0, 0.0, 0.0)
class MockWsenIsds:
"""Mock WSEN_ISDS IMU sensor."""
def __init__(self, i2c, address=0x6B, acc_range="8g", acc_data_rate="104Hz",
gyro_range="500dps", gyro_data_rate="104Hz"):
self.i2c = i2c
self.address = address
self.acc_range = acc_range
self.gyro_range = gyro_range
self.acc_sensitivity = 0.244
self.gyro_sensitivity = 17.5
self.acc_offset_x = 0
self.acc_offset_y = 0
self.acc_offset_z = 0
self.gyro_offset_x = 0
self.gyro_offset_y = 0
self.gyro_offset_z = 0
def get_chip_id(self):
"""Return WHO_AM_I value."""
return 0x6A
def _read_raw_accelerations(self):
"""Return mock acceleration (in mg)."""
return (0.0, 0.0, 1000.0)
def read_angular_velocities(self):
"""Return mock gyroscope (in mdps)."""
return (0.0, 0.0, 0.0)
def acc_calibrate(self, samples=None):
"""Mock calibration."""
pass
def gyro_calibrate(self, samples=None):
"""Mock calibration."""
pass
def make_machine_i2c_module(i2c_cls, pin_cls=None):
if pin_cls is None:
pin_cls = type("Pin", (), {})
return type("module", (), {"I2C": i2c_cls, "Pin": pin_cls})()
def make_machine_timer_module(timer_cls):
return type("module", (), {"Timer": timer_cls})()
def make_usocket_module(socket_cls):
class MockUsocket:
"""Mock usocket module."""
AF_INET = socket_cls.AF_INET
SOCK_STREAM = socket_cls.SOCK_STREAM
@staticmethod
def socket(af, sock_type):
return socket_cls(af, sock_type)
return MockUsocket
def make_config_module(shared_prefs_cls):
return type("module", (), {"SharedPreferences": shared_prefs_cls})()