aboutsummaryrefslogtreecommitdiffstats
path: root/tests/unit/test_resolver.py
blob: 8c93a84cb0f41121778822bb97afa783f26f5ef9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import unittest
from unittest.mock import MagicMock
from firefly_cli.resolver import Resolver
from firefly_cli.errors import ResolutionError

def client_returning(items):
    c = MagicMock()
    c.request.return_value = {
        "data": [
            {"id": i["id"], "type": "accounts", "attributes": i["attrs"]}
            for i in items
        ]
    }
    return c

class TestResolver(unittest.TestCase):
    def test_resolves_unique_account_name(self):
        c = client_returning([
            {"id": "3", "attrs": {"name": "Checking", "type": "asset"}},
            {"id": "4", "attrs": {"name": "Savings", "type": "asset"}},
        ])
        r = Resolver(c)
        acc = r.account("checking")  # case-insensitive
        self.assertEqual(acc["id"], "3")
        self.assertEqual(acc["type"], "asset")

    def test_no_match_raises_with_candidates(self):
        c = client_returning([{"id": "3", "attrs": {"name": "Checking", "type": "asset"}}])
        r = Resolver(c)
        with self.assertRaises(ResolutionError) as ctx:
            r.account("Nope")
        self.assertIn("Checking", str(ctx.exception))

    def test_ambiguous_match_raises(self):
        c = client_returning([
            {"id": "3", "attrs": {"name": "Cash", "type": "asset"}},
            {"id": "9", "attrs": {"name": "Cash", "type": "asset"}},
        ])
        r = Resolver(c)
        with self.assertRaises(ResolutionError) as ctx:
            r.account("Cash")
        self.assertIn("3", str(ctx.exception))
        self.assertIn("9", str(ctx.exception))

    def test_account_by_id_fetches_single(self):
        c = MagicMock()
        c.request.return_value = {"data": {
            "id": "129", "type": "accounts",
            "attributes": {"name": "Nexi", "type": "revenue"}}}
        r = Resolver(c)
        acc = r.account_by_id("129")
        self.assertEqual(acc, {"id": "129", "name": "Nexi", "type": "revenue"})
        c.request.assert_called_once_with("GET", "/api/v1/accounts/129")


def _budget_list_resp(budgets):
    return {"data": [{"id": b["id"], "attributes": {"name": b["name"]}}
                     for b in budgets]}


class TestResolverBudget(unittest.TestCase):
    def test_budget_by_name(self):
        client = MagicMock()
        client.request.return_value = _budget_list_resp(
            [{"id": "3", "name": "Groceries"}, {"id": "4", "name": "Rent"}])
        r = Resolver(client)
        self.assertEqual(r.budget("Groceries")["id"], "3")

    def test_budget_missing_raises_with_candidates(self):
        client = MagicMock()
        client.request.return_value = _budget_list_resp([{"id": "3", "name": "Rent"}])
        r = Resolver(client)
        with self.assertRaises(ResolutionError) as cm:
            r.budget("Nope")
        self.assertIn("Rent", str(cm.exception))

    def test_budget_numeric_ref_goes_by_id(self):
        client = MagicMock()
        client.request.return_value = {
            "data": {"id": "7", "attributes": {"name": "Fun"}}}
        r = Resolver(client)
        got = r.budget("7")
        self.assertEqual(got["id"], "7")
        self.assertEqual(got["name"], "Fun")
        # Must hit the show endpoint, not list.
        client.request.assert_called_with("GET", "/api/v1/budgets/7")