Files
learningcircuit--local-deep…/tests/news/test_folder_manager_comprehensive.py
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

731 lines
24 KiB
Python

"""
Comprehensive tests for FolderManager class.
Tests CRUD operations for folders and subscription organization.
"""
from unittest.mock import Mock
from datetime import datetime, timezone, timedelta
import uuid
class TestFolderManagerInit:
"""Tests for FolderManager initialization."""
def test_accepts_session(self):
"""Test accepts session parameter."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
manager = FolderManager(mock_session)
assert manager.session == mock_session
def test_stores_session_reference(self):
"""Test stores session reference."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
manager = FolderManager(mock_session)
assert manager.session is mock_session
class TestGetUserFolders:
"""Tests for get_user_folders method."""
def test_returns_list(self):
"""Test returns a list."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
mock_session.query().order_by().all.return_value = []
manager = FolderManager(mock_session)
result = manager.get_user_folders("user123")
assert isinstance(result, list)
def test_orders_by_name(self):
"""Test orders folders by name."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
manager = FolderManager(mock_session)
manager.get_user_folders("user123")
# Verify order_by was called
mock_session.query().order_by.assert_called()
def test_returns_all_folders(self):
"""Test returns all folders from query."""
from local_deep_research.news.folder_manager import FolderManager
mock_folder1 = Mock()
mock_folder2 = Mock()
mock_session = Mock()
mock_session.query().order_by().all.return_value = [
mock_folder1,
mock_folder2,
]
manager = FolderManager(mock_session)
result = manager.get_user_folders("user123")
assert len(result) == 2
class TestCreateFolder:
"""Tests for create_folder method."""
def test_creates_folder_with_name(self):
"""Test creates folder with given name."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
manager = FolderManager(mock_session)
manager.create_folder("My Folder")
# Verify add was called
mock_session.add.assert_called_once()
added_folder = mock_session.add.call_args[0][0]
assert added_folder.name == "My Folder"
def test_creates_folder_with_description(self):
"""Test creates folder with description."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
manager = FolderManager(mock_session)
manager.create_folder("My Folder", description="Test desc")
added_folder = mock_session.add.call_args[0][0]
assert added_folder.description == "Test desc"
def test_generates_uuid_for_id(self):
"""Test generates UUID for folder ID."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
manager = FolderManager(mock_session)
manager.create_folder("Test")
added_folder = mock_session.add.call_args[0][0]
# Should be a valid UUID
uuid.UUID(added_folder.id)
def test_commits_session(self):
"""Test commits session after creating folder."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
manager = FolderManager(mock_session)
manager.create_folder("Test")
mock_session.commit.assert_called_once()
def test_returns_created_folder(self):
"""Test returns the created folder."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
manager = FolderManager(mock_session)
result = manager.create_folder("Test", description="Desc")
assert result.name == "Test"
assert result.description == "Desc"
class TestUpdateFolder:
"""Tests for update_folder method."""
def test_returns_none_for_nonexistent_folder(self):
"""Test returns None when folder not found."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
mock_session.query().get.return_value = None
manager = FolderManager(mock_session)
result = manager.update_folder(999, name="New Name")
assert result is None
def test_updates_name(self):
"""Test updates folder name."""
from local_deep_research.news.folder_manager import FolderManager
mock_folder = Mock()
mock_folder.name = "Old Name"
mock_session = Mock()
mock_session.query().get.return_value = mock_folder
manager = FolderManager(mock_session)
manager.update_folder(1, name="New Name")
assert mock_folder.name == "New Name"
def test_updates_description(self):
"""Test updates folder description."""
from local_deep_research.news.folder_manager import FolderManager
mock_folder = Mock()
mock_folder.description = "Old desc"
mock_session = Mock()
mock_session.query().get.return_value = mock_folder
manager = FolderManager(mock_session)
manager.update_folder(1, description="New desc")
assert mock_folder.description == "New desc"
def test_does_not_update_id(self):
"""Test does not update folder ID."""
from local_deep_research.news.folder_manager import FolderManager
mock_folder = Mock()
mock_folder.id = "original-id"
mock_session = Mock()
mock_session.query().get.return_value = mock_folder
manager = FolderManager(mock_session)
manager.update_folder(1, id="new-id")
# ID should not change
assert mock_folder.id == "original-id"
def test_does_not_update_created_at(self):
"""Test does not update created_at."""
from local_deep_research.news.folder_manager import FolderManager
original_time = datetime(2023, 1, 1, tzinfo=timezone.utc)
mock_folder = Mock()
mock_folder.created_at = original_time
mock_session = Mock()
mock_session.query().get.return_value = mock_folder
manager = FolderManager(mock_session)
manager.update_folder(1, created_at=datetime.now(timezone.utc))
assert mock_folder.created_at == original_time
def test_updates_updated_at(self):
"""Test updates updated_at timestamp."""
from local_deep_research.news.folder_manager import FolderManager
mock_folder = Mock()
mock_session = Mock()
mock_session.query().get.return_value = mock_folder
manager = FolderManager(mock_session)
manager.update_folder(1, name="Test")
# updated_at should be set
assert mock_folder.updated_at is not None
def test_commits_session(self):
"""Test commits session after update."""
from local_deep_research.news.folder_manager import FolderManager
mock_folder = Mock()
mock_session = Mock()
mock_session.query().get.return_value = mock_folder
manager = FolderManager(mock_session)
manager.update_folder(1, name="Test")
mock_session.commit.assert_called_once()
def test_returns_updated_folder(self):
"""Test returns the updated folder."""
from local_deep_research.news.folder_manager import FolderManager
mock_folder = Mock()
mock_session = Mock()
mock_session.query().get.return_value = mock_folder
manager = FolderManager(mock_session)
result = manager.update_folder(1, name="Test")
assert result is mock_folder
class TestDeleteFolder:
"""Tests for delete_folder method."""
def test_returns_false_for_nonexistent_folder(self):
"""Test returns False when folder not found."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
mock_session.query().get.return_value = None
manager = FolderManager(mock_session)
result = manager.delete_folder(999)
assert result is False
def test_moves_subscriptions_to_target_folder(self):
"""Test moves subscriptions to target folder."""
from local_deep_research.news.folder_manager import FolderManager
mock_folder = Mock()
mock_folder.name = "Old Folder"
mock_session = Mock()
mock_session.query().get.return_value = mock_folder
manager = FolderManager(mock_session)
manager.delete_folder(1, move_to="New Folder")
# Should update subscriptions
mock_session.query().filter_by().update.assert_called_with(
{"folder": "New Folder"}
)
def test_clears_folder_on_subscriptions_when_no_target(self):
"""Test sets folder to None when no target specified."""
from local_deep_research.news.folder_manager import FolderManager
mock_folder = Mock()
mock_folder.name = "Test Folder"
mock_session = Mock()
mock_session.query().get.return_value = mock_folder
manager = FolderManager(mock_session)
manager.delete_folder(1)
# Should update subscriptions to None
mock_session.query().filter_by().update.assert_called_with(
{"folder": None}
)
def test_deletes_folder(self):
"""Test deletes the folder."""
from local_deep_research.news.folder_manager import FolderManager
mock_folder = Mock()
mock_session = Mock()
mock_session.query().get.return_value = mock_folder
manager = FolderManager(mock_session)
manager.delete_folder(1)
mock_session.delete.assert_called_once_with(mock_folder)
def test_commits_session(self):
"""Test commits session after delete."""
from local_deep_research.news.folder_manager import FolderManager
mock_folder = Mock()
mock_session = Mock()
mock_session.query().get.return_value = mock_folder
manager = FolderManager(mock_session)
manager.delete_folder(1)
mock_session.commit.assert_called_once()
def test_returns_true_on_success(self):
"""Test returns True on successful delete."""
from local_deep_research.news.folder_manager import FolderManager
mock_folder = Mock()
mock_session = Mock()
mock_session.query().get.return_value = mock_folder
manager = FolderManager(mock_session)
result = manager.delete_folder(1)
assert result is True
class TestGetSubscriptionsByFolder:
"""Tests for get_subscriptions_by_folder method."""
def test_returns_dict_with_folders_key(self):
"""Test returns dict with 'folders' key."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
mock_session.query().order_by().all.return_value = []
mock_session.query().filter_by().all.return_value = []
manager = FolderManager(mock_session)
result = manager.get_subscriptions_by_folder("user123")
assert "folders" in result
assert isinstance(result["folders"], list)
def test_returns_dict_with_uncategorized_key(self):
"""Test returns dict with 'uncategorized' key."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
mock_session.query().order_by().all.return_value = []
mock_session.query().filter_by().all.return_value = []
manager = FolderManager(mock_session)
result = manager.get_subscriptions_by_folder("user123")
assert "uncategorized" in result
assert isinstance(result["uncategorized"], list)
def test_includes_folder_data(self):
"""Test includes folder data for each folder."""
from local_deep_research.news.folder_manager import FolderManager
mock_folder = Mock()
mock_folder.name = "Test Folder"
mock_folder.to_dict.return_value = {"id": "1", "name": "Test Folder"}
mock_session = Mock()
mock_session.query().order_by().all.return_value = [mock_folder]
mock_session.query().filter_by().all.return_value = []
manager = FolderManager(mock_session)
result = manager.get_subscriptions_by_folder("user123")
assert len(result["folders"]) == 1
assert result["folders"][0]["folder"]["name"] == "Test Folder"
class TestUpdateSubscription:
"""Tests for update_subscription method."""
def test_returns_none_for_nonexistent_subscription(self):
"""Test returns None when subscription not found."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
mock_session.query().filter_by().first.return_value = None
manager = FolderManager(mock_session)
result = manager.update_subscription("sub-123", name="New Name")
assert result is None
def test_updates_attributes(self):
"""Test updates subscription attributes."""
from local_deep_research.news.folder_manager import FolderManager
mock_sub = Mock()
mock_sub.folder = "Old Folder"
mock_session = Mock()
mock_session.query().filter_by().first.return_value = mock_sub
manager = FolderManager(mock_session)
manager.update_subscription("sub-123", folder="New Folder")
assert mock_sub.folder == "New Folder"
def test_does_not_update_id(self):
"""Test does not update subscription ID."""
from local_deep_research.news.folder_manager import FolderManager
mock_sub = Mock()
mock_sub.id = "original-id"
mock_session = Mock()
mock_session.query().filter_by().first.return_value = mock_sub
manager = FolderManager(mock_session)
manager.update_subscription("sub-123", id="new-id")
assert mock_sub.id == "original-id"
def test_recalculates_next_refresh(self):
"""Test recalculates next_refresh when interval changes."""
from local_deep_research.news.folder_manager import FolderManager
mock_sub = Mock()
mock_sub.last_refresh = datetime(2024, 1, 1, 12, 0, tzinfo=timezone.utc)
mock_sub.refresh_interval_minutes = 60
mock_session = Mock()
mock_session.query().filter_by().first.return_value = mock_sub
manager = FolderManager(mock_session)
manager.update_subscription("sub-123", refresh_interval_minutes=120)
# Should be 2 hours after last_refresh
expected = mock_sub.last_refresh + timedelta(minutes=120)
assert mock_sub.next_refresh == expected
def test_uses_now_when_no_last_refresh(self):
"""Test uses current time when no last_refresh."""
from local_deep_research.news.folder_manager import FolderManager
mock_sub = Mock()
mock_sub.last_refresh = None
mock_sub.refresh_interval_minutes = 60
mock_session = Mock()
mock_session.query().filter_by().first.return_value = mock_sub
manager = FolderManager(mock_session)
before = datetime.now(timezone.utc)
manager.update_subscription("sub-123", refresh_interval_minutes=30)
# next_refresh should be in the future
assert mock_sub.next_refresh > before
def test_updates_updated_at(self):
"""Test updates updated_at timestamp."""
from local_deep_research.news.folder_manager import FolderManager
mock_sub = Mock()
mock_session = Mock()
mock_session.query().filter_by().first.return_value = mock_sub
manager = FolderManager(mock_session)
manager.update_subscription("sub-123", folder="Test")
assert mock_sub.updated_at is not None
def test_commits_session(self):
"""Test commits session after update."""
from local_deep_research.news.folder_manager import FolderManager
mock_sub = Mock()
mock_session = Mock()
mock_session.query().filter_by().first.return_value = mock_sub
manager = FolderManager(mock_session)
manager.update_subscription("sub-123", folder="Test")
mock_session.commit.assert_called_once()
def test_returns_updated_subscription(self):
"""Test returns the updated subscription."""
from local_deep_research.news.folder_manager import FolderManager
mock_sub = Mock()
mock_session = Mock()
mock_session.query().filter_by().first.return_value = mock_sub
manager = FolderManager(mock_session)
result = manager.update_subscription("sub-123", folder="Test")
assert result is mock_sub
class TestDeleteSubscription:
"""Tests for delete_subscription method."""
def test_returns_false_for_nonexistent_subscription(self):
"""Test returns False when subscription not found."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
mock_session.query().filter_by().first.return_value = None
manager = FolderManager(mock_session)
result = manager.delete_subscription("sub-123")
assert result is False
def test_deletes_subscription(self):
"""Test deletes the subscription."""
from local_deep_research.news.folder_manager import FolderManager
mock_sub = Mock()
mock_session = Mock()
mock_session.query().filter_by().first.return_value = mock_sub
manager = FolderManager(mock_session)
manager.delete_subscription("sub-123")
mock_session.delete.assert_called_once_with(mock_sub)
def test_commits_session(self):
"""Test commits session after delete."""
from local_deep_research.news.folder_manager import FolderManager
mock_sub = Mock()
mock_session = Mock()
mock_session.query().filter_by().first.return_value = mock_sub
manager = FolderManager(mock_session)
manager.delete_subscription("sub-123")
mock_session.commit.assert_called_once()
def test_returns_true_on_success(self):
"""Test returns True on successful delete."""
from local_deep_research.news.folder_manager import FolderManager
mock_sub = Mock()
mock_session = Mock()
mock_session.query().filter_by().first.return_value = mock_sub
manager = FolderManager(mock_session)
result = manager.delete_subscription("sub-123")
assert result is True
class TestGetSubscriptionStats:
"""Tests for get_subscription_stats method."""
def test_returns_dict(self):
"""Test returns a dictionary."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
mock_session.query().count.return_value = 0
mock_session.query().filter_by().count.return_value = 0
mock_session.query().order_by().all.return_value = []
manager = FolderManager(mock_session)
result = manager.get_subscription_stats("user123")
assert isinstance(result, dict)
def test_includes_total_count(self):
"""Test includes total subscription count."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
mock_session.query().count.return_value = 10
mock_session.query().filter_by().count.return_value = 0
mock_session.query().order_by().all.return_value = []
manager = FolderManager(mock_session)
result = manager.get_subscription_stats("user123")
assert result["total"] == 10
def test_includes_active_count(self):
"""Test includes active subscription count."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
mock_session.query().count.return_value = 10
mock_session.query().filter_by().count.return_value = 8
mock_session.query().order_by().all.return_value = []
manager = FolderManager(mock_session)
result = manager.get_subscription_stats("user123")
assert "active" in result
def test_includes_by_type_counts(self):
"""Test includes subscription counts by type."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
mock_session.query().count.return_value = 10
mock_session.query().filter_by().count.return_value = 5
mock_session.query().order_by().all.return_value = []
manager = FolderManager(mock_session)
result = manager.get_subscription_stats("user123")
assert "by_type" in result
assert "search" in result["by_type"]
assert "topic" in result["by_type"]
def test_includes_folder_count(self):
"""Test includes folder count."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
mock_session.query().count.return_value = 0
mock_session.query().filter_by().count.return_value = 0
mock_session.query().order_by().all.return_value = [Mock(), Mock()]
manager = FolderManager(mock_session)
result = manager.get_subscription_stats("user123")
assert result["folders"] == 2
class TestSubToDict:
"""Tests for _sub_to_dict helper method."""
def test_includes_id(self):
"""Test includes subscription ID."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
manager = FolderManager(mock_session)
mock_sub = Mock()
mock_sub.id = "sub-123"
mock_sub.subscription_type = "search"
mock_sub.query_or_topic = "test query"
mock_sub.created_at = None
mock_sub.last_refresh = None
mock_sub.next_refresh = None
mock_sub.refresh_interval_minutes = 60
mock_sub.status = "active"
result = manager._sub_to_dict(mock_sub)
assert result["id"] == "sub-123"
def test_includes_type(self):
"""Test includes subscription type."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
manager = FolderManager(mock_session)
mock_sub = Mock()
mock_sub.id = "sub-123"
mock_sub.subscription_type = "topic"
mock_sub.query_or_topic = "AI News"
mock_sub.created_at = None
mock_sub.last_refresh = None
mock_sub.next_refresh = None
mock_sub.refresh_interval_minutes = 60
mock_sub.status = "active"
result = manager._sub_to_dict(mock_sub)
assert result["type"] == "topic"
def test_formats_datetime_as_iso(self):
"""Test formats datetime as ISO string."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
manager = FolderManager(mock_session)
test_time = datetime(2024, 1, 15, 12, 30, 45, tzinfo=timezone.utc)
mock_sub = Mock()
mock_sub.id = "sub-123"
mock_sub.subscription_type = "search"
mock_sub.query_or_topic = "test"
mock_sub.created_at = test_time
mock_sub.last_refresh = test_time
mock_sub.next_refresh = test_time
mock_sub.refresh_interval_minutes = 60
mock_sub.status = "active"
result = manager._sub_to_dict(mock_sub)
assert result["created_at"] == test_time.isoformat()
def test_handles_none_datetimes(self):
"""Test handles None datetime values."""
from local_deep_research.news.folder_manager import FolderManager
mock_session = Mock()
manager = FolderManager(mock_session)
mock_sub = Mock()
mock_sub.id = "sub-123"
mock_sub.subscription_type = "search"
mock_sub.query_or_topic = "test"
mock_sub.created_at = None
mock_sub.last_refresh = None
mock_sub.next_refresh = None
mock_sub.refresh_interval_minutes = 60
mock_sub.status = "active"
result = manager._sub_to_dict(mock_sub)
assert result["created_at"] is None
assert result["last_refresh"] is None
assert result["next_refresh"] is None