from budget_sync.budget_graph import (BudgetGraphLoopError, BudgetGraph,
Node, BudgetGraphMoneyWithNoMilestone,
BudgetGraphBaseError,
- BudgetGraphMoneyMismatch,
+ BudgetGraphMoneyMismatchForBudgetExcludingSubtasks,
+ BudgetGraphMoneyMismatchForBudgetIncludingSubtasks,
BudgetGraphNegativeMoney,
BudgetGraphMilestoneMismatch,
BudgetGraphNegativePayeeMoney,
"bug #1, root bug #5")
def test_budget_graph_money_mismatch(self):
- self.assertEqual(str(BudgetGraphMoneyMismatch(1, 5, "123.4")),
- "Budget assigned to task excluding subtasks "
- "(cf_budget field) doesn't match calculated value:"
- " bug #1, calculated value 123.4")
+ self.assertEqual(str(
+ BudgetGraphMoneyMismatchForBudgetExcludingSubtasks(
+ 1, 5, "123.4")),
+ "Budget assigned to task excluding subtasks "
+ "(cf_budget field) doesn't match calculated value:"
+ " bug #1, calculated value 123.4")
+ self.assertEqual(str(
+ BudgetGraphMoneyMismatchForBudgetIncludingSubtasks(
+ 1, 5, "123.4")),
+ "Budget assigned to task including subtasks "
+ "(cf_total_budget field) doesn't match calculated value:"
+ " bug #1, calculated value 123.4")
def test_budget_graph_negative_money(self):
self.assertEqual(str(BudgetGraphNegativeMoney(1, 5)),
def test_budget_graph_payees_money_mismatch(self):
self.assertEqual(str(
- BudgetGraphPayeesMoneyMismatch(1, 5, Money(123))),
- "Budget assigned to task excluding subtasks (cf_budget field) "
- "doesn't match total value assigned to payees (cf_payees_list):"
- " bug #1, calculated total 123")
+ BudgetGraphPayeesMoneyMismatch(1, 5, Money(123), Money(456))),
+ "Total budget assigned to payees (cf_payees_list) doesn't match "
+ "expected value: bug #1, calculated total 123, expected value 456")
EXAMPLE_BUG1 = MockBug(bug_id=1,
self.assertEqual(node.budget_excluding_subtasks, Money(cents=0))
self.assertEqual(node.budget_including_subtasks, Money(cents=0))
self.assertIsNone(node.nlnet_milestone)
- self.assertEqual(node.payees, {})
+ self.assertEqual(node.payments, {})
def test_loop1(self):
with self.assertRaises(BudgetGraphLoopError) as cm:
self.assertEqual(node1.budget_including_subtasks, Money(cents=2000))
self.assertEqual(node1.nlnet_milestone, "abc")
self.assertEqual(list(node1.children()), [node2])
- self.assertEqual(node1.payees, {})
+ self.assertEqual(list(node1.children_breadth_first()), [node2])
+ self.assertEqual(node1.payments, {})
self.assertIsInstance(node2, Node)
self.assertIs(node2.graph, bg)
self.assertIs(node2.bug, EXAMPLE_CHILD_BUG2)
self.assertEqual(node2.budget_excluding_subtasks, Money(cents=1000))
self.assertEqual(node2.budget_including_subtasks, Money(cents=1000))
self.assertEqual(node2.nlnet_milestone, "abc")
- self.assertEqual(node2.payees, {})
+ self.assertEqual(node2.payments, {})
- def test_money_with_no_milestone(self):
+ def test_children(self):
bg = BudgetGraph([
MockBug(bug_id=1,
cf_budget_parent=None,
cf_budget="0",
- cf_total_budget="10",
+ cf_total_budget="0",
cf_nlnet_milestone=None,
cf_payees_list=""),
- ])
- errors = bg.get_errors()
- self.assertErrorTypesMatches(errors,
- [BudgetGraphMoneyWithNoMilestone,
- BudgetGraphMoneyMismatch])
- self.assertEqual(errors[0].bug_id, 1)
- self.assertEqual(errors[0].root_bug_id, 1)
- bg = BudgetGraph([
- MockBug(bug_id=1,
- cf_budget_parent=None,
- cf_budget="10",
+ MockBug(bug_id=2,
+ cf_budget_parent=1,
+ cf_budget="0",
cf_total_budget="0",
cf_nlnet_milestone=None,
cf_payees_list=""),
- ])
- errors = bg.get_errors()
- self.assertErrorTypesMatches(errors,
- [BudgetGraphMoneyWithNoMilestone,
- BudgetGraphMoneyMismatch])
- self.assertEqual(errors[0].bug_id, 1)
- self.assertEqual(errors[0].root_bug_id, 1)
- bg = BudgetGraph([
- MockBug(bug_id=1,
- cf_budget_parent=None,
- cf_budget="10",
- cf_total_budget="10",
+ MockBug(bug_id=3,
+ cf_budget_parent=1,
+ cf_budget="0",
+ cf_total_budget="0",
+ cf_nlnet_milestone=None,
+ cf_payees_list=""),
+ MockBug(bug_id=4,
+ cf_budget_parent=1,
+ cf_budget="0",
+ cf_total_budget="0",
+ cf_nlnet_milestone=None,
+ cf_payees_list=""),
+ MockBug(bug_id=5,
+ cf_budget_parent=3,
+ cf_budget="0",
+ cf_total_budget="0",
+ cf_nlnet_milestone=None,
+ cf_payees_list=""),
+ MockBug(bug_id=6,
+ cf_budget_parent=3,
+ cf_budget="0",
+ cf_total_budget="0",
+ cf_nlnet_milestone=None,
+ cf_payees_list=""),
+ MockBug(bug_id=7,
+ cf_budget_parent=5,
+ cf_budget="0",
+ cf_total_budget="0",
cf_nlnet_milestone=None,
cf_payees_list=""),
])
- errors = bg.get_errors()
- self.assertErrorTypesMatches(errors, [BudgetGraphMoneyWithNoMilestone])
- self.assertEqual(errors[0].bug_id, 1)
- self.assertEqual(errors[0].root_bug_id, 1)
+ self.assertEqual(len(bg.nodes), 7)
+ node1: Node = bg.nodes[1]
+ node2: Node = bg.nodes[2]
+ node3: Node = bg.nodes[3]
+ node4: Node = bg.nodes[4]
+ node5: Node = bg.nodes[5]
+ node6: Node = bg.nodes[6]
+ node7: Node = bg.nodes[7]
+ self.assertEqual(bg.roots, {node1})
+ self.assertEqual(list(node1.children()),
+ [node2, node3, node5, node7, node6, node4])
+ self.assertEqual(list(node1.children_breadth_first()),
+ [node2, node3, node4, node5, node6, node7])
- def test_money_mismatch(self):
+ def test_money_with_no_milestone(self):
bg = BudgetGraph([
MockBug(bug_id=1,
cf_budget_parent=None,
cf_budget="0",
cf_total_budget="10",
- cf_nlnet_milestone="abc",
+ cf_nlnet_milestone=None,
cf_payees_list=""),
])
errors = bg.get_errors()
- self.assertErrorTypesMatches(errors,
- [BudgetGraphMoneyMismatch])
+ self.assertErrorTypesMatches(errors, [
+ BudgetGraphMoneyWithNoMilestone,
+ BudgetGraphMoneyMismatchForBudgetExcludingSubtasks])
self.assertEqual(errors[0].bug_id, 1)
self.assertEqual(errors[0].root_bug_id, 1)
- self.assertEqual(errors[0].expected_budget_excluding_subtasks, 10)
bg = BudgetGraph([
MockBug(bug_id=1,
cf_budget_parent=None,
cf_budget="10",
cf_total_budget="0",
- cf_nlnet_milestone="abc",
+ cf_nlnet_milestone=None,
cf_payees_list=""),
])
errors = bg.get_errors()
- self.assertErrorTypesMatches(errors,
- [BudgetGraphMoneyMismatch])
+ self.assertErrorTypesMatches(errors, [
+ BudgetGraphMoneyWithNoMilestone,
+ BudgetGraphMoneyMismatchForBudgetIncludingSubtasks])
self.assertEqual(errors[0].bug_id, 1)
self.assertEqual(errors[0].root_bug_id, 1)
- self.assertEqual(errors[0].expected_budget_excluding_subtasks, 0)
bg = BudgetGraph([
MockBug(bug_id=1,
cf_budget_parent=None,
cf_budget="10",
cf_total_budget="10",
- cf_nlnet_milestone="abc",
- cf_payees_list=""),
- ])
- errors = bg.get_errors()
- self.assertEqual(errors, [])
- bg = BudgetGraph([
- MockBug(bug_id=1,
- cf_budget_parent=None,
- cf_budget="10",
- cf_total_budget="10",
- cf_nlnet_milestone="abc",
- cf_payees_list=""),
- MockBug(bug_id=2,
- cf_budget_parent=1,
- cf_budget="10",
- cf_total_budget="10",
- cf_nlnet_milestone="abc",
- cf_payees_list=""),
- MockBug(bug_id=3,
- cf_budget_parent=1,
- cf_budget="1",
- cf_total_budget="10",
- cf_nlnet_milestone="abc",
+ cf_nlnet_milestone=None,
cf_payees_list=""),
])
errors = bg.get_errors()
- self.assertErrorTypesMatches(errors,
- [BudgetGraphMoneyMismatch,
- BudgetGraphMoneyMismatch])
+ self.assertErrorTypesMatches(errors, [BudgetGraphMoneyWithNoMilestone])
self.assertEqual(errors[0].bug_id, 1)
self.assertEqual(errors[0].root_bug_id, 1)
- self.assertEqual(errors[0].expected_budget_excluding_subtasks, -10)
- self.assertEqual(errors[1].bug_id, 3)
- self.assertEqual(errors[1].root_bug_id, 1)
- self.assertEqual(errors[1].expected_budget_excluding_subtasks, 10)
+
+ def test_money_mismatch(self):
+ def helper(budget, total_budget, payees_list, child_budget,
+ expected_errors, expected_fixed_error_types=None):
+ if expected_fixed_error_types is None:
+ expected_fixed_error_types = []
+ bg = BudgetGraph([
+ MockBug(bug_id=1,
+ cf_budget_parent=None,
+ cf_budget=budget,
+ cf_total_budget=total_budget,
+ cf_nlnet_milestone="abc",
+ cf_payees_list=payees_list),
+ MockBug(bug_id=2,
+ cf_budget_parent=1,
+ cf_budget=child_budget,
+ cf_total_budget=child_budget,
+ cf_nlnet_milestone="abc",
+ cf_payees_list=""),
+ ])
+ node1: Node = bg.nodes[1]
+ errors = bg.get_errors()
+ self.assertErrorTypesMatches(errors,
+ [type(i) for i in expected_errors])
+ self.assertEqual([str(i) for i in errors],
+ [str(i) for i in expected_errors])
+ bg = BudgetGraph([
+ MockBug(bug_id=1,
+ cf_budget_parent=None,
+ cf_budget=str(node1.fixed_budget_excluding_subtasks),
+ cf_total_budget=str(
+ node1.fixed_budget_including_subtasks),
+ cf_nlnet_milestone="abc",
+ cf_payees_list=payees_list),
+ MockBug(bug_id=2,
+ cf_budget_parent=1,
+ cf_budget=child_budget,
+ cf_total_budget=child_budget,
+ cf_nlnet_milestone="abc",
+ cf_payees_list=""),
+ ])
+ errors = bg.get_errors()
+ self.assertErrorTypesMatches(errors,
+ expected_fixed_error_types)
+ helper(budget="0",
+ total_budget="0",
+ payees_list="",
+ child_budget="0",
+ expected_errors=[])
+ helper(budget="0",
+ total_budget="0",
+ payees_list="",
+ child_budget="5",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetIncludingSubtasks(
+ 1, 1, Money(5)),
+ ])
+ helper(budget="0",
+ total_budget="0",
+ payees_list="a=1",
+ child_budget="0",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetExcludingSubtasks(
+ 1, 1, Money(1)),
+ BudgetGraphMoneyMismatchForBudgetIncludingSubtasks(
+ 1, 1, Money(1)),
+ ])
+ helper(budget="0",
+ total_budget="0",
+ payees_list="a=1",
+ child_budget="5",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetExcludingSubtasks(
+ 1, 1, Money(1)),
+ BudgetGraphMoneyMismatchForBudgetIncludingSubtasks(
+ 1, 1, Money(6)),
+ ])
+ helper(budget="0",
+ total_budget="0",
+ payees_list="a=10",
+ child_budget="0",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetExcludingSubtasks(
+ 1, 1, Money(10)),
+ BudgetGraphMoneyMismatchForBudgetIncludingSubtasks(
+ 1, 1, Money(10)),
+ ])
+ helper(budget="0",
+ total_budget="0",
+ payees_list="a=10",
+ child_budget="5",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetExcludingSubtasks(
+ 1, 1, Money(10)),
+ BudgetGraphMoneyMismatchForBudgetIncludingSubtasks(
+ 1, 1, Money(15)),
+ ])
+ helper(budget="0",
+ total_budget="100",
+ payees_list="",
+ child_budget="0",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetExcludingSubtasks(
+ 1, 1, Money(100)),
+ ])
+ helper(budget="0",
+ total_budget="100",
+ payees_list="",
+ child_budget="5",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetExcludingSubtasks(
+ 1, 1, Money(95)),
+ ])
+ helper(budget="0",
+ total_budget="100",
+ payees_list="a=1",
+ child_budget="0",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetExcludingSubtasks(
+ 1, 1, Money(100)),
+ BudgetGraphPayeesMoneyMismatch(1, 1, Money(1), Money(100)),
+ ],
+ expected_fixed_error_types=[BudgetGraphPayeesMoneyMismatch])
+ helper(budget="0",
+ total_budget="100",
+ payees_list="a=1",
+ child_budget="5",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetExcludingSubtasks(
+ 1, 1, Money(95)),
+ BudgetGraphPayeesMoneyMismatch(1, 1, Money(1), Money(95)),
+ ],
+ expected_fixed_error_types=[BudgetGraphPayeesMoneyMismatch])
+ helper(budget="0",
+ total_budget="100",
+ payees_list="a=10",
+ child_budget="0",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetExcludingSubtasks(
+ 1, 1, Money(100)),
+ BudgetGraphPayeesMoneyMismatch(1, 1, Money(10), Money(100)),
+ ],
+ expected_fixed_error_types=[BudgetGraphPayeesMoneyMismatch])
+ helper(budget="0",
+ total_budget="100",
+ payees_list="a=10",
+ child_budget="5",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetExcludingSubtasks(
+ 1, 1, Money(95)),
+ BudgetGraphPayeesMoneyMismatch(1, 1, Money(10), Money(95)),
+ ],
+ expected_fixed_error_types=[BudgetGraphPayeesMoneyMismatch])
+ helper(budget="0",
+ total_budget="5",
+ payees_list="",
+ child_budget="5",
+ expected_errors=[])
+ helper(budget="0",
+ total_budget="5",
+ payees_list="a=1",
+ child_budget="5",
+ expected_errors=[
+ BudgetGraphPayeesMoneyMismatch(1, 1, Money(1), Money(0)),
+ ],
+ expected_fixed_error_types=[BudgetGraphPayeesMoneyMismatch])
+ helper(budget="0",
+ total_budget="5",
+ payees_list="a=10",
+ child_budget="5",
+ expected_errors=[
+ BudgetGraphPayeesMoneyMismatch(1, 1, Money(10), Money(0)),
+ ],
+ expected_fixed_error_types=[BudgetGraphPayeesMoneyMismatch])
+ helper(budget="10",
+ total_budget="0",
+ payees_list="",
+ child_budget="0",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetIncludingSubtasks(
+ 1, 1, Money(10)),
+ ])
+ helper(budget="10",
+ total_budget="0",
+ payees_list="",
+ child_budget="5",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetIncludingSubtasks(
+ 1, 1, Money(15)),
+ ])
+ helper(budget="10",
+ total_budget="0",
+ payees_list="a=1",
+ child_budget="0",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetIncludingSubtasks(
+ 1, 1, Money(10)),
+ BudgetGraphPayeesMoneyMismatch(1, 1, Money(1), Money(10)),
+ ],
+ expected_fixed_error_types=[BudgetGraphPayeesMoneyMismatch])
+ helper(budget="10",
+ total_budget="0",
+ payees_list="a=1",
+ child_budget="5",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetIncludingSubtasks(
+ 1, 1, Money(15)),
+ BudgetGraphPayeesMoneyMismatch(1, 1, Money(1), Money(10)),
+ ],
+ expected_fixed_error_types=[BudgetGraphPayeesMoneyMismatch])
+ helper(budget="10",
+ total_budget="0",
+ payees_list="a=10",
+ child_budget="0",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetIncludingSubtasks(
+ 1, 1, Money(10)),
+ ])
+ helper(budget="10",
+ total_budget="0",
+ payees_list="a=10",
+ child_budget="5",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetIncludingSubtasks(
+ 1, 1, Money(15)),
+ ])
+ helper(budget="10",
+ total_budget="10",
+ payees_list="",
+ child_budget="0",
+ expected_errors=[])
+ helper(budget="10",
+ total_budget="10",
+ payees_list="a=1",
+ child_budget="0",
+ expected_errors=[
+ BudgetGraphPayeesMoneyMismatch(1, 1, Money(1), Money(10)),
+ ],
+ expected_fixed_error_types=[BudgetGraphPayeesMoneyMismatch])
+ helper(budget="10",
+ total_budget="10",
+ payees_list="a=10",
+ child_budget="0",
+ expected_errors=[])
+ helper(budget="10",
+ total_budget="100",
+ payees_list="",
+ child_budget="0",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetExcludingSubtasks(
+ 1, 1, Money(100)),
+ ])
+ helper(budget="10",
+ total_budget="100",
+ payees_list="",
+ child_budget="5",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetExcludingSubtasks(
+ 1, 1, Money(95)),
+ ])
+ helper(budget="10",
+ total_budget="100",
+ payees_list="a=1",
+ child_budget="0",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetIncludingSubtasks(
+ 1, 1, Money(10)),
+ BudgetGraphPayeesMoneyMismatch(1, 1, Money(1), Money(10)),
+ ],
+ expected_fixed_error_types=[BudgetGraphPayeesMoneyMismatch])
+ helper(budget="10",
+ total_budget="100",
+ payees_list="a=1",
+ child_budget="5",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetIncludingSubtasks(
+ 1, 1, Money(15)),
+ BudgetGraphPayeesMoneyMismatch(1, 1, Money(1), Money(10)),
+ ],
+ expected_fixed_error_types=[BudgetGraphPayeesMoneyMismatch])
+ helper(budget="10",
+ total_budget="100",
+ payees_list="a=10",
+ child_budget="0",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetIncludingSubtasks(
+ 1, 1, Money(10)),
+ ])
+ helper(budget="10",
+ total_budget="100",
+ payees_list="a=10",
+ child_budget="5",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetIncludingSubtasks(
+ 1, 1, Money(15)),
+ ])
+ helper(budget="10",
+ total_budget="15",
+ payees_list="",
+ child_budget="5",
+ expected_errors=[])
+ helper(budget="10",
+ total_budget="15",
+ payees_list="a=1",
+ child_budget="5",
+ expected_errors=[
+ BudgetGraphPayeesMoneyMismatch(1, 1, Money(1), Money(10)),
+ ],
+ expected_fixed_error_types=[BudgetGraphPayeesMoneyMismatch])
+ helper(budget="10",
+ total_budget="15",
+ payees_list="a=10",
+ child_budget="5",
+ expected_errors=[])
+
+ helper(budget="1",
+ total_budget="15",
+ payees_list="a=10",
+ child_budget="5",
+ expected_errors=[
+ BudgetGraphMoneyMismatchForBudgetExcludingSubtasks(
+ 1, 1, Money("10"))
+ ])
def test_negative_money(self):
bg = BudgetGraph([
cf_payees_list=""),
])
errors = bg.get_errors()
- self.assertErrorTypesMatches(errors,
- [BudgetGraphNegativeMoney,
- BudgetGraphMoneyMismatch])
+ self.assertErrorTypesMatches(errors, [
+ BudgetGraphNegativeMoney,
+ BudgetGraphMoneyMismatchForBudgetExcludingSubtasks])
self.assertEqual(errors[0].bug_id, 1)
self.assertEqual(errors[0].root_bug_id, 1)
self.assertEqual(errors[1].bug_id, 1)
cf_payees_list=""),
])
errors = bg.get_errors()
- self.assertErrorTypesMatches(errors,
- [BudgetGraphNegativeMoney,
- BudgetGraphMoneyMismatch])
+ self.assertErrorTypesMatches(errors, [
+ BudgetGraphNegativeMoney,
+ BudgetGraphMoneyMismatchForBudgetIncludingSubtasks])
self.assertEqual(errors[0].bug_id, 1)
self.assertEqual(errors[0].root_bug_id, 1)
self.assertEqual(errors[1].bug_id, 1)
self.assertEqual(errors[1].root_bug_id, 1)
- self.assertEqual(errors[1].expected_budget_excluding_subtasks, 0)
+ self.assertEqual(errors[1].expected_budget_including_subtasks, -10)
bg = BudgetGraph([
MockBug(bug_id=1,
cf_budget_parent=None,
self.assertEqual(errors[0].root_bug_id, 1)
def test_payees_parse(self):
- def check(cf_payees_list, expected_payees):
+ def check(cf_payees_list, expected_payments):
bg = BudgetGraph([MockBug(bug_id=1,
cf_budget_parent=None,
cf_budget="0",
])
self.assertEqual(len(bg.nodes), 1)
node: Node = bg.nodes[1]
- self.assertEqual(node.payees, expected_payees)
+ self.assertEqual([str(i) for i in node.payments.values()],
+ expected_payments)
check("""
abc = 123
""",
- {"abc": Money(123)})
+ ["Payment(node=#1, payee_key='abc', amount=123, "
+ + "state=NotYetSubmitted, paid=None, submitted=None)"])
check("""
abc = "123"
""",
- {"abc": Money(123)})
+ ["Payment(node=#1, payee_key='abc', amount=123, "
+ + "state=NotYetSubmitted, paid=None, submitted=None)"])
check("""
abc = "123.45"
""",
- {"abc": Money("123.45")})
+ ["Payment(node=#1, payee_key='abc', amount=123.45, "
+ + "state=NotYetSubmitted, paid=None, submitted=None)"])
check("""
abc = "123.45"
"d e f" = "21.35"
""",
- {
- "abc": Money("123.45"),
- "d e f": Money("21.35"),
- })
+ ["Payment(node=#1, payee_key='abc', amount=123.45, "
+ + "state=NotYetSubmitted, paid=None, submitted=None)",
+ "Payment(node=#1, payee_key='d e f', amount=21.35, "
+ + "state=NotYetSubmitted, paid=None, submitted=None)"])
check("""
abc = "123.45"
# my comments
"AAA" = "-21.35"
""",
- {
- "abc": Money("123.45"),
- "AAA": Money("-21.35"),
- })
+ ["Payment(node=#1, payee_key='abc', amount=123.45, "
+ + "state=NotYetSubmitted, paid=None, submitted=None)",
+ "Payment(node=#1, payee_key='AAA', amount=-21.35, "
+ + "state=NotYetSubmitted, paid=None, submitted=None)"])
check("""
"not-an-email@example.com" = "-2345"
""",
- {
- "not-an-email@example.com": Money(-2345),
- })
+ ["Payment(node=#1, payee_key='not-an-email@example.com', "
+ + "amount=-2345, state=NotYetSubmitted, paid=None, "
+ + "submitted=None)"])
+ check("""
+ payee = { amount = 123 }
+ """,
+ ["Payment(node=#1, payee_key='payee', "
+ + "amount=123, state=NotYetSubmitted, paid=None, "
+ + "submitted=None)"])
+ check("""
+ payee = { amount = 123, submitted = 2020-05-01 }
+ """,
+ ["Payment(node=#1, payee_key='payee', "
+ + "amount=123, state=Submitted, paid=None, "
+ + "submitted=2020-05-01)"])
+ check("""
+ payee = { amount = 123, submitted = 2020-05-01T00:00:00 }
+ """,
+ ["Payment(node=#1, payee_key='payee', "
+ + "amount=123, state=Submitted, paid=None, "
+ + "submitted=2020-05-01 00:00:00)"])
+ check("""
+ payee = { amount = 123, submitted = 2020-05-01T00:00:00Z }
+ """,
+ ["Payment(node=#1, payee_key='payee', "
+ + "amount=123, state=Submitted, paid=None, "
+ + "submitted=2020-05-01 00:00:00+00:00)"])
+ check("""
+ payee = { amount = 123, submitted = 2020-05-01T00:00:00-07:23 }
+ """,
+ ["Payment(node=#1, payee_key='payee', "
+ + "amount=123, state=Submitted, paid=None, "
+ + "submitted=2020-05-01 00:00:00-07:23)"])
+ check("""
+ payee = { amount = 123, paid = 2020-05-01 }
+ """,
+ ["Payment(node=#1, payee_key='payee', "
+ + "amount=123, state=Paid, paid=2020-05-01, "
+ + "submitted=None)"])
+ check("""
+ payee = { amount = 123, paid = 2020-05-01T00:00:00 }
+ """,
+ ["Payment(node=#1, payee_key='payee', "
+ + "amount=123, state=Paid, paid=2020-05-01 00:00:00, "
+ + "submitted=None)"])
+ check("""
+ payee = { amount = 123, paid = 2020-05-01T00:00:00Z }
+ """,
+ ["Payment(node=#1, payee_key='payee', "
+ + "amount=123, state=Paid, paid=2020-05-01 00:00:00+00:00, "
+ + "submitted=None)"])
+ check("""
+ payee = { amount = 123, paid = 2020-05-01T00:00:00-07:23 }
+ """,
+ ["Payment(node=#1, payee_key='payee', "
+ + "amount=123, state=Paid, paid=2020-05-01 00:00:00-07:23, "
+ + "submitted=None)"])
+ check("""
+ [payee]
+ amount = 123
+ submitted = 2020-05-23
+ paid = 2020-05-01
+ """,
+ ["Payment(node=#1, payee_key='payee', "
+ + "amount=123, state=Paid, paid=2020-05-01, "
+ + "submitted=2020-05-23)"])
+ check("""
+ [payee]
+ amount = 123
+ submitted = 2020-05-23
+ paid = 2020-05-01T00:00:00
+ """,
+ ["Payment(node=#1, payee_key='payee', "
+ + "amount=123, state=Paid, paid=2020-05-01 00:00:00, "
+ + "submitted=2020-05-23)"])
+ check("""
+ [payee]
+ amount = 123
+ submitted = 2020-05-23
+ paid = 2020-05-01T00:00:00Z
+ """,
+ ["Payment(node=#1, payee_key='payee', "
+ + "amount=123, state=Paid, paid=2020-05-01 00:00:00+00:00, "
+ + "submitted=2020-05-23)"])
+ check("""
+ [payee]
+ amount = 123
+ submitted = 2020-05-23
+ paid = 2020-05-01T00:00:00-07:23
+ """,
+ ["Payment(node=#1, payee_key='payee', "
+ + "amount=123, state=Paid, paid=2020-05-01 00:00:00-07:23, "
+ + "submitted=2020-05-23)"])
def test_payees_money_mismatch(self):
bg = BudgetGraph([
self.assertEqual(errors[0].bug_id, 1)
self.assertEqual(errors[0].root_bug_id, 1)
self.assertEqual(errors[0].payees_total, 15)
- bg = BudgetGraph([
- MockBug(bug_id=1,
- cf_budget_parent=None,
- cf_budget="0",
- cf_total_budget="0",
- cf_nlnet_milestone=None,
- cf_payees_list="payee = 5\npayee2 = 10"),
- ])
- errors = bg.get_errors()
- self.assertErrorTypesMatches(errors,
- [BudgetGraphPayeesMoneyMismatch])
- self.assertEqual(errors[0].bug_id, 1)
- self.assertEqual(errors[0].root_bug_id, 1)
- self.assertEqual(errors[0].payees_total, 15)
def test_payees_parse_error(self):
def check_parse_error(cf_payees_list, expected_msg):
self.assertEqual(errors[0].msg, expected_msg)
check_parse_error("""
- "payee 1" = {}
+ "payee 1" = []
""",
- "value for key 'payee 1' is not a string or integer "
- "(to use fractional values such as 123.45, write "
- "\"123.45\"): {}")
+ "value for key 'payee 1' is invalid -- it should "
+ "either be a monetary value or a table")
check_parse_error("""
payee = "ashjkf"
""",
- "failed to parse Money value for key 'payee': "
+ "failed to parse monetary amount for key 'payee': "
"invalid Money string: characters after sign and "
"before first `.` must be ascii digits")
check_parse_error("""
payee = 123.45
""",
- "value for key 'payee' is not a string or "
- "integer (to use fractional values such as "
- "123.45, write \"123.45\"): 123.45")
+ "failed to parse monetary amount for key 'payee': "
+ "monetary amount is not a string or integer (to "
+ "use fractional amounts such as 123.45, write "
+ "\"123.45\"): 123.45")
+
+ check_parse_error("""
+ payee = {}
+ """,
+ "value for key 'payee' is missing the `amount` "
+ "field which is required")
+
+ check_parse_error("""
+ payee = { amount = 123.45 }
+ """,
+ "failed to parse monetary amount for key 'payee': "
+ "monetary amount is not a string or integer (to "
+ "use fractional amounts such as 123.45, write "
+ "\"123.45\"): 123.45")
+
+ check_parse_error("""
+ payee = { amount = 123, blah = false }
+ """,
+ "value for key 'payee' has an unknown field: `blah`")
+
+ check_parse_error("""
+ payee = { amount = 123, submitted = false }
+ """,
+ "failed to parse `submitted` field for key "
+ "'payee': invalid date: false")
+
+ check_parse_error("""
+ payee = { amount = 123, submitted = 123 }
+ """,
+ "failed to parse `submitted` field for key 'payee':"
+ " invalid date: 123")
+
+ check_parse_error(
+ """
+ payee = { amount = 123, paid = 2020-01-01, submitted = "abc" }
+ """,
+ "failed to parse `submitted` field for key 'payee': "
+ "invalid date: 'abc'")
+
+ check_parse_error(
+ """
+ payee = { amount = 123, paid = 12:34:56 }
+ """,
+ "failed to parse `paid` field for key 'payee': just a time of "
+ "day by itself is not enough, a date must be included: 12:34:56")
+
+ check_parse_error(
+ """
+ payee = { amount = 123, submitted = 12:34:56.123456 }
+ """,
+ "failed to parse `submitted` field for key 'payee': just a time "
+ "of day by itself is not enough, a date must be included: "
+ "12:34:56.123456")
def test_negative_payee_money(self):
bg = BudgetGraph([