Files
ewoooc/tests/test_ppt_vision_service.py
OoO f11b0cc732 test(p19): 補 Phase 14/15/16/17 unit test — 27 tests 全綠
Operation Ollama-First v5.0 / Phase 19 — 補完戰役紀律

tests/test_caller_registry.py (7 tests)
- registry 含 30+ 核心 caller (ADR-028 對齊)
- is_known_caller / assert_known_caller strict=False/True 行為
- ai_call_logger 整合:未知 caller log warning 不阻擋
- frozenset 不可變動

tests/test_deepseek_service.py (6 tests)
- is_available() 需 KEY + flag 雙條件
- generate flag OFF / 200 success / 500 / timeout
- usage tokens 解析(prompt_tokens / completion_tokens)

tests/test_ppt_vision_service.py (6 tests)
- flag OFF 不打 HTTP / 檔不存在
-  無視覺異常 / ⚠️ marker 解析
- HTTP 500 觸發 mark_unhealthy / timeout fail-safe

tests/test_low_quality_response_v2.py (8 tests)
- 規則 5 純英文回應 (中文 < 30%)
- 規則 6 thinking-mode 漏洞 <think>...</think>
- 規則 7 重複迴圈 (前 50 字 ≥ 3 次)
- 規則 8 佔位符 ({{var}} / [TODO] / <待填>)
- 合法繁中商業文字應通過 8 條規則

regression: 全戰役 unit test 累計 241 tests
- Phase 1: 52 (logger + report)
- Phase 2: 14 (ollama_resolve)
- Phase 3: 36 (qa/golden/nemotron/daily)
- Phase 7: 23 (anthropic + code_review)
- Phase 11: 70 (rag + learning + promotion)
- Phase 10.5: 8 (mcp_router)
- Phase 13: 10 (retry chain)
- Phase 19: 27 (caller_registry + deepseek + ppt_vision + lq_v2)  新

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 10:27:35 +08:00

136 lines
4.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
tests/test_ppt_vision_service.py
─────────────────────────────────────────────────────────────────
Operation Ollama-First v5.0 / Phase 14 — PPT vision (minicpm-v) 驗證
"""
import os
import tempfile
from unittest.mock import patch, MagicMock
import pytest
@pytest.fixture(autouse=True)
def _reset_env(monkeypatch):
monkeypatch.delenv('PPT_VISION_ENABLED', raising=False)
yield
@pytest.fixture
def fake_image():
"""產生 1KB 假 png 檔給 test 用"""
f = tempfile.NamedTemporaryFile(suffix='.png', delete=False)
f.write(b'\x89PNG\r\n\x1a\n' + b'\x00' * 1000) # PNG magic + 1KB padding
f.close()
yield f.name
try:
os.unlink(f.name)
except Exception:
pass
def test_flag_off_returns_disabled_error(fake_image):
"""flag OFF 時 check_image 直接回 success=False不打 HTTP"""
from services.ppt_vision_service import PPTVisionService
svc = PPTVisionService()
with patch('services.ppt_vision_service.requests.post') as mock_post:
result = svc.check_image(fake_image)
assert result.success is False
assert 'PPT_VISION_ENABLED=false' in (result.error or '')
mock_post.assert_not_called()
def test_missing_image_file(monkeypatch):
monkeypatch.setenv('PPT_VISION_ENABLED', 'true')
from services.ppt_vision_service import PPTVisionService
svc = PPTVisionService()
result = svc.check_image('/tmp/this_file_does_not_exist_xyz.png')
assert result.success is False
assert 'image not found' in (result.error or '')
def test_no_issues_response(fake_image, monkeypatch):
"""minicpm-v 回「✅ 無視覺異常」→ issues_found 應為空 list"""
monkeypatch.setenv('PPT_VISION_ENABLED', 'true')
from services.ppt_vision_service import PPTVisionService
fake_resp = MagicMock(status_code=200)
fake_resp.json.return_value = {'response': '✅ 無視覺異常'}
with patch('services.ollama_service.resolve_ollama_host',
return_value='http://test:11434'), \
patch('services.ppt_vision_service.requests.post', return_value=fake_resp):
svc = PPTVisionService()
result = svc.check_image(fake_image)
assert result.success is True
assert result.issues_found == []
assert result.confidence == 1.0
def test_issues_detected(fake_image, monkeypatch):
"""minicpm-v 回多個 ⚠️ marker → issues_found 應含解析的問題"""
monkeypatch.setenv('PPT_VISION_ENABLED', 'true')
from services.ppt_vision_service import PPTVisionService
fake_resp = MagicMock(status_code=200)
fake_resp.json.return_value = {
'response': '⚠️ 圖表被切掉:右側長條圖超出邊界\n'
'⚠️ 文字溢出:商品標題被遮擋\n'
'其他無問題'
}
with patch('services.ollama_service.resolve_ollama_host',
return_value='http://test:11434'), \
patch('services.ppt_vision_service.requests.post', return_value=fake_resp):
svc = PPTVisionService()
result = svc.check_image(fake_image)
assert result.success is True
assert len(result.issues_found) == 2
assert any('圖表被切掉' in i for i in result.issues_found)
assert any('文字溢出' in i for i in result.issues_found)
assert result.confidence > 0.5
def test_http_500_marks_unhealthy(fake_image, monkeypatch):
"""HTTP 500 → success=False + mark_unhealthy 被呼叫"""
monkeypatch.setenv('PPT_VISION_ENABLED', 'true')
from services.ppt_vision_service import PPTVisionService
fake_resp = MagicMock(status_code=500)
fake_resp.text = 'oops'
with patch('services.ollama_service.resolve_ollama_host',
return_value='http://test:11434'), \
patch('services.ollama_service.mark_unhealthy') as mock_mark, \
patch('services.ppt_vision_service.requests.post', return_value=fake_resp):
svc = PPTVisionService()
result = svc.check_image(fake_image)
assert result.success is False
assert 'HTTP 500' in (result.error or '')
mock_mark.assert_called_once_with('http://test:11434')
def test_timeout_returns_failure(fake_image, monkeypatch):
monkeypatch.setenv('PPT_VISION_ENABLED', 'true')
from services.ppt_vision_service import PPTVisionService
import requests
with patch('services.ollama_service.resolve_ollama_host',
return_value='http://test:11434'), \
patch('services.ollama_service.mark_unhealthy'), \
patch('services.ppt_vision_service.requests.post',
side_effect=requests.Timeout('60s')):
svc = PPTVisionService()
result = svc.check_image(fake_image)
assert result.success is False
assert 'timeout' in (result.error or '').lower()