Initial commit.
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import asyncio
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
import tempfile
|
||||
|
||||
from pyr.core.config import PyrConfig
|
||||
from pyr.core.app import PyrApp
|
||||
from pyr.ai.client import BaseAIClient
|
||||
from pyr.storage.database import DatabaseManager
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def temp_dir():
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
yield Path(td)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_config(temp_dir):
|
||||
return PyrConfig(
|
||||
provider="openai",
|
||||
model="gpt-3.5-turbo",
|
||||
api_key="test-key",
|
||||
base_url="https://api.openai.com",
|
||||
db_path=str(temp_dir / "test.db"),
|
||||
cache_dir=str(temp_dir / "cache"),
|
||||
verbose=True,
|
||||
syntax_highlight=True,
|
||||
use_tools=True,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_ai_client():
|
||||
client = AsyncMock(spec=BaseAIClient)
|
||||
client.chat = AsyncMock(return_value="Test response")
|
||||
client.chat_with_tools = AsyncMock(return_value=MagicMock(content="Tool response"))
|
||||
client.close = AsyncMock()
|
||||
client.add_system_message = AsyncMock()
|
||||
client.add_user_message = AsyncMock()
|
||||
client.add_assistant_message = AsyncMock()
|
||||
return client
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def test_app(test_config, mock_ai_client):
|
||||
app = PyrApp(test_config)
|
||||
app.ai_client = mock_ai_client
|
||||
|
||||
await app.startup()
|
||||
yield app
|
||||
await app.shutdown()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def test_db(temp_dir):
|
||||
db_path = temp_dir / "test.db"
|
||||
db = DatabaseManager(str(db_path))
|
||||
await db.initialize()
|
||||
yield db
|
||||
await db.close()
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def event_loop():
|
||||
loop = asyncio.new_event_loop()
|
||||
yield loop
|
||||
loop.close()
|
||||
@@ -0,0 +1,50 @@
|
||||
import pytest
|
||||
import os
|
||||
from pyr.core.config import PyrConfig, AIProvider
|
||||
|
||||
|
||||
def test_config_creation():
|
||||
config = PyrConfig()
|
||||
assert config.provider == AIProvider.OPENAI
|
||||
assert config.model == "gpt-4o-mini"
|
||||
assert config.verbose is True
|
||||
|
||||
|
||||
def test_config_with_overrides():
|
||||
config = PyrConfig(
|
||||
provider=AIProvider.ANTHROPIC,
|
||||
model="claude-3-5-haiku-20241022",
|
||||
temperature=0.5
|
||||
)
|
||||
assert config.provider == AIProvider.ANTHROPIC
|
||||
assert config.model == "claude-3-5-haiku-20241022"
|
||||
assert config.temperature == 0.5
|
||||
|
||||
|
||||
def test_config_urls():
|
||||
config = PyrConfig(provider=AIProvider.OPENAI)
|
||||
assert "openai.com" in config.get_completions_url()
|
||||
assert "openai.com" in config.get_models_url()
|
||||
|
||||
|
||||
def test_config_headers():
|
||||
config = PyrConfig(api_key="test-key", provider=AIProvider.OPENAI)
|
||||
headers = config.get_auth_headers()
|
||||
assert "Authorization" in headers
|
||||
assert headers["Authorization"] == "Bearer test-key"
|
||||
|
||||
|
||||
def test_anthropic_headers():
|
||||
config = PyrConfig(api_key="test-key", provider=AIProvider.ANTHROPIC)
|
||||
headers = config.get_auth_headers()
|
||||
assert "x-api-key" in headers
|
||||
assert headers["x-api-key"] == "test-key"
|
||||
|
||||
|
||||
def test_env_var_override(monkeypatch):
|
||||
monkeypatch.setenv("R_MODEL", "test-model")
|
||||
monkeypatch.setenv("R_PROVIDER", "anthropic")
|
||||
|
||||
config = PyrConfig()
|
||||
assert config.model == "test-model"
|
||||
assert config.provider == AIProvider.ANTHROPIC
|
||||
@@ -0,0 +1,77 @@
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
|
||||
from pyr.tools.file_ops import ReadFileTool, WriteFileTool, DirectoryGlobTool, MkdirTool
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_write_and_read_file(temp_dir):
|
||||
write_tool = WriteFileTool()
|
||||
read_tool = ReadFileTool()
|
||||
|
||||
test_file = temp_dir / "test.txt"
|
||||
test_content = "Hello, PYR!"
|
||||
|
||||
result = await write_tool.execute(str(test_file), test_content)
|
||||
assert "successfully" in result.lower()
|
||||
|
||||
result = await read_tool.execute(str(test_file))
|
||||
assert test_content in result
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_write_file_append(temp_dir):
|
||||
write_tool = WriteFileTool()
|
||||
read_tool = ReadFileTool()
|
||||
|
||||
test_file = temp_dir / "append_test.txt"
|
||||
|
||||
await write_tool.execute(str(test_file), "Line 1\n")
|
||||
await write_tool.execute(str(test_file), "Line 2\n", append=True)
|
||||
|
||||
result = await read_tool.execute(str(test_file))
|
||||
assert "Line 1" in result
|
||||
assert "Line 2" in result
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_directory_glob(temp_dir):
|
||||
glob_tool = DirectoryGlobTool()
|
||||
|
||||
(temp_dir / "test1.txt").write_text("content1")
|
||||
(temp_dir / "test2.txt").write_text("content2")
|
||||
(temp_dir / "other.log").write_text("log content")
|
||||
|
||||
result = await glob_tool.execute(f"{temp_dir}/*.txt")
|
||||
assert "test1.txt" in result
|
||||
assert "test2.txt" in result
|
||||
assert "other.log" not in result
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mkdir_tool(temp_dir):
|
||||
mkdir_tool = MkdirTool()
|
||||
|
||||
new_dir = temp_dir / "new_directory" / "nested"
|
||||
|
||||
result = await mkdir_tool.execute(str(new_dir))
|
||||
assert "created" in result.lower()
|
||||
assert new_dir.exists()
|
||||
assert new_dir.is_dir()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_read_nonexistent_file():
|
||||
read_tool = ReadFileTool()
|
||||
|
||||
result = await read_tool.execute("/nonexistent/file.txt")
|
||||
assert "error" in result.lower()
|
||||
|
||||
|
||||
def test_tool_definitions():
|
||||
read_tool = ReadFileTool()
|
||||
definition = read_tool.get_definition()
|
||||
|
||||
assert definition.function["name"] == "read_file"
|
||||
assert "path" in definition.function["parameters"]["properties"]
|
||||
assert "path" in definition.function["parameters"]["required"]
|
||||
Reference in New Issue
Block a user