The new command ImportCommand takes a Serializable type, from which it can call the deserialize method to generate a DB ORM type. The Serializable interface also declares the serialize method. (De)serialization moved to the ORM types, due to the inability to properly use overloading. Possible improvement for the future is to merge serialization information on JSONDecoder/Encoder classes. Adds a MockClient with the in-memory SQLite DB which can be used by tests. Most types export/import functionally tested using two DBs and comparing entries.
96 lines
2.7 KiB
Python
96 lines
2.7 KiB
Python
from collections.abc import Sequence
|
|
import json
|
|
from pathlib import Path
|
|
import pickle
|
|
import pytest
|
|
from typing import Any, cast
|
|
|
|
import mocks.transactions
|
|
|
|
from pfbudget.common.types import ExportFormat
|
|
from pfbudget.core.command import ExportCommand, ImportCommand
|
|
from pfbudget.db.client import Client
|
|
from pfbudget.db.model import Transaction
|
|
|
|
|
|
class FakeClient(Client):
|
|
def __init__(self):
|
|
self._transactions = mocks.transactions.simple
|
|
|
|
def select(self, what: Any, *_) -> Sequence[Any]:
|
|
if what == Transaction:
|
|
return self.transactions
|
|
return []
|
|
|
|
def insert(self, *_):
|
|
pass
|
|
|
|
def update(self, *_):
|
|
pass
|
|
|
|
def delete(self, *_):
|
|
pass
|
|
|
|
@property
|
|
def transactions(self):
|
|
return self._transactions
|
|
|
|
@transactions.setter
|
|
def transactions(self, value: Sequence[Transaction]):
|
|
self._transactions = value
|
|
|
|
|
|
@pytest.fixture
|
|
def client() -> Client:
|
|
return FakeClient()
|
|
|
|
|
|
class TestCommand:
|
|
def test_export_json(self, tmp_path: Path, client: Client):
|
|
client = FakeClient()
|
|
file = tmp_path / "test.json"
|
|
command = ExportCommand(client, Transaction, file, ExportFormat.JSON)
|
|
command.execute()
|
|
|
|
with open(file, newline="") as f:
|
|
result = json.load(f)
|
|
assert result == [t.serialize() for t in mocks.transactions.simple]
|
|
|
|
cast(FakeClient, client).transactions = mocks.transactions.simple_transformed
|
|
command.execute()
|
|
|
|
with open(file, newline="") as f:
|
|
result = json.load(f)
|
|
assert result == [
|
|
t.serialize() for t in mocks.transactions.simple_transformed
|
|
]
|
|
|
|
def test_export_pickle(self, tmp_path: Path, client: Client):
|
|
file = tmp_path / "test.pickle"
|
|
command = ExportCommand(client, Transaction, file, ExportFormat.pickle)
|
|
command.execute()
|
|
|
|
with open(file, "rb") as f:
|
|
result = pickle.load(f)
|
|
assert result == mocks.transactions.simple
|
|
|
|
cast(FakeClient, client).transactions = mocks.transactions.simple_transformed
|
|
command.execute()
|
|
|
|
with open(file, "rb") as f:
|
|
result = pickle.load(f)
|
|
assert result == mocks.transactions.simple_transformed
|
|
|
|
def test_import(self, tmp_path: Path, client: Client):
|
|
file = tmp_path / "test"
|
|
for format in list(ExportFormat):
|
|
command = ExportCommand(client, Transaction, file, format)
|
|
command.execute()
|
|
|
|
command = ImportCommand(client, Transaction, file, format)
|
|
command.execute()
|
|
|
|
transactions = cast(FakeClient, client).transactions
|
|
assert len(transactions) > 0
|
|
assert transactions == client.select(Transaction)
|