问题 - 索引中该目录记为小写 `scripts/`,工作区实为 `Scripts/`。因 core.ignorecase=true, 本地 `git diff -- Scripts/bin/x.py` 会**静默返回空**(看似无改动), 且在大小写敏感环境(Linux CI / Docker 挂载)会检出 `scripts/`, 与全仓所有 `Scripts/...` 引用不匹配。 - 该目录此前 10 个脚本(check_python_version.py、perf_snapshot.py、 install_collector_launchd.py、mysql_toggle.sh 等)从未入库, 而 CI 第 31 行正调用 `Scripts/bin/check_python_version.py --strict` —— 全新检出必然失败。 改动 - 索引路径统一为 `Scripts/`(工作区文件未移动,仅索引改名)。 - 补齐上述 10 个未跟踪脚本及其测试。 影响 - 修正前索引 35 条(全为小写路径),修正后 45 条。
90 lines
3.3 KiB
Python
90 lines
3.3 KiB
Python
# coding=utf-8
|
||
"""insights.py 数据洞察模块单元测试.
|
||
|
||
重点覆盖:
|
||
- parse_date:多分支日期解析(None / datetime / 8位数字 / 长字符串 / 短字符串)
|
||
该函数被 overview_db 和 query_latest_date 调用,是整个洞察模块的日期处理核心。
|
||
"""
|
||
|
||
import os
|
||
import sys
|
||
from datetime import datetime
|
||
from unittest.mock import MagicMock, patch
|
||
|
||
import pytest
|
||
|
||
# 将 Scripts/bin 加入 sys.path
|
||
_bin_dir = os.path.join(os.path.dirname(__file__), "..")
|
||
if _bin_dir not in sys.path:
|
||
sys.path.insert(0, _bin_dir)
|
||
|
||
# conftest 注入的 pymysql mock 缺少 cursors.DictCursor,补齐
|
||
_pymysql_mock = sys.modules.get("pymysql")
|
||
if _pymysql_mock is not None and not hasattr(_pymysql_mock, "cursors"):
|
||
_pymysql_mock.cursors = MagicMock(DictCursor=dict)
|
||
|
||
# insights.py 模块级执行 args = parser.parse_args(),
|
||
# 需将 sys.argv 设为最小值避免 argparse 解析 pytest 参数。
|
||
_old_argv = sys.argv
|
||
sys.argv = ["insights.py"]
|
||
try:
|
||
import insights
|
||
finally:
|
||
sys.argv = _old_argv
|
||
|
||
|
||
# ── parse_date ────────────────────────────────────────────
|
||
|
||
|
||
class TestParseDate:
|
||
"""parse_date 多分支日期解析测试."""
|
||
|
||
def test_none_returns_none(self):
|
||
"""None 输入 → 返回 None."""
|
||
assert insights.parse_date(None) is None
|
||
|
||
def test_empty_string_returns_none(self):
|
||
"""空字符串 → 返回 None(falsy 分支)."""
|
||
assert insights.parse_date("") is None
|
||
|
||
def test_datetime_object_formatted(self):
|
||
"""datetime 对象 → 格式化为 YYYY-MM-DD HH:MM:SS."""
|
||
dt = datetime(2024, 3, 15, 14, 30, 45)
|
||
assert insights.parse_date(dt) == "2024-03-15 14:30:45"
|
||
|
||
def test_eight_digit_string_to_date(self):
|
||
"""8 位纯数字字符串 → 格式化为 YYYY-MM-DD."""
|
||
assert insights.parse_date("20240315") == "2024-03-15"
|
||
|
||
def test_nineteen_char_string_truncated(self):
|
||
""">=19 字符 → 截取前 19 字符(YYYY-MM-DD HH:MM:SS 部分)."""
|
||
s = "2024-03-15 14:30:45.123456"
|
||
assert insights.parse_date(s) == "2024-03-15 14:30:45"
|
||
|
||
def test_ten_char_string_truncated(self):
|
||
"""10-18 字符 → 截取前 10 字符(YYYY-MM-DD 部分)."""
|
||
assert insights.parse_date("2024-03-15") == "2024-03-15"
|
||
|
||
def test_short_string_returned_as_is(self):
|
||
"""<10 字符 → 原样返回."""
|
||
assert insights.parse_date("short") == "short"
|
||
|
||
def test_whitespace_stripped_before_processing(self):
|
||
"""输入前后空白被 strip."""
|
||
assert insights.parse_date(" 20240315 ") == "2024-03-15"
|
||
|
||
def test_non_date_eight_digits_still_formatted(self):
|
||
"""8 位纯数字但不代表日期 → 仍按格式拼接(函数不做语义校验)."""
|
||
result = insights.parse_date("12345678")
|
||
assert result == "1234-56-78"
|
||
|
||
def test_int_input_converted_to_string(self):
|
||
"""整数输入 → str() 转换后走字符串分支."""
|
||
result = insights.parse_date(20240315)
|
||
assert result == "2024-03-15"
|
||
|
||
def test_fourteen_digit_int_truncated_to_10(self):
|
||
"""14 位整数 → 转 str 后按 >=10 且 <19 分支截取前 10 位."""
|
||
result = insights.parse_date(20240315143045)
|
||
assert result == "2024031514"
|