tests: centralize script path setup in conftest.py

Add a pytest-discovered tests/conftest.py for the last30days scripts path and
remove duplicate per-file sys.path.insert boilerplate from tests.

Normalize affected imports to rely on the shared scripts path and remove the
now-unneeded E402 suppressions.
This commit is contained in:
Yong-yuan-X
2026-05-20 23:16:07 +08:00
parent 850c7e0185
commit e74b0e1e93
84 changed files with 194 additions and 578 deletions
+17 -17
View File
@@ -1,20 +1,16 @@
"""Tests for hackernews.py - HN search via Algolia API."""
import json
import sys
from datetime import datetime, timezone
from pathlib import Path
from unittest.mock import Mock, patch
import pytest
sys.path.insert(0, str(Path(__file__).parent.parent / "skills" / "last30days" / "scripts"))
from lib import hackernews
# === Helper Functions ===
def create_mock_hit(
object_id="12345",
title="Test HN Story",
@@ -40,9 +36,9 @@ def create_mock_hit(
"url": url,
}
# === Tests for _date_to_unix() ===
def test_date_to_unix_basic():
"""Test converting YYYY-MM-DD to Unix timestamp."""
result = hackernews._date_to_unix("2026-01-01")
@@ -59,9 +55,9 @@ def test_date_to_unix_leap_day():
expected = datetime(2024, 2, 29, tzinfo=timezone.utc).timestamp()
assert result == int(expected)
# === Tests for _unix_to_date() ===
def test_unix_to_date_basic():
"""Test converting Unix timestamp to YYYY-MM-DD."""
ts = int(datetime(2026, 1, 15, tzinfo=timezone.utc).timestamp())
@@ -77,9 +73,9 @@ def test_unix_to_date_with_time():
assert result == "2026-01-15"
# === Tests for _strip_html() ===
def test_strip_html_basic():
"""Test HTML stripping and entity decoding."""
html_text = "<p>Hello &amp; goodbye</p>"
@@ -113,9 +109,9 @@ def test_strip_html_entities():
# Entities are decoded
assert "&" in result or "test" in result
# === Tests for _title_matches_query() ===
def test_title_matches_query_basic():
"""Test basic query matching."""
title = "New AI framework for developers"
@@ -199,10 +195,11 @@ def test_title_matches_query_flattens_hyphens_and_commas():
# query 'rust, go, zig' flattens; title contains 'go'
assert hackernews._title_matches_query("Go 1.24 generics update", "rust, go, zig") is True
# === Tests for search_hackernews() ===
@patch('lib.hackernews.http.request')
def test_search_hackernews_basic(mock_request):
"""Test basic HN search."""
mock_request.return_value = {
@@ -221,8 +218,9 @@ def test_search_hackernews_basic(mock_request):
assert len(result["hits"]) == 1
assert mock_request.called
@patch('lib.hackernews.http.request')
def test_search_hackernews_depth_config(mock_request):
"""Test that depth parameter controls hit count."""
mock_request.return_value = {"hits": [], "nbHits": 0}
@@ -235,8 +233,9 @@ def test_search_hackernews_depth_config(mock_request):
assert "hitsPerPage=15" in url
@patch('lib.hackernews.http.request')
def test_search_hackernews_date_filtering(mock_request):
"""Test that date range is applied correctly."""
mock_request.return_value = {"hits": [], "nbHits": 0}
@@ -250,8 +249,9 @@ def test_search_hackernews_date_filtering(mock_request):
assert "numericFilters" in url
assert "created_at_i" in url
@patch('lib.hackernews.http.request')
def test_search_hackernews_http_error_handling(mock_request):
"""Test graceful handling of HTTP errors."""
from lib.http import HTTPError
@@ -263,8 +263,9 @@ def test_search_hackernews_http_error_handling(mock_request):
assert result["hits"] == []
assert "error" in result
@patch('lib.hackernews.http.request')
def test_search_hackernews_engagement_filter(mock_request):
"""Test that low-engagement stories are filtered."""
mock_request.return_value = {"hits": [], "nbHits": 0}
@@ -277,9 +278,9 @@ def test_search_hackernews_engagement_filter(mock_request):
# Should filter for points > 2 (URL-encoded)
assert "points" in url and "%3E2" in url
# === Tests for parse_hackernews_response() ===
def test_parse_hackernews_response_basic():
"""Test parsing basic Algolia response."""
response = {
@@ -402,9 +403,9 @@ def test_parse_hackernews_response_empty_response():
assert items == []
# === Tests for engagement scoring ===
def test_engagement_score_calculation():
"""Test that engagement dict contains points and comments."""
response = {
@@ -435,6 +436,5 @@ def test_engagement_score_zero_values():
assert engagement["points"] == 0
assert engagement["comments"] == 0
if __name__ == "__main__":
pytest.main([__file__, "-v"])