Example #1
0
class AccountTest(unittest.TestCase):
    def setUp(self):
        self.parser = Parser()
        self.account = self.parser.parse_account("Assets:Bank")

    def testAccountAdd(self):
        amount = self.parser.parse_value("150 EUR")
        entry = self.account + amount
        self.assertEqual(self.account, entry.account)
        self.assertEqual(amount, entry.amount)

    def testAccountSub(self):
        amount = self.parser.parse_value("150 EUR")
        entry = self.account - amount
        self.assertEqual(self.account, entry.account)
        self.assertEqual(-amount, entry.amount)

    def testRoot(self):
        self.assertEqual(self.parser.accounts["Assets"], self.account.root())

    def testShortenedName(self):
        account = self.account["Joint:Savings:Yearly:Interest:Compound:Open"]
        size = 30
        name = account.shortened_name(size)

        self.assertLessEqual(len(name), size)
        self.assertEqual(7, len(filter(lambda x: x == ':', name)))

    def testSubName(self):
        account = self.account["Checking"]
        self.assertEqual(u'Bank:Checking', self.account.parent.sub_name(account))
        self.assertIsNone(self.account.sub_name(self.parser.accounts["Test"]))
Example #2
0
class TestTagFilters(unittest.TestCase):
    def setUp(self):
        self.parser = Parser()
        bank_account = self.parser.parse_account("Assets:Bank")
        books_account = self.parser.parse_account("Expenses:Books")
        bank_account.tags["foo"] = "bar"

        self.bank = bank_account - self.parser.parse_value("33 $")
        self.books = books_account + self.parser.parse_value("33 $")
        self.tr = Transaction([self.bank, self.books])
        self.tr.tags["baz"] = "hello world"
        self.books.tags["title"] = "Necronomicon"

    def testAccountTagFilter(self):
        filter = Account.tag_filter("foo", "bar")
        self.assertTrue(filter(self.tr, self.bank))
        self.assertFalse(filter(self.tr, self.books))

    def testAccountTagFilterEmpty(self):
        filter = Account.tag_filter("foo")
        self.assertTrue(filter(self.tr, self.bank))
        self.assertFalse(filter(self.tr, self.books))

    def testAccountTagFilterWrong(self):
        filter = Account.tag_filter("baz")
        self.assertFalse(filter(self.tr, self.bank))
        self.assertFalse(filter(self.tr, self.books))

    def testTransactionTagFilter(self):
        filter = Transaction.tag_filter("baz", "hello world")
        self.assertTrue(filter(self.tr, self.bank))
        self.assertTrue(filter(self.tr, self.books))
        self.assertTrue(filter(self.tr, None))

    def testTransactionTagFilterEmpty(self):
        filter = Transaction.tag_filter("baz", None)
        self.assertTrue(filter(self.tr, self.bank))
        self.assertTrue(filter(self.tr, self.books))
        self.assertTrue(filter(self.tr, None))

    def testTransactionTagFilterWrong(self):
        filter = Transaction.tag_filter("foo", None)
        self.assertFalse(filter(self.tr, self.bank))
        self.assertFalse(filter(self.tr, self.books))
        self.assertFalse(filter(self.tr, None))

    def testTransactionAccountFilter(self):
        filter = Transaction.account_tag_filter("foo", "bar")
        self.assertTrue(filter(self.tr, None))

    def testEntryTagFilter(self):
        filter = Entry.tag_filter("title", "Necronomicon")
        self.assertTrue(filter(self.tr, self.books))
        self.assertFalse(filter(self.tr, self.bank))
        self.assertFalse(filter(self.tr, None))
Example #3
0
class TestFilter(unittest.TestCase):
    def setUp(self):
        self.three_entries = Filter(lambda tr, entry: len(tr.entries) == 3)
        self.in_euro = Filter(lambda tr, entry: list(entry.amount.currencies()) == ["EUR"])

        self.parser = Parser()
        bank_account = self.parser.parse_account("Assets:Bank")
        books_account = self.parser.parse_account("Expenses:Books")
        cash_account = self.parser.parse_account("Assets:Cash")

        bank = bank_account - self.parser.parse_value("33 EUR")
        books = books_account + self.parser.parse_value("33 EUR")
        self.tr1 = Transaction([bank, books])

        bank = bank_account - self.parser.parse_value("91 $")
        books = books_account + self.parser.parse_value("40 $")
        cash = cash_account + self.parser.parse_value("51 $")
        self.tr2 = Transaction([bank, books, cash])
        
    def testFilter(self):
        self.assertFalse(self.three_entries(self.tr1, self.tr1.entries[0]))
        self.assertTrue(self.three_entries(self.tr2, self.tr2.entries[0]))
        self.assertTrue(self.in_euro(self.tr1, self.tr1.entries[0]))
        self.assertFalse(self.in_euro(self.tr2, self.tr2.entries[0]))

    def testFilterParse(self):
        filter = Filter.parse(self.parser, lambda tr, entry: entry.account.name.startswith("Assets"))
        self.assertTrue(filter(self.tr1, self.tr1.entries[0]))
        self.assertFalse(filter(self.tr1, self.tr1.entries[1]))

    def testFilterInvert(self):
        self.assertTrue((~self.three_entries)(self.tr1, self.tr1.entries[0]))
        self.assertFalse((~self.three_entries)(self.tr2, self.tr2.entries[0]))
        self.assertFalse((~self.in_euro)(self.tr1, self.tr1.entries[0]))
        self.assertTrue((~self.in_euro)(self.tr2, self.tr2.entries[0]))

    def testFilterAnd(self):
        filter = self.three_entries & self.in_euro
        self.assertFalse(filter(self.tr1, self.tr1.entries[0]))
        self.assertFalse(filter(self.tr2, self.tr2.entries[0]))

    def testFilterOr(self):
        filter = self.three_entries | self.in_euro
        self.assertTrue(filter(self.tr1, self.tr1.entries[0]))
        self.assertTrue(filter(self.tr2, self.tr2.entries[0]))

    def testHasAccountFilter(self):
        filter = Filter.has_account(self.parser.parse_account("Assets:Bank"))
        self.assertTrue(filter(self.tr1, self.tr1.entries[0]))
        self.assertFalse(filter(self.tr1, self.tr1.entries[1]))

    def testMatchesFilter(self):
        filter = Filter.matches(re.compile(r"ank"))
        self.assertTrue(filter(self.tr1, self.tr1.entries[0]))
        self.assertFalse(filter(self.tr1, self.tr1.entries[1]))
Example #4
0
class TestCLIFilters(unittest.TestCase):
    def setUp(self):
        self.parser = Parser()
        bank_account = self.parser.parse_account("Assets:Bank")
        books_account = self.parser.parse_account("Expenses:Books")
        cash_account = self.parser.parse_account("Assets:Cash")

        bank = bank_account - self.parser.parse_value("33 EUR")
        books = books_account + self.parser.parse_value("33 EUR")
        books.tags["foo"] = "bar"
        self.tr1 = Transaction([bank, books], date=date(2009, 12, 31))

        bank = bank_account - self.parser.parse_value("91 $")
        books = books_account + self.parser.parse_value("40 $")
        books.tags["date"] = date(2009, 3, 1)
        cash = cash_account + self.parser.parse_value("51 $")
        self.tr2 = Transaction([bank, books, cash], date=date(2010, 1, 1))

    def testDateFilter(self):
        filter = DateFilter.parse(self.parser, "2010/10/01")
        self.assertEqual(date(2010, 10, 1), filter.date)

        self.assertRaises(ValueError, DateFilter.parse, self.parser, "foo")
        self.assertRaises(ValueError, DateFilter.parse, self.parser, "2011/15/12")

    def testBeginFilter(self):
        filter = BeginFilter.parse(self.parser, "2010")
        self.assertFalse(filter(self.tr1, self.tr1.entries[0]))
        self.assertTrue(filter(self.tr2, self.tr2.entries[0]))
        self.assertFalse(filter(self.tr2, self.tr2.entries[1]))

    def testEndFilter(self):
        filter = EndFilter.parse(self.parser, "2010")
        self.assertTrue(filter(self.tr1, self.tr1.entries[0]))
        self.assertFalse(filter(self.tr2, self.tr2.entries[0]))
        self.assertTrue(filter(self.tr2, self.tr2.entries[1]))

    def testExpressionFilter(self):
        filter = ExpressionFilter.parse(self.parser, "entry.account.name.startswith('Assets')")
        self.assertTrue(filter(self.tr1, self.tr1.entries[0]))
        self.assertFalse(filter(self.tr1, self.tr1.entries[1]))

    def testExpressionFilterDate(self):
        filter = ExpressionFilter.parse(self.parser, "entry.date < date('2010')")
        self.assertTrue(filter(self.tr1, self.tr1.entries[0]))
        self.assertFalse(filter(self.tr2, self.tr2.entries[0]))
        self.assertTrue(filter(self.tr2, self.tr2.entries[1]))

    def testExpressionFilterTag(self):
        filter = ExpressionFilter.parse(self.parser, "entry.foo")
        self.assertFalse(filter(self.tr1, self.tr1.entries[0]))
        self.assertTrue(filter(self.tr1, self.tr1.entries[1]))
Example #5
0
class RuleTest(unittest.TestCase):
    def setUp(self):
        self.parser = Parser()
        self.bank_account = self.parser.parse_account("Assets:Bank")
        self.books_account = self.parser.parse_account("Expenses:Books")
        self.cash_account = self.parser.parse_account("Assets:Cash")

        bank = self.bank_account - self.parser.parse_value("33 EUR")
        books = self.books_account + self.parser.parse_value("33 EUR")
        self.tr = Transaction([bank, books])

        self.rules = RuleCollection()

        @Generator
        def discount(entry):
            amount = entry.amount * Decimal("0.1")
            yield entry.account - amount
            yield self.cash_account + amount
        self.discount = discount

    def testRuleOnLedger(self):
        rule = Rule(Filter.has_account(self.books_account), self.discount)
        self.rules.add_rule(rule)

        result = []
        result += self.rules.apply(self.tr, self.tr.entries[0])
        result += self.rules.apply(self.tr, self.tr.entries[1])

        expected = [self.bank_account - self.parser.parse_value("33.00 EUR"),
                    self.books_account + self.parser.parse_value("33.00 EUR"),
                    self.cash_account + self.parser.parse_value("3.30 EUR"),
                    self.books_account - self.parser.parse_value("3.30 EUR")]

        self.assertItemsEqual(expected, result)

    def testAccountTagRule(self):
        self.books_account.tags["discount"] = self.discount
        self.rules.add_rule(Account.tag_rule("discount"))

        result = []
        result += self.rules.apply(self.tr, self.tr.entries[0])
        result += self.rules.apply(self.tr, self.tr.entries[1])

        expected = [self.bank_account - self.parser.parse_value("33.00 EUR"),
                    self.books_account + self.parser.parse_value("33.00 EUR"),
                    self.cash_account + self.parser.parse_value("3.30 EUR"),
                    self.books_account - self.parser.parse_value("3.30 EUR")]

        self.assertItemsEqual(expected, result)
Example #6
0
class EntryTest(unittest.TestCase):
    def setUp(self):
        self.parser = Parser()

    def testParsing(self):
        value = self.parser.parse_value("34 EUR")
        account = self.parser.parse_account("Test Account")
        entry = Entry(account, value)
        self.assertEqual(entry, self.parser.parse_entry("  Test Account        34 EUR"))

    def testEquality(self):
        value1 = self.parser.parse_value("34 EUR")
        value2 = self.parser.parse_value("12 $")
        account1 = self.parser.parse_account("Test")
        account2 = self.parser.parse_account("Bank")

        self.assertEqual(Entry(account1, value1), Entry(account1, value1))
        self.assertNotEqual(Entry(account1, value1), Entry(account2, value1))
        self.assertNotEqual(Entry(account1, value1), Entry(account1, value2))

    def testEntryParser(self):
        entry = self.parser.parse_entry("  Expenses:Books       61 EUR   ; :gift:")
        self.assertEqual("Expenses:Books", entry.account.name)
        self.assertEqual(Value.parse("61 EUR"), entry.amount)
        self.assertItemsEqual(["gift"], entry.tags.keys())

    def testEntryDict(self):
        entry = self.parser.parse_entry("  Expenses:Books       61 EUR   ; :gift:")
        entry2 = self.parser.parse_entry("  Expenses:Books       61 EUR")
        entry3 = self.parser.parse_entry("  Expenses:Books       51 EUR")
        entry4 = self.parser.parse_entry("    Expenses:Books       51 EUR")

        d = {}
        d[entry] = True
        d[entry2] = True
        d[entry3] = True
        d[entry4] = True

        self.assertItemsEqual([entry, entry2, entry3], d.keys())

    def testRepr(self):
        entry = self.parser.parse_entry("  Expenses:Books    55 EUR")
        s = str(entry)

        self.assertRegexpMatches(s, "Expenses:Books")
        self.assertRegexpMatches(s, "55.00 EUR")

    def testEntryDate(self):
        entry = self.parser.parse_entry("  Expenses:Books       61 EUR   ; [2011/03/03]")
        entry2 = self.parser.parse_entry("  Expenses:Books       61 EUR")
        transaction = FakeTransaction(date=date(2011, 03, 01))

        self.assertEqual(date(2011, 03, 03), entry.date(transaction))
        self.assertEqual(date(2011, 03, 01), entry2.date(transaction))

    def testEntryOfTransaction(self):
        transaction = FakeTransaction(date=date(2011, 03, 01))
        entry = self.parser.parse_entry("  Expenses:Books       61 EUR   ; [2011/03/03]").of(transaction)
        entry2 = self.parser.parse_entry("  Expenses:Books       61 EUR").of(transaction)

        self.assertEqual(date(2011, 03, 03), entry.date)
        self.assertEqual(date(2011, 03, 01), entry2.date)
Example #7
0
class TransactionTest(unittest.TestCase):
    def setUp(self):
        self.parser = Parser()
        self.bank = self.parser.accounts["Assets"]["Bank"]
        self.expenses = self.parser.accounts["Expenses"]["Books"]

    def testParsing(self):
        str = "2011/04/15 * Bookshop\n" + \
              "    Assets:Bank       -40 EUR\n" + \
              "    Expenses:Books"
        value = self.parser.parse_value("40 EUR")
        entry1 = Entry(self.bank, -value)
        entry2 = Entry(self.expenses, value)
        tr = Transaction([entry1, entry2])
        self.assertEquals(tr, self.parser.parse_transaction(str))

    def testParsingComments(self):
        str = "; gift for wife\n" + \
              "2011/05/21 * Bookshop\n" + \
              "    Assets:Bank      -40 EUR\n" + \
              "    Expenses:Books"
        tr = self.parser.parse_transaction(str)

        value = self.parser.parse_value("40 EUR")
        self.assertEqual("Assets:Bank", tr.entries[0].account.name)
        self.assertEqual("Expenses:Books", tr.entries[1].account.name)
        self.assertEqual(-value, tr.entries[0].amount)
        self.assertEqual(value, tr.entries[1].amount)

    def testEmptyTransaction(self):
        str = ""
        self.assertIsNone(self.parser.parse_transaction(str))

        str = "; hello world"
        self.assertIsNone(self.parser.parse_transaction(str))

    def testParseUnbalanced(self):
        str = "2011/02/05 * Bookshop\n" + \
              "    Assets:Bank          -40 EUR\n" + \
              "    Expenses:Book        41 EUR"
        with self.assertRaises(UnbalancedTransaction) as cm:
            self.parser.parse_transaction(str)

    def testParseUndefined(self):
        str = "2011/02/05 * Bookshop\n" + \
              "    Assets:Bank\n" + \
              "    Expenses:Book"
        with self.assertRaises(UndefinedTransaction) as cm:
            self.parser.parse_transaction(str)

    def testMalformedHeader(self):
        str = "test 2011/02/05 * Bookshop\n" + \
              "    Assets:Bank          -40 EUR\n" + \
              "    Expenses:Book"
        with self.assertRaises(MalformedHeader) as cm:
            self.parser.parse_transaction(str)

    def testMalformedHeader2(self):
        str = " 2011/02/05 * Bookshop\n" + \
              "    Assets:Bank          -40 EUR\n" + \
              "    Expenses:Book"
        with self.assertRaises(MalformedHeader) as cm:
            self.parser.parse_transaction(str)

    def testUnbalanced(self):
        value = self.parser.parse_value("40 EUR")
        entry1 = Entry(self.bank, value)
        entry2 = Entry(self.expenses, value)
        self.assertRaises(UnbalancedTransaction, Transaction, [entry1, entry2])

    def testUndefined(self):
        entry1 = Entry(self.bank, None)
        entry2 = Entry(self.expenses, None)
        self.assertRaises(UndefinedTransaction, Transaction, [entry1, entry2])

    def testDefined(self):
        value = self.parser.parse_value("40 EUR")
        entry1 = Entry(self.bank, value)
        entry2 = Entry(self.expenses, None)
        tr = Transaction([entry1, entry2])
        self.assertEqual(-value, tr.entries[-1].amount)

    def testRepr(self):
        value = self.parser.parse_value("50 EUR")
        entry1 = Entry(self.bank, value)
        entry2 = Entry(self.expenses, None)
        tr = Transaction([entry1, entry2])
        self.assertRegexpMatches(repr(tr), "Transaction")

    def testTransactionEntries(self):
        value = self.parser.parse_value("50 EUR")
        entry1 = Entry(self.bank, value)
        entry2 = Entry(self.expenses, None)
        tr = Transaction([entry1, entry2])
        self.assertEqual(entry1, tr[0])
        self.assertEqual(entry2, tr[1])

    def testAmount(self):
        value = self.parser.parse_value("40 EUR")
        entry1 = Entry(self.bank, value)
        entry2 = Entry(self.expenses, None)
        tr = Transaction([entry1, entry2])
        self.assertEqual(ZERO, tr.amount)

    def testClone(self):
        value = self.parser.parse_value("40 EUR")
        entry1 = Entry(self.bank, value)
        entry2 = Entry(self.expenses, None)
        tr = Transaction([entry1, entry2])
        tr2 = tr.clone()
        self.assertFalse(id(tr) == id(tr2))
        self.assertItemsEqual(tr.entries, tr2.entries)
        self.assertEqual(tr.date, tr2.date)
        self.assertEqual(tr.label, tr2.label)