from pathlib import Path from typing import Any, Sequence, Type import pytest from mocks import banks, categories, transactions from mocks.client import MockClient from pfbudget.common.types import ExportFormat from pfbudget.core.command import ( BackupCommand, ExportCommand, ImportBackupCommand, ImportCommand, ImportFailedError, ) from pfbudget.db.client import Client from pfbudget.db.model import ( Bank, BankTransaction, Base, Category, CategoryGroup, MoneyTransaction, Note, SplitTransaction, Tag, Transaction, TransactionCategory, TransactionTag, ) @pytest.fixture def client() -> Client: return MockClient() params = [ (transactions.simple, Transaction), (transactions.simple_transformed, Transaction), (transactions.bank, Transaction), (transactions.bank, BankTransaction), (transactions.money, Transaction), (transactions.money, MoneyTransaction), (transactions.split, SplitTransaction), ([banks.checking, banks.cc], Bank), ([categories.category_null, categories.category1, categories.category2], Category), ( [ categories.categorygroup1, categories.category_null, categories.category1, categories.category2, ], CategoryGroup, ), ([categories.tag_1], Tag), ] not_serializable = [ (transactions.simple_transformed, TransactionCategory), (transactions.tagged, TransactionTag), (transactions.noted, Note), ] class TestBackup: @pytest.mark.parametrize("input, what", params) def test_import(self, tmp_path: Path, input: Sequence[Any], what: Type[Any]): file = tmp_path / "test.json" client = MockClient() client.insert(input) originals = client.select(what) assert originals command = ExportCommand(client, what, file, ExportFormat.JSON) command.execute() other = MockClient() command = ImportCommand(other, what, file, ExportFormat.JSON) command.execute() imported = other.select(what) assert originals == imported command = ExportCommand(client, what, file, ExportFormat.pickle) with pytest.raises(AttributeError): command.execute() command = ImportCommand(other, what, file, ExportFormat.pickle) with pytest.raises(AttributeError): command.execute() @pytest.mark.parametrize("input, what", not_serializable) def test_try_backup_not_serializable( self, tmp_path: Path, input: Sequence[Any], what: Type[Any] ): file = tmp_path / "test.json" client = MockClient() client.insert(input) originals = client.select(what) assert originals command = ExportCommand(client, what, file, ExportFormat.JSON) with pytest.raises(AttributeError): command.execute() other = MockClient() command = ImportCommand(other, what, file, ExportFormat.JSON) with pytest.raises(ImportFailedError): command.execute() imported = other.select(what) assert not imported def test_full_backup(self, tmp_path: Path): file = tmp_path / "test.json" client = MockClient() client.insert([e for t in params for e in t[0]]) command = BackupCommand(client, file, ExportFormat.JSON) command.execute() other = MockClient() command = ImportBackupCommand(other, file, ExportFormat.JSON) command.execute() def subclasses(cls: Type[Any]) -> set[Type[Any]]: return set(cls.__subclasses__()) | { s for c in cls.__subclasses__() for s in subclasses(c) } for t in [cls for cls in subclasses(Base)]: originals = client.select(t) imported = other.select(t) assert originals == imported, f"{t}"