- parser: FSM 解析器与仓颉版逐语义对齐,修 S01/S02/S04/Q05 - robot/hardvars: 六类硬件变量工厂,修 r.cj:911 重名 FIXME、Q07 倒序释放 - plugin: Python 插件替代 Lua 桥接,修 S07 三级路径查找 - hd: i2c(每fd锁 Q03/S06)/spi/servo/kalman/mpu6050(S05/Q06)/speaker(S03 实声) - modules: PCA9685 与 Lua 版逐字节对齐;ADS1115 重写(experimental);ADS1256 空桩 - tests: 42 项 pytest 全绿(Mock 总线 journal 断言) - CLI: --dry-run / --test roundtrip / --verbose;运行时零第三方依赖
50 lines
1.7 KiB
Python
50 lines
1.7 KiB
Python
"""插件加载器测试:三级路径查找(S07) / 缺失报错 / 实例隔离"""
|
|
|
|
import pytest
|
|
|
|
from pybot import plugin
|
|
|
|
|
|
def test_find_builtin_module():
|
|
"""包内置 modules/ 能找到 PCA9685"""
|
|
path = plugin.find_module("PCA9685")
|
|
assert path.name == "PCA9685.py"
|
|
assert path.parent.name == "modules"
|
|
|
|
|
|
def test_plugin_not_found():
|
|
with pytest.raises(plugin.PluginNotFound) as ei:
|
|
plugin.find_module("NoSuchDevice")
|
|
assert "NoSuchDevice" in str(ei.value)
|
|
assert "modules" in str(ei.value) # 报错含搜索路径
|
|
|
|
|
|
def test_env_path_priority(tmp_path, monkeypatch):
|
|
"""$PYBOT_MODULES_PATH 优先于包内置目录"""
|
|
(tmp_path / "PCA9685.py").write_text(
|
|
"def build(ctx): return {'from': 'env'}\n"
|
|
"def call(ctx): return {}\n"
|
|
"def destroy(ctx): return {}\n", encoding="utf-8")
|
|
monkeypatch.setenv("PYBOT_MODULES_PATH", str(tmp_path))
|
|
assert plugin.find_module("PCA9685") == tmp_path / "PCA9685.py"
|
|
mod = plugin.load_module("PCA9685")
|
|
assert mod.build({}) == {"from": "env"}
|
|
|
|
|
|
def test_missing_protocol_function(tmp_path, monkeypatch):
|
|
"""插件缺 build/call/destroy 任一函数即拒绝加载"""
|
|
(tmp_path / "Broken.py").write_text(
|
|
"def build(ctx): return {}\n", encoding="utf-8")
|
|
monkeypatch.setenv("PYBOT_MODULES_PATH", str(tmp_path))
|
|
with pytest.raises(plugin.PluginNotFound):
|
|
plugin.load_module("Broken")
|
|
|
|
|
|
def test_independent_instances():
|
|
"""每次加载新模块实例:模块级全局状态互不共享(对齐 Lua 每设备状态机)"""
|
|
a = plugin.load_module("SPI")
|
|
b = plugin.load_module("SPI")
|
|
assert a is not b
|
|
a._fd = 42
|
|
assert b._fd == -1
|