chore: fixed imports and tests configuration

This commit is contained in:
2025-12-27 19:39:36 +01:00
parent b132554631
commit 6195abbaa5
43 changed files with 216 additions and 243 deletions

View File

@@ -1,20 +1,16 @@
"""Pytest configuration and shared fixtures."""
import sys
from pathlib import Path
#TODO: Moved directory, should not be necessary anymore but need to check !!
# TODO: Moved directory, should not be necessary anymore but need to check !!
# Ajouter le dossier parent (brain) au PYTHONPATH
# sys.path.insert(0, str(Path(__file__).parent.parent))
import pytest
import shutil
import sys
import tempfile
from pathlib import Path
from unittest.mock import MagicMock, Mock
import pytest
from infrastructure.persistence import Memory, set_memory
from alfred.infrastructure.persistence import Memory, set_memory
@pytest.fixture
@@ -255,7 +251,6 @@ def mock_deepseek():
def test_something(mock_deepseek):
# Your test code here
"""
import sys
from unittest.mock import Mock
# Save the original module if it exists

View File

@@ -2,8 +2,8 @@
from unittest.mock import Mock
from agent.agent import Agent
from infrastructure.persistence import get_memory
from alfred.agent.agent import Agent
from alfred.infrastructure.persistence import get_memory
class TestAgentInit:

View File

@@ -1,11 +1,9 @@
"""Edge case tests for the Agent."""
import pytest
from unittest.mock import Mock
import pytest
from agent.agent import Agent
from infrastructure.persistence import get_memory
from alfred.agent.agent import Agent
from alfred.infrastructure.persistence import get_memory
class TestExecuteToolCallEdgeCases:
@@ -16,7 +14,7 @@ class TestExecuteToolCallEdgeCases:
agent = Agent(llm=mock_llm)
# Mock a tool that returns None
from agent.registry import Tool
from alfred.agent.registry import Tool
agent.tools["test_tool"] = Tool(
name="test_tool", description="Test", func=lambda: None, parameters={}
@@ -34,7 +32,7 @@ class TestExecuteToolCallEdgeCases:
"""Should propagate KeyboardInterrupt."""
agent = Agent(llm=mock_llm)
from agent.registry import Tool
from alfred.agent.registry import Tool
def raise_interrupt():
raise KeyboardInterrupt()

View File

@@ -10,7 +10,7 @@ class TestHealthEndpoint:
def test_health_check(self, memory):
"""Should return healthy status."""
from app import app
from alfred.app import app
client = TestClient(app)
@@ -25,7 +25,7 @@ class TestModelsEndpoint:
def test_list_models(self, memory):
"""Should return model list."""
from app import app
from alfred.app import app
client = TestClient(app)
@@ -43,7 +43,7 @@ class TestMemoryEndpoints:
def test_get_memory_state(self, memory):
"""Should return full memory state."""
from app import app
from alfred.app import app
client = TestClient(app)
@@ -57,7 +57,7 @@ class TestMemoryEndpoints:
def test_get_search_results_empty(self, memory):
"""Should return empty when no search results."""
from app import app
from alfred.app import app
client = TestClient(app)
@@ -69,7 +69,7 @@ class TestMemoryEndpoints:
def test_get_search_results_with_data(self, memory_with_search_results):
"""Should return search results when available."""
from app import app
from alfred.app import app
client = TestClient(app)
@@ -83,7 +83,7 @@ class TestMemoryEndpoints:
def test_clear_session(self, memory_with_search_results):
"""Should clear session memories."""
from app import app
from alfred.app import app
client = TestClient(app)
@@ -102,10 +102,10 @@ class TestChatCompletionsEndpoint:
def test_chat_completion_success(self, memory):
"""Should return chat completion."""
from app import app
from alfred.app import app
# Patch the agent's step method directly
with patch("app.agent.step", return_value="Hello! How can I help?"):
with patch("alfred.app.agent.step", return_value="Hello! How can I help?"):
client = TestClient(app)
response = client.post(
@@ -123,7 +123,7 @@ class TestChatCompletionsEndpoint:
def test_chat_completion_no_user_message(self, memory):
"""Should return error if no user message."""
from app import app
from alfred.app import app
client = TestClient(app)
@@ -146,7 +146,7 @@ class TestChatCompletionsEndpoint:
def test_chat_completion_empty_messages(self, memory):
"""Should return error for empty messages."""
from app import app
from alfred.app import app
client = TestClient(app)
@@ -162,7 +162,7 @@ class TestChatCompletionsEndpoint:
def test_chat_completion_invalid_json(self, memory):
"""Should return error for invalid JSON."""
from app import app
from alfred.app import app
client = TestClient(app)
@@ -176,9 +176,9 @@ class TestChatCompletionsEndpoint:
def test_chat_completion_streaming(self, memory):
"""Should support streaming mode."""
from app import app
from alfred.app import app
with patch("app.agent.step", return_value="Streaming response"):
with patch("alfred.app.agent.step", return_value="Streaming response"):
client = TestClient(app)
response = client.post(
@@ -195,9 +195,9 @@ class TestChatCompletionsEndpoint:
def test_chat_completion_extracts_last_user_message(self, memory):
"""Should use last user message."""
from app import app
from alfred.app import app
with patch("app.agent.step", return_value="Response") as mock_step:
with patch("alfred.app.agent.step", return_value="Response") as mock_step:
client = TestClient(app)
response = client.post(
@@ -218,9 +218,9 @@ class TestChatCompletionsEndpoint:
def test_chat_completion_response_format(self, memory):
"""Should return OpenAI-compatible format."""
from app import app
from alfred.app import app
with patch("app.agent.step", return_value="Test response"):
with patch("alfred.app.agent.step", return_value="Test response"):
client = TestClient(app)
response = client.post(

View File

@@ -10,7 +10,8 @@ class TestChatCompletionsEdgeCases:
def test_very_long_message(self, memory):
"""Should handle very long user message."""
from app import agent, app
from alfred.app import app
from alfred.agent import agent
# Patch the agent's LLM directly
mock_llm = Mock()
@@ -32,7 +33,8 @@ class TestChatCompletionsEdgeCases:
def test_unicode_message(self, memory):
"""Should handle unicode in message."""
from app import agent, app
from alfred.app import app
from alfred.agent import agent
mock_llm = Mock()
mock_llm.complete.return_value = {
@@ -57,7 +59,8 @@ class TestChatCompletionsEdgeCases:
def test_special_characters_in_message(self, memory):
"""Should handle special characters."""
from app import agent, app
from alfred.app import app
from alfred.agent import agent
mock_llm = Mock()
mock_llm.complete.return_value = {"role": "assistant", "content": "Response"}
@@ -78,12 +81,12 @@ class TestChatCompletionsEdgeCases:
def test_empty_content_in_message(self, memory):
"""Should handle empty content in message."""
with patch("app.DeepSeekClient") as mock_llm_class:
with patch("alfred.app.DeepSeekClient") as mock_llm_class:
mock_llm = Mock()
mock_llm.complete.return_value = "Response"
mock_llm_class.return_value = mock_llm
from app import app
from alfred.app import app
client = TestClient(app)
@@ -100,11 +103,11 @@ class TestChatCompletionsEdgeCases:
def test_null_content_in_message(self, memory):
"""Should handle null content in message."""
with patch("app.DeepSeekClient") as mock_llm_class:
with patch("alfred.app.DeepSeekClient") as mock_llm_class:
mock_llm = Mock()
mock_llm_class.return_value = mock_llm
from app import app
from alfred.app import app
client = TestClient(app)
@@ -120,11 +123,11 @@ class TestChatCompletionsEdgeCases:
def test_missing_content_field(self, memory):
"""Should handle missing content field."""
with patch("app.DeepSeekClient") as mock_llm_class:
with patch("alfred.app.DeepSeekClient") as mock_llm_class:
mock_llm = Mock()
mock_llm_class.return_value = mock_llm
from app import app
from alfred.app import app
client = TestClient(app)
@@ -141,11 +144,11 @@ class TestChatCompletionsEdgeCases:
def test_missing_role_field(self, memory):
"""Should handle missing role field."""
with patch("app.DeepSeekClient") as mock_llm_class:
with patch("alfred.app.DeepSeekClient") as mock_llm_class:
mock_llm = Mock()
mock_llm_class.return_value = mock_llm
from app import app
from alfred.app import app
client = TestClient(app)
@@ -162,12 +165,12 @@ class TestChatCompletionsEdgeCases:
def test_invalid_role(self, memory):
"""Should handle invalid role."""
with patch("app.DeepSeekClient") as mock_llm_class:
with patch("alfred.app.DeepSeekClient") as mock_llm_class:
mock_llm = Mock()
mock_llm.complete.return_value = "Response"
mock_llm_class.return_value = mock_llm
from app import app
from alfred.app import app
client = TestClient(app)
@@ -184,7 +187,8 @@ class TestChatCompletionsEdgeCases:
def test_many_messages(self, memory):
"""Should handle many messages in conversation."""
from app import agent, app
from alfred.app import app
from alfred.agent import agent
mock_llm = Mock()
mock_llm.complete.return_value = {"role": "assistant", "content": "Response"}
@@ -210,11 +214,11 @@ class TestChatCompletionsEdgeCases:
def test_only_system_messages(self, memory):
"""Should reject if only system messages."""
with patch("app.DeepSeekClient") as mock_llm_class:
with patch("alfred.app.DeepSeekClient") as mock_llm_class:
mock_llm = Mock()
mock_llm_class.return_value = mock_llm
from app import app
from alfred.app import app
client = TestClient(app)
@@ -233,11 +237,11 @@ class TestChatCompletionsEdgeCases:
def test_only_assistant_messages(self, memory):
"""Should reject if only assistant messages."""
with patch("app.DeepSeekClient") as mock_llm_class:
with patch("alfred.app.DeepSeekClient") as mock_llm_class:
mock_llm = Mock()
mock_llm_class.return_value = mock_llm
from app import app
from alfred.app import app
client = TestClient(app)
@@ -255,11 +259,11 @@ class TestChatCompletionsEdgeCases:
def test_messages_not_array(self, memory):
"""Should reject if messages is not array."""
with patch("app.DeepSeekClient") as mock_llm_class:
with patch("alfred.app.DeepSeekClient") as mock_llm_class:
mock_llm = Mock()
mock_llm_class.return_value = mock_llm
from app import app
from alfred.app import app
client = TestClient(app)
@@ -276,11 +280,11 @@ class TestChatCompletionsEdgeCases:
def test_message_not_object(self, memory):
"""Should handle message that is not object."""
with patch("app.DeepSeekClient") as mock_llm_class:
with patch("alfred.app.DeepSeekClient") as mock_llm_class:
mock_llm = Mock()
mock_llm_class.return_value = mock_llm
from app import app
from alfred.app import app
client = TestClient(app)
@@ -297,7 +301,8 @@ class TestChatCompletionsEdgeCases:
def test_extra_fields_in_request(self, memory):
"""Should ignore extra fields in request."""
from app import agent, app
from alfred.app import app
from alfred.agent import agent
mock_llm = Mock()
mock_llm.complete.return_value = {"role": "assistant", "content": "Response"}
@@ -320,8 +325,9 @@ class TestChatCompletionsEdgeCases:
def test_streaming_with_tool_call(self, memory, real_folder):
"""Should handle streaming with tool execution."""
from app import agent, app
from infrastructure.persistence import get_memory
from alfred.app import app
from alfred.agent import agent
from alfred.infrastructure.persistence import get_memory
mem = get_memory()
mem.ltm.set_config("download_folder", str(real_folder["downloads"]))
@@ -365,7 +371,8 @@ class TestChatCompletionsEdgeCases:
def test_concurrent_requests_simulation(self, memory):
"""Should handle rapid sequential requests."""
from app import agent, app
from alfred.app import app
from alfred.agent import agent
mock_llm = Mock()
mock_llm.complete.return_value = {"role": "assistant", "content": "Response"}
@@ -385,7 +392,8 @@ class TestChatCompletionsEdgeCases:
def test_llm_returns_json_in_response(self, memory):
"""Should handle LLM returning JSON in text response."""
from app import agent, app
from alfred.app import app
from alfred.agent import agent
mock_llm = Mock()
mock_llm.complete.return_value = {
@@ -414,9 +422,9 @@ class TestMemoryEndpointsEdgeCases:
def test_memory_state_with_large_data(self, memory):
"""Should handle large memory state."""
with patch("app.DeepSeekClient") as mock_llm:
with patch("alfred.app.DeepSeekClient") as mock_llm:
mock_llm.return_value = Mock()
from app import app
from alfred.app import app
# Add lots of data to memory
for i in range(100):
@@ -432,9 +440,9 @@ class TestMemoryEndpointsEdgeCases:
def test_memory_state_with_unicode(self, memory):
"""Should handle unicode in memory state."""
with patch("app.DeepSeekClient") as mock_llm:
with patch("alfred.app.DeepSeekClient") as mock_llm:
mock_llm.return_value = Mock()
from app import app
from alfred.app import app
memory.ltm.set_config("japanese", "日本語テスト")
memory.stm.add_message("user", "🎬 Movie request")
@@ -448,9 +456,9 @@ class TestMemoryEndpointsEdgeCases:
def test_search_results_with_special_chars(self, memory):
"""Should handle special characters in search results."""
with patch("app.DeepSeekClient") as mock_llm:
with patch("alfred.app.DeepSeekClient") as mock_llm:
mock_llm.return_value = Mock()
from app import app
from alfred.app import app
memory.episodic.store_search_results(
"Test <script>alert('xss')</script>",
@@ -467,9 +475,9 @@ class TestMemoryEndpointsEdgeCases:
def test_clear_session_idempotent(self, memory):
"""Should be idempotent - multiple clears should work."""
with patch("app.DeepSeekClient") as mock_llm:
with patch("alfred.app.DeepSeekClient") as mock_llm:
mock_llm.return_value = Mock()
from app import app
from alfred.app import app
client = TestClient(app)
@@ -480,9 +488,9 @@ class TestMemoryEndpointsEdgeCases:
def test_clear_session_preserves_ltm(self, memory):
"""Should preserve LTM after clear."""
with patch("app.DeepSeekClient") as mock_llm:
with patch("alfred.app.DeepSeekClient") as mock_llm:
mock_llm.return_value = Mock()
from app import app
from alfred.app import app
memory.ltm.set_config("important", "data")
memory.stm.add_message("user", "Hello")
@@ -502,9 +510,9 @@ class TestHealthEndpointEdgeCases:
def test_health_returns_version(self, memory):
"""Should return version in health check."""
with patch("app.DeepSeekClient") as mock_llm:
with patch("alfred.app.DeepSeekClient") as mock_llm:
mock_llm.return_value = Mock()
from app import app
from alfred.app import app
client = TestClient(app)
@@ -515,9 +523,9 @@ class TestHealthEndpointEdgeCases:
def test_health_with_query_params(self, memory):
"""Should ignore query parameters."""
with patch("app.DeepSeekClient") as mock_llm:
with patch("alfred.app.DeepSeekClient") as mock_llm:
mock_llm.return_value = Mock()
from app import app
from alfred.app import app
client = TestClient(app)
@@ -531,9 +539,9 @@ class TestModelsEndpointEdgeCases:
def test_models_response_format(self, memory):
"""Should return OpenAI-compatible format."""
with patch("app.DeepSeekClient") as mock_llm:
with patch("alfred.app.DeepSeekClient") as mock_llm:
mock_llm.return_value = Mock()
from app import app
from alfred.app import app
client = TestClient(app)

View File

@@ -1,8 +1,7 @@
"""Critical tests for configuration validation."""
import pytest
from agent.config import ConfigurationError, Settings
from alfred.agent.config import ConfigurationError, Settings
class TestConfigValidation:

View File

@@ -1,12 +1,11 @@
"""Edge case tests for configuration and parameters."""
import os
import pytest
from unittest.mock import patch
import pytest
from agent.config import ConfigurationError, Settings
from agent.parameters import (
from alfred.agent.config import ConfigurationError, Settings
from alfred.agent.parameters import (
REQUIRED_PARAMETERS,
ParameterSchema,
format_parameters_for_prompt,

View File

@@ -1,17 +1,15 @@
"""Edge case tests for domain entities and value objects."""
import pytest
from datetime import datetime
import pytest
from domain.movies.entities import Movie
from domain.movies.value_objects import MovieTitle, Quality, ReleaseYear
from domain.shared.exceptions import ValidationError
from domain.shared.value_objects import FilePath, FileSize, ImdbId
from domain.subtitles.entities import Subtitle
from domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset
from domain.tv_shows.entities import TVShow
from domain.tv_shows.value_objects import ShowStatus
from alfred.domain.movies.entities import Movie
from alfred.domain.movies.value_objects import MovieTitle, Quality, ReleaseYear
from alfred.domain.shared.exceptions import ValidationError
from alfred.domain.shared.value_objects import FilePath, FileSize, ImdbId
from alfred.domain.subtitles.entities import Subtitle
from alfred.domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset
from alfred.domain.tv_shows.entities import TVShow
from alfred.domain.tv_shows.value_objects import ShowStatus
class TestImdbIdEdgeCases:

View File

@@ -1,10 +1,8 @@
"""Tests for the Memory system."""
import pytest
from datetime import datetime
import pytest
from infrastructure.persistence import (
from alfred.infrastructure.persistence import (
EpisodicMemory,
LongTermMemory,
Memory,
@@ -13,7 +11,7 @@ from infrastructure.persistence import (
has_memory,
init_memory,
)
from infrastructure.persistence.context import _memory_ctx
from alfred.infrastructure.persistence.context import _memory_ctx
def is_iso_format(s: str) -> bool:

View File

@@ -4,8 +4,7 @@ import json
import os
import pytest
from infrastructure.persistence import (
from alfred.infrastructure.persistence import (
EpisodicMemory,
LongTermMemory,
Memory,
@@ -14,7 +13,7 @@ from infrastructure.persistence import (
init_memory,
set_memory,
)
from infrastructure.persistence.context import _memory_ctx
from alfred.infrastructure.persistence.context import _memory_ctx
class TestLongTermMemoryEdgeCases:

View File

@@ -1,7 +1,7 @@
"""Tests for PromptBuilder."""
from agent.prompts import PromptBuilder
from agent.registry import make_tools
from alfred.agent.prompts import PromptBuilder
from alfred.agent.registry import make_tools
class TestPromptBuilder:

View File

@@ -1,7 +1,7 @@
"""Critical tests for prompt builder - Tests that would have caught bugs."""
from agent.prompts import PromptBuilder
from agent.registry import make_tools
from alfred.agent.prompts import PromptBuilder
from alfred.agent.registry import make_tools
class TestPromptBuilderToolsInjection:

View File

@@ -1,7 +1,7 @@
"""Edge case tests for PromptBuilder."""
from agent.prompts import PromptBuilder
from agent.registry import make_tools
from alfred.agent.prompts import PromptBuilder
from alfred.agent.registry import make_tools
class TestPromptBuilderEdgeCases:
@@ -266,7 +266,7 @@ class TestFormatToolsDescriptionEdgeCases:
def test_format_with_complex_parameters(self, memory):
"""Should format complex parameter schemas."""
from agent.registry import Tool
from alfred.agent.registry import Tool
tools = {
"complex_tool": Tool(

View File

@@ -3,9 +3,8 @@
import inspect
import pytest
from agent.prompts import PromptBuilder
from agent.registry import Tool, _create_tool_from_function, make_tools
from alfred.agent.prompts import PromptBuilder
from alfred.agent.registry import Tool, _create_tool_from_function, make_tools
class TestToolSpecFormat:

View File

@@ -1,8 +1,7 @@
"""Edge case tests for tool registry."""
import pytest
from agent.registry import Tool, make_tools
from alfred.agent.registry import Tool, make_tools
class TestToolEdgeCases:

View File

@@ -1,13 +1,13 @@
"""Tests for JSON repositories."""
from domain.movies.entities import Movie
from domain.movies.value_objects import MovieTitle, Quality, ReleaseYear
from domain.shared.value_objects import FilePath, FileSize, ImdbId
from domain.subtitles.entities import Subtitle
from domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset
from domain.tv_shows.entities import TVShow
from domain.tv_shows.value_objects import ShowStatus
from infrastructure.persistence.json import (
from alfred.domain.movies.entities import Movie
from alfred.domain.movies.value_objects import MovieTitle, Quality, ReleaseYear
from alfred.domain.shared.value_objects import FilePath, FileSize, ImdbId
from alfred.domain.subtitles.entities import Subtitle
from alfred.domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset
from alfred.domain.tv_shows.entities import TVShow
from alfred.domain.tv_shows.value_objects import ShowStatus
from alfred.infrastructure.persistence.json import (
JsonMovieRepository,
JsonSubtitleRepository,
JsonTVShowRepository,

View File

@@ -2,14 +2,14 @@
from datetime import datetime
from domain.movies.entities import Movie
from domain.movies.value_objects import MovieTitle, Quality
from domain.shared.value_objects import FilePath, FileSize, ImdbId
from domain.subtitles.entities import Subtitle
from domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset
from domain.tv_shows.entities import TVShow
from domain.tv_shows.value_objects import ShowStatus
from infrastructure.persistence.json import (
from alfred.domain.movies.entities import Movie
from alfred.domain.movies.value_objects import MovieTitle, Quality
from alfred.domain.shared.value_objects import FilePath, FileSize, ImdbId
from alfred.domain.subtitles.entities import Subtitle
from alfred.domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset
from alfred.domain.tv_shows.entities import TVShow
from alfred.domain.tv_shows.value_objects import ShowStatus
from alfred.infrastructure.persistence.json import (
JsonMovieRepository,
JsonSubtitleRepository,
JsonTVShowRepository,

View File

@@ -2,8 +2,8 @@
from unittest.mock import Mock, patch
from agent.tools import api as api_tools
from infrastructure.persistence import get_memory
from alfred.agent.tools import api as api_tools
from alfred.infrastructure.persistence import get_memory
def create_mock_response(status_code, json_data=None, text=None):
@@ -21,7 +21,7 @@ def create_mock_response(status_code, json_data=None, text=None):
class TestFindMediaImdbId:
"""Tests for find_media_imdb_id tool."""
@patch("infrastructure.api.tmdb.client.requests.get")
@patch("alfred.infrastructure.api.tmdb.client.requests.get")
def test_success(self, mock_get, memory):
"""Should return movie info on success."""
@@ -56,7 +56,7 @@ class TestFindMediaImdbId:
# Verify HTTP calls
assert mock_get.call_count == 2
@patch("infrastructure.api.tmdb.client.requests.get")
@patch("alfred.infrastructure.api.tmdb.client.requests.get")
def test_stores_in_stm(self, mock_get, memory):
"""Should store result in STM on success."""
@@ -88,7 +88,7 @@ class TestFindMediaImdbId:
assert entity["title"] == "Inception"
assert mem.stm.current_topic == "searching_media"
@patch("infrastructure.api.tmdb.client.requests.get")
@patch("alfred.infrastructure.api.tmdb.client.requests.get")
def test_not_found(self, mock_get, memory):
"""Should return error when not found."""
mock_get.return_value = create_mock_response(200, json_data={"results": []})
@@ -98,7 +98,7 @@ class TestFindMediaImdbId:
assert result["status"] == "error"
assert result["error"] == "not_found"
@patch("infrastructure.api.tmdb.client.requests.get")
@patch("alfred.infrastructure.api.tmdb.client.requests.get")
def test_does_not_store_on_error(self, mock_get, memory):
"""Should not store in STM on error."""
mock_get.return_value = create_mock_response(200, json_data={"results": []})
@@ -112,7 +112,7 @@ class TestFindMediaImdbId:
class TestFindTorrent:
"""Tests for find_torrent tool."""
@patch("infrastructure.api.knaben.client.requests.post")
@patch("alfred.infrastructure.api.knaben.client.requests.post")
def test_success(self, mock_post, memory):
"""Should return torrents on success."""
mock_post.return_value = create_mock_response(
@@ -146,7 +146,7 @@ class TestFindTorrent:
payload = mock_post.call_args[1]["json"]
assert payload["query"] == "Inception 1080p"
@patch("infrastructure.api.knaben.client.requests.post")
@patch("alfred.infrastructure.api.knaben.client.requests.post")
def test_stores_in_episodic(self, mock_post, memory):
"""Should store results in episodic memory."""
mock_post.return_value = create_mock_response(
@@ -171,7 +171,7 @@ class TestFindTorrent:
assert mem.episodic.last_search_results["query"] == "Inception"
assert mem.stm.current_topic == "selecting_torrent"
@patch("infrastructure.api.knaben.client.requests.post")
@patch("alfred.infrastructure.api.knaben.client.requests.post")
def test_results_have_indexes(self, mock_post, memory):
"""Should add indexes to results."""
mock_post.return_value = create_mock_response(
@@ -211,7 +211,7 @@ class TestFindTorrent:
assert results[1]["index"] == 2
assert results[2]["index"] == 3
@patch("infrastructure.api.knaben.client.requests.post")
@patch("alfred.infrastructure.api.knaben.client.requests.post")
def test_not_found(self, mock_post, memory):
"""Should return error when no torrents found."""
mock_post.return_value = create_mock_response(200, json_data={"hits": []})
@@ -286,7 +286,7 @@ class TestAddTorrentToQbittorrent:
This is acceptable mocking because we're testing the TOOL logic, not the client.
"""
@patch("agent.tools.api.qbittorrent_client")
@patch("alfred.agent.tools.api.qbittorrent_client")
def test_success(self, mock_client, memory):
"""Should add torrent successfully and update memory."""
mock_client.add_torrent.return_value = True
@@ -298,7 +298,7 @@ class TestAddTorrentToQbittorrent:
# Verify client was called correctly
mock_client.add_torrent.assert_called_once_with("magnet:?xt=urn:btih:abc123")
@patch("agent.tools.api.qbittorrent_client")
@patch("alfred.agent.tools.api.qbittorrent_client")
def test_adds_to_active_downloads(self, mock_client, memory_with_search_results):
"""Should add to active downloads on success."""
mock_client.add_torrent.return_value = True
@@ -313,7 +313,7 @@ class TestAddTorrentToQbittorrent:
== "Inception.2010.1080p.BluRay.x264"
)
@patch("agent.tools.api.qbittorrent_client")
@patch("alfred.agent.tools.api.qbittorrent_client")
def test_sets_topic_and_ends_workflow(self, mock_client, memory):
"""Should set topic and end workflow."""
mock_client.add_torrent.return_value = True
@@ -326,10 +326,10 @@ class TestAddTorrentToQbittorrent:
assert mem.stm.current_topic == "downloading"
assert mem.stm.current_workflow is None
@patch("agent.tools.api.qbittorrent_client")
@patch("alfred.agent.tools.api.qbittorrent_client")
def test_error_handling(self, mock_client, memory):
"""Should handle client errors correctly."""
from infrastructure.api.qbittorrent.exceptions import QBittorrentAPIError
from alfred.infrastructure.api.qbittorrent.exceptions import QBittorrentAPIError
mock_client.add_torrent.side_effect = QBittorrentAPIError("Connection failed")
@@ -349,7 +349,7 @@ class TestAddTorrentByIndex:
- Error handling for edge cases
"""
@patch("agent.tools.api.qbittorrent_client")
@patch("alfred.agent.tools.api.qbittorrent_client")
def test_success(self, mock_client, memory_with_search_results):
"""Should get torrent by index and add it."""
mock_client.add_torrent.return_value = True
@@ -362,7 +362,7 @@ class TestAddTorrentByIndex:
# Verify correct magnet was extracted and used
mock_client.add_torrent.assert_called_once_with("magnet:?xt=urn:btih:abc123")
@patch("agent.tools.api.qbittorrent_client")
@patch("alfred.agent.tools.api.qbittorrent_client")
def test_uses_correct_magnet(self, mock_client, memory_with_search_results):
"""Should extract correct magnet from index."""
mock_client.add_torrent.return_value = True

View File

@@ -1,18 +1,16 @@
"""Edge case tests for tools."""
import pytest
from unittest.mock import Mock, patch
import pytest
from agent.tools import api as api_tools
from agent.tools import filesystem as fs_tools
from infrastructure.persistence import get_memory
from alfred.agent.tools import api as api_tools
from alfred.agent.tools import filesystem as fs_tools
from alfred.infrastructure.persistence import get_memory
class TestFindTorrentEdgeCases:
"""Edge case tests for find_torrent."""
@patch("agent.tools.api.SearchTorrentsUseCase")
@patch("alfred.agent.tools.api.SearchTorrentsUseCase")
def test_empty_query(self, mock_use_case_class, memory):
"""Should handle empty query."""
mock_response = Mock()
@@ -28,7 +26,7 @@ class TestFindTorrentEdgeCases:
assert result["status"] == "error"
@patch("agent.tools.api.SearchTorrentsUseCase")
@patch("alfred.agent.tools.api.SearchTorrentsUseCase")
def test_very_long_query(self, mock_use_case_class, memory):
"""Should handle very long query."""
mock_response = Mock()
@@ -47,7 +45,7 @@ class TestFindTorrentEdgeCases:
# Should not crash
assert "status" in result
@patch("agent.tools.api.SearchTorrentsUseCase")
@patch("alfred.agent.tools.api.SearchTorrentsUseCase")
def test_special_characters_in_query(self, mock_use_case_class, memory):
"""Should handle special characters in query."""
mock_response = Mock()
@@ -65,7 +63,7 @@ class TestFindTorrentEdgeCases:
assert "status" in result
@patch("agent.tools.api.SearchTorrentsUseCase")
@patch("alfred.agent.tools.api.SearchTorrentsUseCase")
def test_unicode_query(self, mock_use_case_class, memory):
"""Should handle unicode in query."""
mock_response = Mock()
@@ -82,7 +80,7 @@ class TestFindTorrentEdgeCases:
assert "status" in result
@patch("agent.tools.api.SearchTorrentsUseCase")
@patch("alfred.agent.tools.api.SearchTorrentsUseCase")
def test_results_with_missing_fields(self, mock_use_case_class, memory):
"""Should handle results with missing fields."""
mock_response = Mock()
@@ -104,7 +102,7 @@ class TestFindTorrentEdgeCases:
mem = get_memory()
assert len(mem.episodic.last_search_results["results"]) == 2
@patch("agent.tools.api.SearchTorrentsUseCase")
@patch("alfred.agent.tools.api.SearchTorrentsUseCase")
def test_api_timeout(self, mock_use_case_class, memory):
"""Should handle API timeout."""
mock_use_case = Mock()
@@ -157,7 +155,7 @@ class TestGetTorrentByIndexEdgeCases:
class TestAddTorrentEdgeCases:
"""Edge case tests for add_torrent functions."""
@patch("agent.tools.api.AddTorrentUseCase")
@patch("alfred.agent.tools.api.AddTorrentUseCase")
def test_invalid_magnet_link(self, mock_use_case_class, memory):
"""Should handle invalid magnet link."""
mock_response = Mock()
@@ -173,7 +171,7 @@ class TestAddTorrentEdgeCases:
assert result["status"] == "error"
@patch("agent.tools.api.AddTorrentUseCase")
@patch("alfred.agent.tools.api.AddTorrentUseCase")
def test_empty_magnet_link(self, mock_use_case_class, memory):
"""Should handle empty magnet link."""
mock_response = Mock()
@@ -189,7 +187,7 @@ class TestAddTorrentEdgeCases:
assert result["status"] == "error"
@patch("agent.tools.api.AddTorrentUseCase")
@patch("alfred.agent.tools.api.AddTorrentUseCase")
def test_very_long_magnet_link(self, mock_use_case_class, memory):
"""Should handle very long magnet link."""
mock_response = Mock()
@@ -203,7 +201,7 @@ class TestAddTorrentEdgeCases:
assert "status" in result
@patch("agent.tools.api.AddTorrentUseCase")
@patch("alfred.agent.tools.api.AddTorrentUseCase")
def test_qbittorrent_connection_refused(self, mock_use_case_class, memory):
"""Should handle qBittorrent connection refused."""
mock_use_case = Mock()
@@ -391,7 +389,7 @@ class TestFilesystemEdgeCases:
class TestFindMediaImdbIdEdgeCases:
"""Edge case tests for find_media_imdb_id."""
@patch("agent.tools.api.SearchMovieUseCase")
@patch("alfred.agent.tools.api.SearchMovieUseCase")
def test_movie_with_same_name_different_years(self, mock_use_case_class, memory):
"""Should handle movies with same name."""
mock_response = Mock()
@@ -409,7 +407,7 @@ class TestFindMediaImdbIdEdgeCases:
assert result["status"] == "ok"
@patch("agent.tools.api.SearchMovieUseCase")
@patch("alfred.agent.tools.api.SearchMovieUseCase")
def test_movie_with_special_title(self, mock_use_case_class, memory):
"""Should handle movies with special characters in title."""
mock_response = Mock()
@@ -426,7 +424,7 @@ class TestFindMediaImdbIdEdgeCases:
assert result["status"] == "ok"
@patch("agent.tools.api.SearchMovieUseCase")
@patch("alfred.agent.tools.api.SearchMovieUseCase")
def test_tv_show_vs_movie(self, mock_use_case_class, memory):
"""Should distinguish TV shows from movies."""
mock_response = Mock()

View File

@@ -1,11 +1,9 @@
"""Tests for filesystem tools."""
import pytest
from pathlib import Path
import pytest
from agent.tools import filesystem as fs_tools
from infrastructure.persistence import get_memory
from alfred.agent.tools import filesystem as fs_tools
from alfred.infrastructure.persistence import get_memory
class TestSetPathForFolder: