bttests.py
author Fabien Ninoles <fabien@tzone.org>
Sun, 03 Jan 2016 20:24:28 -0500
changeset 2 64f48a8c758c
parent 0 811cd790a493
permissions -rw-r--r--
New portfolio report compatible with the merge.

from budgettracker import Budget, Transaction, Decimal

class Expect:
    def __init__(self, *cmds, verbose = False):
        self._cmds = cmds
        self._index = 0
        self.verbose = verbose
    def __call__(self, prompt):
        assert(self._index < len(self._cmds))
        idx = self._index
        self._index += 1
        if self.verbose:
            print("{:<20} => {}".format(prompt, self._cmds[idx]))
        return self._cmds[idx]

class Test:
    def run(self):
        self.test_load_save()
        self.test_report(True)
        self.test_envelops()
        self.test_read_transaction()

    def test_read_transaction(self, verbose = False):
        cmds = [ "Salary", "400",
                 "Taxes", "100",
                 "Taxes", "-100",
                 "Grocery", "200" ]
        b = self.create_budget()
        t = b.read_transaction(Expect(verbose = verbose, *(cmds + ["", "n"])))
        assert(t is None)
        t = b.read_transaction(Expect(verbose = verbose, *(cmds + ["", "y"])))
        assert(t.amount == 400)
        assert(t.budget["Taxes"] == 100)
        assert(t.budget["Grocery"] == 200)
        assert(len(t.budget) == 2)
        assert(t.expenses["Taxes"] == 100)
        assert(len(t.expenses) == 1)
        assert(t.balance == 200)
        t = b.read_transaction(Expect(verbose = verbose, *(cmds + ["Hobbies", "", "y"])))
        assert(t.amount == 400)
        assert(t.budget["Taxes"] == 100)
        assert(t.budget["Grocery"] == 200)
        assert(t.budget["Hobbies"] == 200)
        assert(len(t.budget) == 3)
        assert(t.expenses["Taxes"] == 100)
        assert(len(t.expenses) == 1)
        assert(t.balance == 0)

    def create_budget(self):
        b = Budget()
        salary = Decimal(500)
        taxes = salary * Decimal('0.20')
        # Salary: 500 - 100 in taxes = 400
        # Budget: 200$ in Grocery, 100$ for Taxes
        # Expenses: Taxes 100$
        # Unassigned: 200$
        t = Transaction(name="Salary", amount=salary-taxes,
                        budget = [("Grocery", Decimal(200)),
                                  ("Taxes", taxes)],
                        expenses = [("Taxes", taxes)])
        b.add_transaction(t)
        # Gift: 100$
        # Budget: 100$ in Hobbies
        t = Transaction(name = "Gift", amount = Decimal(100), envelop = "Hobbies")
        b.add_transaction(t)
        # Costco: -75$
        # Expenses: 75$ in Grocery
        t = Transaction(name="Costco", amount=Decimal(-75))
        t.rebalance("Grocery")
        b.add_transaction(t)
        # Cinema: -50
        # Expenses: 50$ in Hobbies
        t = Transaction(name="Cinema", amount=Decimal(-50), envelop="Hobbies")
        assert(t.balance == 0)
        b.add_transaction(t)
        # Missing money: -20$
        # Unassigned: -20$
        t = Transaction(name="Missing", amount=Decimal(-20))
        b.add_transaction(t)
        # Total:
        # Budget: 200$ Grocery, 100$ Taxes, 100$ Hobbies = 400$
        # Expenses: 100$ Taxes, 75$ Grocery, 50$ Hobbies = 225$
        # Unassigned: 200$ Salary, -20$ Missing = 180$ 

        b.set_envelop_description("Grocery", "stuff for stomach")
        b.rename_envelop("Grocery", "Food")
        return b

    def test_load_save(self, verbose = False):
        b = self.create_budget()

        from io import StringIO
        fp = StringIO()
        b.save(fp)
        saved = fp.getvalue()
        if verbose: print(saved)

        b2 = Budget()
        b2.load(StringIO(saved))
        fp = StringIO()
        b2.save(fp)
        saved2 = fp.getvalue()
        if verbose: print(saved2)
        assert(saved == saved2)

    def test_envelops(self, verbose = False):
        b = self.create_budget()
        envelops = list(b.envelops)
        assert(len(envelops) == 5)
        total = envelops[-2]
        unassigned = envelops[-1]

        assert(total.budget == 400)
        assert(total.expenses == 225)
        assert(total.balance == 175)
        assert(unassigned.budget == 200)
        assert(unassigned.expenses == 20)
        assert(unassigned.balance == 180)

    def test_report(self, verbose = False):
        b = self.create_budget()
        for l in b.report():
            if verbose:
                print(l)

if __name__ == '__main__':
    Test().run()