Files
wehub-resource-sync 7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

331 lines
10 KiB
Python

"""
Extended tests for news/flask_api.py
Tests cover:
- safe_error_message() helper
- get_user_id() helper
- Flask route handlers with mocking
- Error handling and response codes
- Request validation
"""
import pytest
from unittest.mock import patch
from flask import Flask
@pytest.fixture
def flask_app():
"""Create a Flask app for testing."""
app = Flask(__name__)
app.config["TESTING"] = True
return app
class TestSafeErrorMessage:
"""Tests for safe_error_message() helper."""
def test_returns_string(self):
"""Returns a string."""
from local_deep_research.news.flask_api import safe_error_message
result = safe_error_message(Exception("test"))
assert isinstance(result, str)
def test_handles_value_error(self):
"""Returns 'Invalid input provided' for ValueError."""
from local_deep_research.news.flask_api import safe_error_message
result = safe_error_message(ValueError("bad value"))
assert result == "Invalid input provided"
def test_handles_key_error(self):
"""Returns 'Required data missing' for KeyError."""
from local_deep_research.news.flask_api import safe_error_message
result = safe_error_message(KeyError("missing_key"))
assert result == "Required data missing"
def test_handles_type_error(self):
"""Returns 'Invalid data format' for TypeError."""
from local_deep_research.news.flask_api import safe_error_message
result = safe_error_message(TypeError("wrong type"))
assert result == "Invalid data format"
def test_handles_generic_exception(self):
"""Returns generic message for other exceptions."""
from local_deep_research.news.flask_api import safe_error_message
result = safe_error_message(Exception("unknown error"))
assert "error occurred" in result.lower()
def test_includes_context_in_message(self):
"""Includes context in error message."""
from local_deep_research.news.flask_api import safe_error_message
result = safe_error_message(Exception("error"), context="testing")
assert "testing" in result
def test_handles_none_exception(self):
"""Handles None-like exception gracefully."""
from local_deep_research.news.flask_api import safe_error_message
result = safe_error_message(Exception(""))
assert isinstance(result, str)
def test_empty_context(self):
"""Handles empty context string."""
from local_deep_research.news.flask_api import safe_error_message
result = safe_error_message(Exception("error"), context="")
assert isinstance(result, str)
class TestGetUserId:
"""Tests for get_user_id() helper."""
def test_function_exists(self):
"""get_user_id function exists."""
from local_deep_research.news.flask_api import get_user_id
assert callable(get_user_id)
def test_returns_none_when_no_current_user(self):
"""Returns None when current_user returns None."""
# Create app context for the import inside get_user_id
app = Flask(__name__)
with app.app_context():
with patch(
"local_deep_research.web.auth.decorators.current_user"
) as mock_current:
mock_current.return_value = None
from local_deep_research.news.flask_api import get_user_id
result = get_user_id()
assert result is None
def test_returns_username_when_user_exists(self):
"""Returns username when current_user returns a username."""
app = Flask(__name__)
with app.app_context():
with patch(
"local_deep_research.web.auth.decorators.current_user"
) as mock_current:
mock_current.return_value = "testuser"
from local_deep_research.news.flask_api import get_user_id
result = get_user_id()
assert result == "testuser"
class TestNewsBlueprintExists:
"""Tests for news_api_bp Blueprint."""
def test_blueprint_name(self):
"""Blueprint name is 'news_api'."""
from local_deep_research.news.flask_api import news_api_bp
assert news_api_bp.name == "news_api"
def test_blueprint_url_prefix(self):
"""Blueprint has /api url_prefix."""
from local_deep_research.news.flask_api import news_api_bp
assert news_api_bp.url_prefix == "/api"
class TestFeedRouteValidation:
"""Tests for /feed route validation."""
def test_feed_route_function_exists(self):
"""get_news_feed function exists."""
from local_deep_research.news.flask_api import get_news_feed
assert callable(get_news_feed)
class TestErrorHandlers:
"""Tests for error handler functions."""
def test_bad_request_handler_exists(self):
"""400 error handler is defined."""
app = Flask(__name__)
with app.app_context():
from local_deep_research.news.flask_api import bad_request
result = bad_request(Exception("test"))
assert result[1] == 400
def test_not_found_handler_exists(self):
"""404 error handler is defined."""
app = Flask(__name__)
with app.app_context():
from local_deep_research.news.flask_api import not_found
result = not_found(Exception("test"))
assert result[1] == 404
def test_internal_error_handler_exists(self):
"""500 error handler is defined."""
app = Flask(__name__)
with app.app_context():
from local_deep_research.news.flask_api import internal_error
result = internal_error(Exception("test"))
assert result[1] == 500
def test_bad_request_returns_json(self):
"""400 error handler returns JSON."""
app = Flask(__name__)
with app.app_context():
from local_deep_research.news.flask_api import bad_request
result = bad_request(Exception("test"))
# Result is tuple (response, status_code)
assert "error" in result[0].get_json()
def test_not_found_returns_json(self):
"""404 error handler returns JSON."""
app = Flask(__name__)
with app.app_context():
from local_deep_research.news.flask_api import not_found
result = not_found(Exception("test"))
assert "error" in result[0].get_json()
def test_internal_error_returns_json(self):
"""500 error handler returns JSON."""
app = Flask(__name__)
with app.app_context():
from local_deep_research.news.flask_api import internal_error
result = internal_error(Exception("test"))
assert "error" in result[0].get_json()
class TestSafeErrorMessageExtended:
"""Extended tests for safe_error_message() helper."""
def test_attribute_error_returns_generic(self):
"""Returns generic message for AttributeError."""
from local_deep_research.news.flask_api import safe_error_message
result = safe_error_message(AttributeError("missing attr"))
assert "error occurred" in result.lower()
def test_index_error_returns_generic(self):
"""Returns generic message for IndexError."""
from local_deep_research.news.flask_api import safe_error_message
result = safe_error_message(IndexError("list index out of range"))
assert "error occurred" in result.lower()
def test_runtime_error_returns_generic(self):
"""Returns generic message for RuntimeError."""
from local_deep_research.news.flask_api import safe_error_message
result = safe_error_message(RuntimeError("runtime issue"))
assert "error occurred" in result.lower()
def test_context_with_special_characters(self):
"""Handles context with special characters."""
from local_deep_research.news.flask_api import safe_error_message
result = safe_error_message(Exception("error"), context="test <>&\"'")
assert isinstance(result, str)
def test_long_context_string(self):
"""Handles long context string."""
from local_deep_research.news.flask_api import safe_error_message
long_context = "x" * 1000
result = safe_error_message(Exception("error"), context=long_context)
assert isinstance(result, str)
def test_unicode_context(self):
"""Handles unicode in context."""
from local_deep_research.news.flask_api import safe_error_message
result = safe_error_message(Exception("error"), context="日本語")
assert isinstance(result, str)
class TestBlueprintConfiguration:
"""Tests for Blueprint configuration."""
def test_blueprint_has_routes_registered(self):
"""Blueprint has routes registered."""
from local_deep_research.news.flask_api import news_api_bp
# Blueprint should have deferred functions
assert len(news_api_bp.deferred_functions) > 0
def test_blueprint_is_flask_blueprint(self):
"""Blueprint is a Flask Blueprint instance."""
from local_deep_research.news.flask_api import news_api_bp
from flask import Blueprint
assert isinstance(news_api_bp, Blueprint)
class TestErrorHandlerMessages:
"""Tests for error handler message content."""
def test_bad_request_message_content(self):
"""400 handler returns 'Bad request' message."""
app = Flask(__name__)
with app.app_context():
from local_deep_research.news.flask_api import bad_request
result = bad_request(Exception("test"))
json_data = result[0].get_json()
assert json_data["error"] == "Bad request"
def test_not_found_message_content(self):
"""404 handler returns 'Resource not found' message."""
app = Flask(__name__)
with app.app_context():
from local_deep_research.news.flask_api import not_found
result = not_found(Exception("test"))
json_data = result[0].get_json()
assert json_data["error"] == "Resource not found"
def test_internal_error_message_content(self):
"""500 handler returns 'Internal server error' message."""
app = Flask(__name__)
with app.app_context():
from local_deep_research.news.flask_api import internal_error
result = internal_error(Exception("test"))
json_data = result[0].get_json()
assert json_data["error"] == "Internal server error"