Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ jobs:
run: uv run mypy src

- name: 运行测试
run: uv run pytest tests -v --cov=src/uart_mcp --cov-report=term-missing
run: uv run pytest tests -v --cov=src/uart_mcp --cov-report=term-missing --ignore=tests/test_integration_real_port.py
4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@ build-backend = "hatchling.build"
packages = ["src/uart_mcp"]

[tool.ruff]
line-length = 88
line-length = 120
target-version = "py313"

[tool.ruff.lint]
select = ["E", "F", "I", "N", "W"]
ignore = ["E501"] # 忽略行长度检查,使用 line-length 控制

[tool.mypy]
python_version = "3.13"
Expand All @@ -43,6 +44,7 @@ strict = true
[tool.pytest.ini_options]
pythonpath = ["src"]
testpaths = ["tests"]
addopts = "--ignore=tests/test_integration_real_port.py"

[dependency-groups]
dev = [
Expand Down
6 changes: 1 addition & 5 deletions src/uart_mcp/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,11 @@
import platform
import re
import threading
import tomllib
from dataclasses import dataclass
from pathlib import Path
from typing import Any

try:
import tomllib
except ImportError:
import tomli as tomllib # Python < 3.11 兼容

logger = logging.getLogger(__name__)

# 支持的波特率和数据位(从 types.py 导入常量以保持一致性)
Expand Down
48 changes: 24 additions & 24 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@

class MockSerialLoopback:
"""模拟串口回环的 Serial 类

写入的数据会自动进入读取缓冲区,模拟TX/RX短接的回环效果
"""

def __init__(self, port=None, baudrate=9600, bytesize=8, parity='N',
stopbits=1, timeout=None, write_timeout=None,
stopbits=1, timeout=None, write_timeout=None,
xonxoff=False, rtscts=False, **kwargs):
self.port = port
self.baudrate = baudrate
Expand All @@ -24,26 +24,26 @@ def __init__(self, port=None, baudrate=9600, bytesize=8, parity='N',
self.write_timeout = write_timeout
self.xonxoff = xonxoff
self.rtscts = rtscts

self._is_open = True
self._buffer = bytearray() # 回环缓冲区
self._lock = threading.Lock()

@property
def is_open(self):
return self._is_open

@property
def in_waiting(self):
with self._lock:
return len(self._buffer)

def open(self):
self._is_open = True

def close(self):
self._is_open = False

def write(self, data):
"""写入数据,同时放入读取缓冲区(回环)"""
if not self._is_open:
Expand All @@ -53,7 +53,7 @@ def write(self, data):
with self._lock:
self._buffer.extend(data)
return len(data)

def read(self, size=1):
"""从缓冲区读取数据"""
if not self._is_open:
Expand All @@ -62,27 +62,27 @@ def read(self, size=1):
data = bytes(self._buffer[:size])
self._buffer = self._buffer[size:]
return data

def read_all(self):
"""读取所有可用数据"""
with self._lock:
data = bytes(self._buffer)
self._buffer.clear()
return data

def reset_input_buffer(self):
"""清空输入缓冲区"""
with self._lock:
self._buffer.clear()

def reset_output_buffer(self):
"""清空输出缓冲区(模拟)"""
pass

def flush(self):
"""刷新输出"""
pass

def apply_settings(self, settings):
"""应用配置设置(热更新)"""
if "baudrate" in settings:
Expand Down Expand Up @@ -121,17 +121,17 @@ def mock_serial():
@pytest.fixture
def mock_serial_loopback():
"""模拟串口回环 - 写入数据自动进入读取缓冲区

用于集成测试,模拟真实硬件的回环效果
"""
mock_instances = {}

def create_mock_serial(*args, **kwargs):
port = kwargs.get('port') or (args[0] if args else '/dev/mock')
if port not in mock_instances:
mock_instances[port] = MockSerialLoopback(*args, **kwargs)
return mock_instances[port]

with patch("serial.Serial", side_effect=create_mock_serial):
yield mock_instances

Expand All @@ -148,7 +148,7 @@ def mock_list_ports_with_devices():
"""模拟返回设备列表的 list_ports"""
mock_ports = [
MockPortInfo("/dev/ttyMOCK0", "模拟USB串口", "USB VID:PID=1234:5678"),
MockPortInfo("/dev/ttyMOCK1", "模拟蓝牙串口", "BLUETOOTH ADDR=00:11:22:33:44:55"),
MockPortInfo("/dev/ttyMOCK1", "模拟蓝牙串口", "BT ADDR=00:11:22:33:44:55"),
]
with patch("serial.tools.list_ports.comports", return_value=mock_ports):
yield mock_ports
Expand All @@ -167,16 +167,16 @@ def reset_managers():
"""重置全局管理器状态,用于隔离测试"""
# 保存原状态
from uart_mcp import serial_manager, terminal_manager

old_serial = serial_manager._serial_manager
old_terminal = terminal_manager._terminal_manager

# 重置为 None
serial_manager._serial_manager = None
terminal_manager._terminal_manager = None

yield

# 清理新创建的管理器
try:
if serial_manager._serial_manager is not None:
Expand All @@ -188,7 +188,7 @@ def reset_managers():
terminal_manager._terminal_manager.shutdown()
except Exception:
pass

# 恢复原状态
serial_manager._serial_manager = old_serial
terminal_manager._terminal_manager = old_terminal
9 changes: 4 additions & 5 deletions tests/test_config_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,21 @@
"""

import os
import stat
import tempfile
from pathlib import Path
from unittest.mock import patch

import pytest

from uart_mcp.config import (
ConfigManager,
BlacklistManager,
ConfigManager,
UartConfig,
get_config_dir,
get_config_path,
get_blacklist_manager,
get_blacklist_path,
get_config_dir,
get_config_manager,
get_blacklist_manager,
get_config_path,
)


Expand Down
Loading