mirror of
https://github.com/elisiariocouto/leggen.git
synced 2025-12-13 11:22:21 +00:00
Add tests for configurable paths and finalize implementation
Co-authored-by: elisiariocouto <818914+elisiariocouto@users.noreply.github.com>
This commit is contained in:
committed by
Elisiário Couto
parent
e9711339bd
commit
8654471042
@@ -86,23 +86,17 @@ def api_client(fastapi_app):
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_db_path(temp_db_path):
|
def mock_db_path(temp_db_path):
|
||||||
"""Mock the database path to use temporary database for testing."""
|
"""Mock the database path to use temporary database for testing."""
|
||||||
from pathlib import Path
|
from leggen.utils.paths import path_manager
|
||||||
|
|
||||||
# Create the expected directory structure
|
# Set the path manager to use the temporary database
|
||||||
temp_home = temp_db_path.parent
|
original_database_path = path_manager._database_path
|
||||||
config_dir = temp_home / ".config" / "leggen"
|
path_manager.set_database_path(temp_db_path)
|
||||||
config_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
try:
|
||||||
# Create the expected database path
|
yield temp_db_path
|
||||||
expected_db_path = config_dir / "leggen.db"
|
finally:
|
||||||
|
# Restore original path
|
||||||
# Mock Path.home to return our temp directory
|
path_manager._database_path = original_database_path
|
||||||
def mock_home():
|
|
||||||
return temp_home
|
|
||||||
|
|
||||||
# Patch Path.home in the main pathlib module
|
|
||||||
with patch.object(Path, "home", staticmethod(mock_home)):
|
|
||||||
yield expected_db_path
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
|||||||
162
tests/unit/test_configurable_paths.py
Normal file
162
tests/unit/test_configurable_paths.py
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
"""Integration tests for configurable paths."""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import tempfile
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from leggen.utils.paths import path_manager
|
||||||
|
from leggen.database.sqlite import persist_balances, get_balances
|
||||||
|
|
||||||
|
|
||||||
|
class MockContext:
|
||||||
|
"""Mock context for testing."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
class TestConfigurablePaths:
|
||||||
|
"""Test configurable path management."""
|
||||||
|
|
||||||
|
def test_default_paths(self):
|
||||||
|
"""Test that default paths are correctly set."""
|
||||||
|
# Reset path manager
|
||||||
|
original_config = path_manager._config_dir
|
||||||
|
original_db = path_manager._database_path
|
||||||
|
|
||||||
|
try:
|
||||||
|
path_manager._config_dir = None
|
||||||
|
path_manager._database_path = None
|
||||||
|
|
||||||
|
# Test defaults
|
||||||
|
config_dir = path_manager.get_config_dir()
|
||||||
|
db_path = path_manager.get_database_path()
|
||||||
|
|
||||||
|
assert config_dir == Path.home() / ".config" / "leggen"
|
||||||
|
assert db_path == Path.home() / ".config" / "leggen" / "leggen.db"
|
||||||
|
finally:
|
||||||
|
path_manager._config_dir = original_config
|
||||||
|
path_manager._database_path = original_db
|
||||||
|
|
||||||
|
def test_environment_variables(self):
|
||||||
|
"""Test that environment variables override defaults."""
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
test_config_dir = Path(tmpdir) / "test-config"
|
||||||
|
test_db_path = Path(tmpdir) / "test.db"
|
||||||
|
|
||||||
|
with patch.dict(os.environ, {
|
||||||
|
'LEGGEN_CONFIG_DIR': str(test_config_dir),
|
||||||
|
'LEGGEN_DATABASE_PATH': str(test_db_path)
|
||||||
|
}):
|
||||||
|
# Reset path manager to pick up environment variables
|
||||||
|
original_config = path_manager._config_dir
|
||||||
|
original_db = path_manager._database_path
|
||||||
|
|
||||||
|
try:
|
||||||
|
path_manager._config_dir = None
|
||||||
|
path_manager._database_path = None
|
||||||
|
|
||||||
|
config_dir = path_manager.get_config_dir()
|
||||||
|
db_path = path_manager.get_database_path()
|
||||||
|
|
||||||
|
assert config_dir == test_config_dir
|
||||||
|
assert db_path == test_db_path
|
||||||
|
finally:
|
||||||
|
path_manager._config_dir = original_config
|
||||||
|
path_manager._database_path = original_db
|
||||||
|
|
||||||
|
def test_explicit_path_setting(self):
|
||||||
|
"""Test explicitly setting paths."""
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
test_config_dir = Path(tmpdir) / "explicit-config"
|
||||||
|
test_db_path = Path(tmpdir) / "explicit.db"
|
||||||
|
|
||||||
|
# Save original paths
|
||||||
|
original_config = path_manager._config_dir
|
||||||
|
original_db = path_manager._database_path
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Set explicit paths
|
||||||
|
path_manager.set_config_dir(test_config_dir)
|
||||||
|
path_manager.set_database_path(test_db_path)
|
||||||
|
|
||||||
|
assert path_manager.get_config_dir() == test_config_dir
|
||||||
|
assert path_manager.get_database_path() == test_db_path
|
||||||
|
assert path_manager.get_config_file_path() == test_config_dir / "config.toml"
|
||||||
|
assert path_manager.get_auth_file_path() == test_config_dir / "auth.json"
|
||||||
|
finally:
|
||||||
|
# Restore original paths
|
||||||
|
path_manager._config_dir = original_config
|
||||||
|
path_manager._database_path = original_db
|
||||||
|
|
||||||
|
def test_database_operations_with_custom_path(self):
|
||||||
|
"""Test that database operations work with custom paths."""
|
||||||
|
with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as tmp_file:
|
||||||
|
test_db_path = Path(tmp_file.name)
|
||||||
|
|
||||||
|
# Save original database path
|
||||||
|
original_db = path_manager._database_path
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Set custom database path
|
||||||
|
path_manager.set_database_path(test_db_path)
|
||||||
|
|
||||||
|
# Test database operations
|
||||||
|
ctx = MockContext()
|
||||||
|
balance = {
|
||||||
|
"account_id": "test-account",
|
||||||
|
"bank": "TEST_BANK",
|
||||||
|
"status": "active",
|
||||||
|
"iban": "TEST_IBAN",
|
||||||
|
"amount": 1000.0,
|
||||||
|
"currency": "EUR",
|
||||||
|
"type": "available",
|
||||||
|
"timestamp": "2023-01-01T00:00:00",
|
||||||
|
}
|
||||||
|
|
||||||
|
# Persist balance
|
||||||
|
persist_balances(ctx, balance)
|
||||||
|
|
||||||
|
# Retrieve balances
|
||||||
|
balances = get_balances()
|
||||||
|
|
||||||
|
assert len(balances) == 1
|
||||||
|
assert balances[0]["account_id"] == "test-account"
|
||||||
|
assert balances[0]["amount"] == 1000.0
|
||||||
|
|
||||||
|
# Verify database file exists at custom location
|
||||||
|
assert test_db_path.exists()
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Restore original path and cleanup
|
||||||
|
path_manager._database_path = original_db
|
||||||
|
if test_db_path.exists():
|
||||||
|
test_db_path.unlink()
|
||||||
|
|
||||||
|
def test_directory_creation(self):
|
||||||
|
"""Test that directories are created as needed."""
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
test_config_dir = Path(tmpdir) / "new" / "config" / "dir"
|
||||||
|
test_db_path = Path(tmpdir) / "new" / "db" / "dir" / "test.db"
|
||||||
|
|
||||||
|
# Save original paths
|
||||||
|
original_config = path_manager._config_dir
|
||||||
|
original_db = path_manager._database_path
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Set paths to non-existent directories
|
||||||
|
path_manager.set_config_dir(test_config_dir)
|
||||||
|
path_manager.set_database_path(test_db_path)
|
||||||
|
|
||||||
|
# Ensure directories are created
|
||||||
|
path_manager.ensure_config_dir_exists()
|
||||||
|
path_manager.ensure_database_dir_exists()
|
||||||
|
|
||||||
|
assert test_config_dir.exists()
|
||||||
|
assert test_db_path.parent.exists()
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Restore original paths
|
||||||
|
path_manager._config_dir = original_config
|
||||||
|
path_manager._database_path = original_db
|
||||||
@@ -21,14 +21,18 @@ def temp_db_path():
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_home_db_path(temp_db_path):
|
def mock_home_db_path(temp_db_path):
|
||||||
"""Mock the home database path to use temp file."""
|
"""Mock the database path to use temp file."""
|
||||||
config_dir = temp_db_path.parent / ".config" / "leggen"
|
from leggen.utils.paths import path_manager
|
||||||
config_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
db_file = config_dir / "leggen.db"
|
# Set the path manager to use the temporary database
|
||||||
|
original_database_path = path_manager._database_path
|
||||||
with patch("pathlib.Path.home") as mock_home:
|
path_manager.set_database_path(temp_db_path)
|
||||||
mock_home.return_value = temp_db_path.parent
|
|
||||||
yield db_file
|
try:
|
||||||
|
yield temp_db_path
|
||||||
|
finally:
|
||||||
|
# Restore original path
|
||||||
|
path_manager._database_path = original_database_path
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@@ -90,18 +94,14 @@ class TestSQLiteDatabase:
|
|||||||
"""Test persisting transactions to database."""
|
"""Test persisting transactions to database."""
|
||||||
ctx = MockContext()
|
ctx = MockContext()
|
||||||
|
|
||||||
# Mock the database path
|
# Persist transactions
|
||||||
with patch("pathlib.Path.home") as mock_home:
|
new_transactions = sqlite_db.persist_transactions(
|
||||||
mock_home.return_value = mock_home_db_path.parent / ".."
|
ctx, "test-account-123", sample_transactions
|
||||||
|
)
|
||||||
|
|
||||||
# Persist transactions
|
# Should return all transactions as new
|
||||||
new_transactions = sqlite_db.persist_transactions(
|
assert len(new_transactions) == 2
|
||||||
ctx, "test-account-123", sample_transactions
|
assert new_transactions[0]["internalTransactionId"] == "txn-001"
|
||||||
)
|
|
||||||
|
|
||||||
# Should return all transactions as new
|
|
||||||
assert len(new_transactions) == 2
|
|
||||||
assert new_transactions[0]["internalTransactionId"] == "txn-001"
|
|
||||||
|
|
||||||
def test_persist_transactions_duplicates(
|
def test_persist_transactions_duplicates(
|
||||||
self, mock_home_db_path, sample_transactions
|
self, mock_home_db_path, sample_transactions
|
||||||
@@ -109,40 +109,34 @@ class TestSQLiteDatabase:
|
|||||||
"""Test handling duplicate transactions."""
|
"""Test handling duplicate transactions."""
|
||||||
ctx = MockContext()
|
ctx = MockContext()
|
||||||
|
|
||||||
with patch("pathlib.Path.home") as mock_home:
|
# Insert transactions twice
|
||||||
mock_home.return_value = mock_home_db_path.parent / ".."
|
new_transactions_1 = sqlite_db.persist_transactions(
|
||||||
|
ctx, "test-account-123", sample_transactions
|
||||||
|
)
|
||||||
|
new_transactions_2 = sqlite_db.persist_transactions(
|
||||||
|
ctx, "test-account-123", sample_transactions
|
||||||
|
)
|
||||||
|
|
||||||
# Insert transactions twice
|
# First time should return all as new
|
||||||
new_transactions_1 = sqlite_db.persist_transactions(
|
assert len(new_transactions_1) == 2
|
||||||
ctx, "test-account-123", sample_transactions
|
# Second time should also return all (INSERT OR REPLACE behavior with composite key)
|
||||||
)
|
assert len(new_transactions_2) == 2
|
||||||
new_transactions_2 = sqlite_db.persist_transactions(
|
|
||||||
ctx, "test-account-123", sample_transactions
|
|
||||||
)
|
|
||||||
|
|
||||||
# First time should return all as new
|
|
||||||
assert len(new_transactions_1) == 2
|
|
||||||
# Second time should also return all (INSERT OR REPLACE behavior with composite key)
|
|
||||||
assert len(new_transactions_2) == 2
|
|
||||||
|
|
||||||
def test_get_transactions_all(self, mock_home_db_path, sample_transactions):
|
def test_get_transactions_all(self, mock_home_db_path, sample_transactions):
|
||||||
"""Test retrieving all transactions."""
|
"""Test retrieving all transactions."""
|
||||||
ctx = MockContext()
|
ctx = MockContext()
|
||||||
|
|
||||||
with patch("pathlib.Path.home") as mock_home:
|
# Insert test data
|
||||||
mock_home.return_value = mock_home_db_path.parent / ".."
|
sqlite_db.persist_transactions(ctx, "test-account-123", sample_transactions)
|
||||||
|
|
||||||
# Insert test data
|
# Get all transactions
|
||||||
sqlite_db.persist_transactions(ctx, "test-account-123", sample_transactions)
|
transactions = sqlite_db.get_transactions()
|
||||||
|
|
||||||
# Get all transactions
|
assert len(transactions) == 2
|
||||||
transactions = sqlite_db.get_transactions()
|
assert (
|
||||||
|
transactions[0]["internalTransactionId"] == "txn-002"
|
||||||
assert len(transactions) == 2
|
) # Ordered by date DESC
|
||||||
assert (
|
assert transactions[1]["internalTransactionId"] == "txn-001"
|
||||||
transactions[0]["internalTransactionId"] == "txn-002"
|
|
||||||
) # Ordered by date DESC
|
|
||||||
assert transactions[1]["internalTransactionId"] == "txn-001"
|
|
||||||
|
|
||||||
def test_get_transactions_filtered_by_account(
|
def test_get_transactions_filtered_by_account(
|
||||||
self, mock_home_db_path, sample_transactions
|
self, mock_home_db_path, sample_transactions
|
||||||
|
|||||||
364
tests/unit/test_sqlite_database.py.bak
Normal file
364
tests/unit/test_sqlite_database.py.bak
Normal file
@@ -0,0 +1,364 @@
|
|||||||
|
"""Tests for SQLite database functions."""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import tempfile
|
||||||
|
from pathlib import Path
|
||||||
|
from unittest.mock import patch
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
import leggen.database.sqlite as sqlite_db
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def temp_db_path():
|
||||||
|
"""Create a temporary database file for testing."""
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
db_path = Path(tmpdir) / f"test_{uuid.uuid4().hex}.db"
|
||||||
|
yield db_path
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_home_db_path(temp_db_path):
|
||||||
|
"""Mock the database path to use temp file."""
|
||||||
|
from leggen.utils.paths import path_manager
|
||||||
|
|
||||||
|
# Set the path manager to use the temporary database
|
||||||
|
original_database_path = path_manager._database_path
|
||||||
|
path_manager.set_database_path(temp_db_path)
|
||||||
|
|
||||||
|
try:
|
||||||
|
yield temp_db_path
|
||||||
|
finally:
|
||||||
|
# Restore original path
|
||||||
|
path_manager._database_path = original_database_path
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def sample_transactions():
|
||||||
|
"""Sample transaction data for testing."""
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"transactionId": "bank-txn-001", # NEW: stable bank-provided ID
|
||||||
|
"internalTransactionId": "txn-001",
|
||||||
|
"institutionId": "REVOLUT_REVOLT21",
|
||||||
|
"iban": "LT313250081177977789",
|
||||||
|
"transactionDate": datetime(2025, 9, 1, 9, 30),
|
||||||
|
"description": "Coffee Shop Payment",
|
||||||
|
"transactionValue": -10.50,
|
||||||
|
"transactionCurrency": "EUR",
|
||||||
|
"transactionStatus": "booked",
|
||||||
|
"accountId": "test-account-123",
|
||||||
|
"rawTransaction": {"transactionId": "bank-txn-001", "some": "data"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"transactionId": "bank-txn-002", # NEW: stable bank-provided ID
|
||||||
|
"internalTransactionId": "txn-002",
|
||||||
|
"institutionId": "REVOLUT_REVOLT21",
|
||||||
|
"iban": "LT313250081177977789",
|
||||||
|
"transactionDate": datetime(2025, 9, 2, 14, 15),
|
||||||
|
"description": "Grocery Store",
|
||||||
|
"transactionValue": -45.30,
|
||||||
|
"transactionCurrency": "EUR",
|
||||||
|
"transactionStatus": "booked",
|
||||||
|
"accountId": "test-account-123",
|
||||||
|
"rawTransaction": {"transactionId": "bank-txn-002", "other": "data"},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def sample_balance():
|
||||||
|
"""Sample balance data for testing."""
|
||||||
|
return {
|
||||||
|
"account_id": "test-account-123",
|
||||||
|
"bank": "REVOLUT_REVOLT21",
|
||||||
|
"status": "active",
|
||||||
|
"iban": "LT313250081177977789",
|
||||||
|
"amount": 1000.00,
|
||||||
|
"currency": "EUR",
|
||||||
|
"type": "interimAvailable",
|
||||||
|
"timestamp": datetime.now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class MockContext:
|
||||||
|
"""Mock context for testing."""
|
||||||
|
|
||||||
|
|
||||||
|
class TestSQLiteDatabase:
|
||||||
|
"""Test SQLite database operations."""
|
||||||
|
|
||||||
|
def test_persist_transactions(self, mock_home_db_path, sample_transactions):
|
||||||
|
"""Test persisting transactions to database."""
|
||||||
|
ctx = MockContext()
|
||||||
|
|
||||||
|
# Persist transactions
|
||||||
|
new_transactions = sqlite_db.persist_transactions(
|
||||||
|
ctx, "test-account-123", sample_transactions
|
||||||
|
)
|
||||||
|
|
||||||
|
# Should return all transactions as new
|
||||||
|
assert len(new_transactions) == 2
|
||||||
|
assert new_transactions[0]["internalTransactionId"] == "txn-001"
|
||||||
|
|
||||||
|
def test_persist_transactions_duplicates(
|
||||||
|
self, mock_home_db_path, sample_transactions
|
||||||
|
):
|
||||||
|
"""Test handling duplicate transactions."""
|
||||||
|
ctx = MockContext()
|
||||||
|
|
||||||
|
# Insert transactions twice
|
||||||
|
new_transactions_1 = sqlite_db.persist_transactions(
|
||||||
|
ctx, "test-account-123", sample_transactions
|
||||||
|
)
|
||||||
|
new_transactions_2 = sqlite_db.persist_transactions(
|
||||||
|
ctx, "test-account-123", sample_transactions
|
||||||
|
)
|
||||||
|
|
||||||
|
# First time should return all as new
|
||||||
|
assert len(new_transactions_1) == 2
|
||||||
|
# Second time should also return all (INSERT OR REPLACE behavior with composite key)
|
||||||
|
assert len(new_transactions_2) == 2
|
||||||
|
|
||||||
|
def test_get_transactions_all(self, mock_home_db_path, sample_transactions):
|
||||||
|
"""Test retrieving all transactions."""
|
||||||
|
ctx = MockContext()
|
||||||
|
|
||||||
|
# Insert test data
|
||||||
|
sqlite_db.persist_transactions(ctx, "test-account-123", sample_transactions)
|
||||||
|
|
||||||
|
# Get all transactions
|
||||||
|
transactions = sqlite_db.get_transactions()
|
||||||
|
|
||||||
|
assert len(transactions) == 2
|
||||||
|
assert (
|
||||||
|
transactions[0]["internalTransactionId"] == "txn-002"
|
||||||
|
) # Ordered by date DESC
|
||||||
|
assert transactions[1]["internalTransactionId"] == "txn-001"
|
||||||
|
|
||||||
|
def test_get_transactions_filtered_by_account(
|
||||||
|
self, mock_home_db_path, sample_transactions
|
||||||
|
):
|
||||||
|
"""Test filtering transactions by account ID."""
|
||||||
|
ctx = MockContext()
|
||||||
|
|
||||||
|
# Add transaction for different account
|
||||||
|
other_account_transaction = sample_transactions[0].copy()
|
||||||
|
other_account_transaction["internalTransactionId"] = "txn-003"
|
||||||
|
other_account_transaction["accountId"] = "other-account"
|
||||||
|
|
||||||
|
all_transactions = sample_transactions + [other_account_transaction]
|
||||||
|
|
||||||
|
with patch("pathlib.Path.home") as mock_home:
|
||||||
|
mock_home.return_value = mock_home_db_path.parent / ".."
|
||||||
|
|
||||||
|
sqlite_db.persist_transactions(ctx, "test-account-123", all_transactions)
|
||||||
|
|
||||||
|
# Filter by account
|
||||||
|
transactions = sqlite_db.get_transactions(account_id="test-account-123")
|
||||||
|
|
||||||
|
assert len(transactions) == 2
|
||||||
|
for txn in transactions:
|
||||||
|
assert txn["accountId"] == "test-account-123"
|
||||||
|
|
||||||
|
def test_get_transactions_with_pagination(
|
||||||
|
self, mock_home_db_path, sample_transactions
|
||||||
|
):
|
||||||
|
"""Test transaction pagination."""
|
||||||
|
ctx = MockContext()
|
||||||
|
|
||||||
|
with patch("pathlib.Path.home") as mock_home:
|
||||||
|
mock_home.return_value = mock_home_db_path.parent / ".."
|
||||||
|
|
||||||
|
sqlite_db.persist_transactions(ctx, "test-account-123", sample_transactions)
|
||||||
|
|
||||||
|
# Get first page
|
||||||
|
transactions_page1 = sqlite_db.get_transactions(limit=1, offset=0)
|
||||||
|
assert len(transactions_page1) == 1
|
||||||
|
|
||||||
|
# Get second page
|
||||||
|
transactions_page2 = sqlite_db.get_transactions(limit=1, offset=1)
|
||||||
|
assert len(transactions_page2) == 1
|
||||||
|
|
||||||
|
# Should be different transactions
|
||||||
|
assert (
|
||||||
|
transactions_page1[0]["internalTransactionId"]
|
||||||
|
!= transactions_page2[0]["internalTransactionId"]
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_get_transactions_with_amount_filter(
|
||||||
|
self, mock_home_db_path, sample_transactions
|
||||||
|
):
|
||||||
|
"""Test filtering transactions by amount."""
|
||||||
|
ctx = MockContext()
|
||||||
|
|
||||||
|
with patch("pathlib.Path.home") as mock_home:
|
||||||
|
mock_home.return_value = mock_home_db_path.parent / ".."
|
||||||
|
|
||||||
|
sqlite_db.persist_transactions(ctx, "test-account-123", sample_transactions)
|
||||||
|
|
||||||
|
# Filter by minimum amount (should exclude coffee shop payment)
|
||||||
|
transactions = sqlite_db.get_transactions(min_amount=-20.0)
|
||||||
|
assert len(transactions) == 1
|
||||||
|
assert transactions[0]["transactionValue"] == -10.50
|
||||||
|
|
||||||
|
def test_get_transactions_with_search(self, mock_home_db_path, sample_transactions):
|
||||||
|
"""Test searching transactions by description."""
|
||||||
|
ctx = MockContext()
|
||||||
|
|
||||||
|
with patch("pathlib.Path.home") as mock_home:
|
||||||
|
mock_home.return_value = mock_home_db_path.parent / ".."
|
||||||
|
|
||||||
|
sqlite_db.persist_transactions(ctx, "test-account-123", sample_transactions)
|
||||||
|
|
||||||
|
# Search for "Coffee"
|
||||||
|
transactions = sqlite_db.get_transactions(search="Coffee")
|
||||||
|
assert len(transactions) == 1
|
||||||
|
assert "Coffee" in transactions[0]["description"]
|
||||||
|
|
||||||
|
def test_get_transactions_empty_database(self, mock_home_db_path):
|
||||||
|
"""Test getting transactions from empty database."""
|
||||||
|
with patch("pathlib.Path.home") as mock_home:
|
||||||
|
mock_home.return_value = mock_home_db_path.parent / ".."
|
||||||
|
|
||||||
|
transactions = sqlite_db.get_transactions()
|
||||||
|
assert transactions == []
|
||||||
|
|
||||||
|
def test_get_transactions_nonexistent_database(self):
|
||||||
|
"""Test getting transactions when database doesn't exist."""
|
||||||
|
with patch("pathlib.Path.home") as mock_home:
|
||||||
|
mock_home.return_value = Path("/nonexistent")
|
||||||
|
|
||||||
|
transactions = sqlite_db.get_transactions()
|
||||||
|
assert transactions == []
|
||||||
|
|
||||||
|
def test_persist_balances(self, mock_home_db_path, sample_balance):
|
||||||
|
"""Test persisting balance data."""
|
||||||
|
ctx = MockContext()
|
||||||
|
|
||||||
|
with patch("pathlib.Path.home") as mock_home:
|
||||||
|
mock_home.return_value = mock_home_db_path.parent / ".."
|
||||||
|
|
||||||
|
result = sqlite_db.persist_balances(ctx, sample_balance)
|
||||||
|
|
||||||
|
# Should return the balance data
|
||||||
|
assert result["account_id"] == "test-account-123"
|
||||||
|
|
||||||
|
def test_get_balances(self, mock_home_db_path, sample_balance):
|
||||||
|
"""Test retrieving balances."""
|
||||||
|
ctx = MockContext()
|
||||||
|
|
||||||
|
with patch("pathlib.Path.home") as mock_home:
|
||||||
|
mock_home.return_value = mock_home_db_path.parent / ".."
|
||||||
|
|
||||||
|
# Insert test balance
|
||||||
|
sqlite_db.persist_balances(ctx, sample_balance)
|
||||||
|
|
||||||
|
# Get balances
|
||||||
|
balances = sqlite_db.get_balances()
|
||||||
|
|
||||||
|
assert len(balances) == 1
|
||||||
|
assert balances[0]["account_id"] == "test-account-123"
|
||||||
|
assert balances[0]["amount"] == 1000.00
|
||||||
|
|
||||||
|
def test_get_balances_filtered_by_account(self, mock_home_db_path, sample_balance):
|
||||||
|
"""Test filtering balances by account ID."""
|
||||||
|
ctx = MockContext()
|
||||||
|
|
||||||
|
# Create balance for different account
|
||||||
|
other_balance = sample_balance.copy()
|
||||||
|
other_balance["account_id"] = "other-account"
|
||||||
|
|
||||||
|
with patch("pathlib.Path.home") as mock_home:
|
||||||
|
mock_home.return_value = mock_home_db_path.parent / ".."
|
||||||
|
|
||||||
|
sqlite_db.persist_balances(ctx, sample_balance)
|
||||||
|
sqlite_db.persist_balances(ctx, other_balance)
|
||||||
|
|
||||||
|
# Filter by account
|
||||||
|
balances = sqlite_db.get_balances(account_id="test-account-123")
|
||||||
|
|
||||||
|
assert len(balances) == 1
|
||||||
|
assert balances[0]["account_id"] == "test-account-123"
|
||||||
|
|
||||||
|
def test_get_account_summary(self, mock_home_db_path, sample_transactions):
|
||||||
|
"""Test getting account summary from transactions."""
|
||||||
|
ctx = MockContext()
|
||||||
|
|
||||||
|
with patch("pathlib.Path.home") as mock_home:
|
||||||
|
mock_home.return_value = mock_home_db_path.parent / ".."
|
||||||
|
|
||||||
|
sqlite_db.persist_transactions(ctx, "test-account-123", sample_transactions)
|
||||||
|
|
||||||
|
summary = sqlite_db.get_account_summary("test-account-123")
|
||||||
|
|
||||||
|
assert summary is not None
|
||||||
|
assert summary["accountId"] == "test-account-123"
|
||||||
|
assert summary["institutionId"] == "REVOLUT_REVOLT21"
|
||||||
|
assert summary["iban"] == "LT313250081177977789"
|
||||||
|
|
||||||
|
def test_get_account_summary_nonexistent(self, mock_home_db_path):
|
||||||
|
"""Test getting summary for nonexistent account."""
|
||||||
|
with patch("pathlib.Path.home") as mock_home:
|
||||||
|
mock_home.return_value = mock_home_db_path.parent / ".."
|
||||||
|
|
||||||
|
summary = sqlite_db.get_account_summary("nonexistent")
|
||||||
|
assert summary is None
|
||||||
|
|
||||||
|
def test_get_transaction_count(self, mock_home_db_path, sample_transactions):
|
||||||
|
"""Test getting transaction count."""
|
||||||
|
ctx = MockContext()
|
||||||
|
|
||||||
|
with patch("pathlib.Path.home") as mock_home:
|
||||||
|
mock_home.return_value = mock_home_db_path.parent / ".."
|
||||||
|
|
||||||
|
sqlite_db.persist_transactions(ctx, "test-account-123", sample_transactions)
|
||||||
|
|
||||||
|
# Get total count
|
||||||
|
count = sqlite_db.get_transaction_count()
|
||||||
|
assert count == 2
|
||||||
|
|
||||||
|
# Get count for specific account
|
||||||
|
count_filtered = sqlite_db.get_transaction_count(
|
||||||
|
account_id="test-account-123"
|
||||||
|
)
|
||||||
|
assert count_filtered == 2
|
||||||
|
|
||||||
|
# Get count for nonexistent account
|
||||||
|
count_none = sqlite_db.get_transaction_count(account_id="nonexistent")
|
||||||
|
assert count_none == 0
|
||||||
|
|
||||||
|
def test_get_transaction_count_with_filters(
|
||||||
|
self, mock_home_db_path, sample_transactions
|
||||||
|
):
|
||||||
|
"""Test getting transaction count with filters."""
|
||||||
|
ctx = MockContext()
|
||||||
|
|
||||||
|
with patch("pathlib.Path.home") as mock_home:
|
||||||
|
mock_home.return_value = mock_home_db_path.parent / ".."
|
||||||
|
|
||||||
|
sqlite_db.persist_transactions(ctx, "test-account-123", sample_transactions)
|
||||||
|
|
||||||
|
# Filter by search
|
||||||
|
count = sqlite_db.get_transaction_count(search="Coffee")
|
||||||
|
assert count == 1
|
||||||
|
|
||||||
|
# Filter by amount
|
||||||
|
count = sqlite_db.get_transaction_count(min_amount=-20.0)
|
||||||
|
assert count == 1
|
||||||
|
|
||||||
|
def test_database_indexes_created(self, mock_home_db_path, sample_transactions):
|
||||||
|
"""Test that database indexes are created properly."""
|
||||||
|
ctx = MockContext()
|
||||||
|
|
||||||
|
with patch("pathlib.Path.home") as mock_home:
|
||||||
|
mock_home.return_value = mock_home_db_path.parent / ".."
|
||||||
|
|
||||||
|
# Persist transactions to create tables and indexes
|
||||||
|
sqlite_db.persist_transactions(ctx, "test-account-123", sample_transactions)
|
||||||
|
|
||||||
|
# Get transactions to ensure we can query the table (indexes working)
|
||||||
|
transactions = sqlite_db.get_transactions(account_id="test-account-123")
|
||||||
|
assert len(transactions) == 2
|
||||||
Reference in New Issue
Block a user