1 from budget_sync
.test
.mock_bug
import MockBug
2 from budget_sync
.budget_graph
import (BudgetGraphLoopError
, BudgetGraph
,
3 Node
, BudgetGraphMoneyWithNoMilestone
,
5 BudgetGraphMoneyMismatch
,
6 BudgetGraphNegativeMoney
,
7 BudgetGraphMilestoneMismatch
)
8 from budget_sync
.money
import Money
9 from typing
import List
, Type
13 class TestErrorFormatting(unittest
.TestCase
):
14 def test_budget_graph_loop_error(self
):
15 self
.assertEqual(str(BudgetGraphLoopError([1, 2, 3, 4, 5])),
16 "Detected Loop in Budget Graph: #5 -> #1 "
17 "-> #2 -> #3 -> #4 -> #5")
18 self
.assertEqual(str(BudgetGraphLoopError([1])),
19 "Detected Loop in Budget Graph: #1 -> #1")
21 def test_budget_graph_money_with_no_milestone(self
):
22 self
.assertEqual(str(BudgetGraphMoneyWithNoMilestone(1, 5)),
23 "Bug assigned money but without any assigned "
26 def test_budget_graph_milestone_mismatch(self
):
27 self
.assertEqual(str(BudgetGraphMilestoneMismatch(1, 5)),
28 "Bug's assigned milestone doesn't match the "
29 "milestone assigned to the root bug: descendant "
30 "bug #1, root bug #5")
32 def test_budget_graph_money_mismatch(self
):
33 self
.assertEqual(str(BudgetGraphMoneyMismatch(1, 5, "123.4")),
34 "Budget assigned to task excluding subtasks "
35 "(cf_budget field) doesn't match calculated value:"
36 " bug #1, calculated value 123.4")
38 def test_budget_graph_negative_money(self
):
39 self
.assertEqual(str(BudgetGraphNegativeMoney(1, 5)),
40 "Budget assigned to task is less than zero: bug #1")
43 EXAMPLE_BUG1
= MockBug(bug_id
=1,
44 cf_budget_parent
=None,
47 cf_nlnet_milestone
=None)
48 EXAMPLE_LOOP1_BUG1
= MockBug(bug_id
=1,
52 cf_nlnet_milestone
=None)
53 EXAMPLE_LOOP2_BUG1
= MockBug(bug_id
=1,
57 cf_nlnet_milestone
=None)
58 EXAMPLE_LOOP2_BUG2
= MockBug(bug_id
=2,
62 cf_nlnet_milestone
=None)
63 EXAMPLE_PARENT_BUG1
= MockBug(bug_id
=1,
64 cf_budget_parent
=None,
67 cf_nlnet_milestone
="abc")
68 EXAMPLE_CHILD_BUG2
= MockBug(bug_id
=2,
72 cf_nlnet_milestone
="abc")
75 class TestBudgetGraph(unittest
.TestCase
):
76 def assertErrorTypesMatches(self
, errors
: List
[BudgetGraphBaseError
], template
: List
[Type
]):
79 error_types
.append(type(error
))
80 self
.assertEqual(error_types
, template
)
84 self
.assertEqual(len(bg
.nodes
), 0)
85 self
.assertEqual(len(bg
.roots
), 0)
87 def test_single(self
):
88 bg
= BudgetGraph([EXAMPLE_BUG1
])
89 self
.assertEqual(len(bg
.nodes
), 1)
90 node
: Node
= bg
.nodes
[1]
91 self
.assertEqual(bg
.roots
, {node}
)
92 self
.assertIsInstance(node
, Node
)
93 self
.assertIs(node
.graph
, bg
)
94 self
.assertIs(node
.bug
, EXAMPLE_BUG1
)
95 self
.assertIs(node
.root
, node
)
96 self
.assertIsNone(node
.parent_id
)
97 self
.assertEqual(node
.immediate_children
, set())
98 self
.assertEqual(node
.budget_excluding_subtasks
, Money(cents
=0))
99 self
.assertEqual(node
.budget_including_subtasks
, Money(cents
=0))
100 self
.assertIsNone(node
.nlnet_milestone
)
102 def test_loop1(self
):
103 with self
.assertRaises(BudgetGraphLoopError
) as cm
:
104 BudgetGraph([EXAMPLE_LOOP1_BUG1
]).roots
105 self
.assertEqual(cm
.exception
.bug_ids
, [1])
107 def test_loop2(self
):
108 with self
.assertRaises(BudgetGraphLoopError
) as cm
:
109 BudgetGraph([EXAMPLE_LOOP2_BUG1
, EXAMPLE_LOOP2_BUG2
]).roots
110 self
.assertEqual(cm
.exception
.bug_ids
, [2, 1])
112 def test_parent_child(self
):
113 bg
= BudgetGraph([EXAMPLE_PARENT_BUG1
, EXAMPLE_CHILD_BUG2
])
114 self
.assertEqual(len(bg
.nodes
), 2)
115 node1
: Node
= bg
.nodes
[1]
116 node2
: Node
= bg
.nodes
[2]
117 self
.assertEqual(bg
.roots
, {node1}
)
118 self
.assertEqual(node1
, node1
)
119 self
.assertEqual(node2
, node2
)
120 self
.assertNotEqual(node1
, node2
)
121 self
.assertNotEqual(node2
, node1
)
122 self
.assertIsInstance(node1
, Node
)
123 self
.assertIs(node1
.graph
, bg
)
124 self
.assertIs(node1
.bug
, EXAMPLE_PARENT_BUG1
)
125 self
.assertIsNone(node1
.parent_id
)
126 self
.assertEqual(node1
.root
, node1
)
127 self
.assertEqual(node1
.immediate_children
, {node2}
)
128 self
.assertEqual(node1
.budget_excluding_subtasks
, Money(cents
=1000))
129 self
.assertEqual(node1
.budget_including_subtasks
, Money(cents
=2000))
130 self
.assertEqual(node1
.nlnet_milestone
, "abc")
131 self
.assertEqual(list(node1
.children()), [node2
])
132 self
.assertIsInstance(node2
, Node
)
133 self
.assertIs(node2
.graph
, bg
)
134 self
.assertIs(node2
.bug
, EXAMPLE_CHILD_BUG2
)
135 self
.assertEqual(node2
.parent_id
, 1)
136 self
.assertEqual(node2
.root
, node1
)
137 self
.assertEqual(node2
.immediate_children
, set())
138 self
.assertEqual(node2
.budget_excluding_subtasks
, Money(cents
=1000))
139 self
.assertEqual(node2
.budget_including_subtasks
, Money(cents
=1000))
140 self
.assertEqual(node2
.nlnet_milestone
, "abc")
142 def test_money_with_no_milestone(self
):
145 cf_budget_parent
=None,
147 cf_total_budget
="10",
148 cf_nlnet_milestone
=None),
150 errors
= bg
.get_errors()
151 self
.assertErrorTypesMatches(errors
,
152 [BudgetGraphMoneyWithNoMilestone
,
153 BudgetGraphMoneyMismatch
])
154 self
.assertEqual(errors
[0].bug_id
, 1)
155 self
.assertEqual(errors
[0].root_bug_id
, 1)
158 cf_budget_parent
=None,
161 cf_nlnet_milestone
=None),
163 errors
= bg
.get_errors()
164 self
.assertErrorTypesMatches(errors
,
165 [BudgetGraphMoneyWithNoMilestone
,
166 BudgetGraphMoneyMismatch
])
167 self
.assertEqual(errors
[0].bug_id
, 1)
168 self
.assertEqual(errors
[0].root_bug_id
, 1)
171 cf_budget_parent
=None,
173 cf_total_budget
="10",
174 cf_nlnet_milestone
=None),
176 errors
= bg
.get_errors()
177 self
.assertErrorTypesMatches(errors
, [BudgetGraphMoneyWithNoMilestone
])
178 self
.assertEqual(errors
[0].bug_id
, 1)
179 self
.assertEqual(errors
[0].root_bug_id
, 1)
181 def test_money_mismatch(self
):
184 cf_budget_parent
=None,
186 cf_total_budget
="10",
187 cf_nlnet_milestone
="abc"),
189 errors
= bg
.get_errors()
190 self
.assertErrorTypesMatches(errors
,
191 [BudgetGraphMoneyMismatch
])
192 self
.assertEqual(errors
[0].bug_id
, 1)
193 self
.assertEqual(errors
[0].root_bug_id
, 1)
194 self
.assertEqual(errors
[0].expected_budget_excluding_subtasks
, 10)
197 cf_budget_parent
=None,
200 cf_nlnet_milestone
="abc"),
202 errors
= bg
.get_errors()
203 self
.assertErrorTypesMatches(errors
,
204 [BudgetGraphMoneyMismatch
])
205 self
.assertEqual(errors
[0].bug_id
, 1)
206 self
.assertEqual(errors
[0].root_bug_id
, 1)
207 self
.assertEqual(errors
[0].expected_budget_excluding_subtasks
, 0)
210 cf_budget_parent
=None,
212 cf_total_budget
="10",
213 cf_nlnet_milestone
="abc"),
215 errors
= bg
.get_errors()
216 self
.assertEqual(errors
, [])
219 cf_budget_parent
=None,
221 cf_total_budget
="10",
222 cf_nlnet_milestone
="abc"),
226 cf_total_budget
="10",
227 cf_nlnet_milestone
="abc"),
231 cf_total_budget
="10",
232 cf_nlnet_milestone
="abc"),
234 errors
= bg
.get_errors()
235 self
.assertErrorTypesMatches(errors
,
236 [BudgetGraphMoneyMismatch
,
237 BudgetGraphMoneyMismatch
])
238 self
.assertEqual(errors
[0].bug_id
, 1)
239 self
.assertEqual(errors
[0].root_bug_id
, 1)
240 self
.assertEqual(errors
[0].expected_budget_excluding_subtasks
, -10)
241 self
.assertEqual(errors
[1].bug_id
, 3)
242 self
.assertEqual(errors
[1].root_bug_id
, 1)
243 self
.assertEqual(errors
[1].expected_budget_excluding_subtasks
, 10)
245 def test_negative_money(self
):
248 cf_budget_parent
=None,
250 cf_total_budget
="-10",
251 cf_nlnet_milestone
="abc"),
253 errors
= bg
.get_errors()
254 self
.assertErrorTypesMatches(errors
,
255 [BudgetGraphNegativeMoney
,
256 BudgetGraphMoneyMismatch
])
257 self
.assertEqual(errors
[0].bug_id
, 1)
258 self
.assertEqual(errors
[0].root_bug_id
, 1)
259 self
.assertEqual(errors
[1].bug_id
, 1)
260 self
.assertEqual(errors
[1].root_bug_id
, 1)
261 self
.assertEqual(errors
[1].expected_budget_excluding_subtasks
, -10)
264 cf_budget_parent
=None,
267 cf_nlnet_milestone
="abc"),
269 errors
= bg
.get_errors()
270 self
.assertErrorTypesMatches(errors
,
271 [BudgetGraphNegativeMoney
,
272 BudgetGraphMoneyMismatch
])
273 self
.assertEqual(errors
[0].bug_id
, 1)
274 self
.assertEqual(errors
[0].root_bug_id
, 1)
275 self
.assertEqual(errors
[1].bug_id
, 1)
276 self
.assertEqual(errors
[1].root_bug_id
, 1)
277 self
.assertEqual(errors
[1].expected_budget_excluding_subtasks
, 0)
280 cf_budget_parent
=None,
282 cf_total_budget
="-10",
283 cf_nlnet_milestone
="abc"),
285 errors
= bg
.get_errors()
286 self
.assertErrorTypesMatches(errors
,
287 [BudgetGraphNegativeMoney
])
288 self
.assertEqual(errors
[0].bug_id
, 1)
289 self
.assertEqual(errors
[0].root_bug_id
, 1)
292 if __name__
== "__main__":