-from typing import Optional
+from typing import Optional, Union
+from budget_sync.util import BugStatus
class MockBug:
def __init__(self,
bug_id: int,
- cf_budget_parent: Optional[int],
- cf_budget: str,
- cf_total_budget: str,
- cf_nlnet_milestone: Optional[str],
- cf_payees_list: str,
- summary: str):
+ cf_budget_parent: Optional[int] = None,
+ cf_budget: str = "0",
+ cf_total_budget: str = "0",
+ cf_nlnet_milestone: Optional[str] = None,
+ cf_payees_list: str = "",
+ summary: str = "<default summary>",
+ status: Union[str, BugStatus] = BugStatus.CONFIRMED):
self.id = bug_id
- if cf_budget_parent is not None:
- self.cf_budget_parent = cf_budget_parent
+ self.__budget_parent = cf_budget_parent
self.cf_budget = cf_budget
self.cf_total_budget = cf_total_budget
if cf_nlnet_milestone is None:
self.cf_nlnet_milestone = cf_nlnet_milestone
self.cf_payees_list = cf_payees_list
self.summary = summary
+ self.status = str(status)
+
+ @property
+ def cf_budget_parent(self) -> int:
+ if self.__budget_parent is None:
+ raise AttributeError(
+ "'MockBug' object has no attribute 'cf_budget_parent'")
+ return self.__budget_parent
+
+ @cf_budget_parent.setter
+ def cf_budget_parent(self, value: int):
+ if isinstance(value, int):
+ self.__budget_parent = value
+ else:
+ raise TypeError("cf_budget_parent must be an int")
+
+ @cf_budget_parent.deleter
+ def cf_budget_parent(self):
+ self.cf_budget_parent # trigger AttributeError if property cleared
+ self.__budget_parent = None
def __repr__(self):
cf_budget_parent = getattr(self, "cf_budget_parent", None)
+ status = BugStatus.cast(self.status, unknown_allowed=True)
return (f"MockBug(bug_id={self.id!r}, "
f"cf_budget_parent={cf_budget_parent!r}, "
f"cf_budget={self.cf_budget!r}, "
f"cf_total_budget={self.cf_total_budget!r}, "
f"cf_nlnet_milestone={self.cf_nlnet_milestone!r}, "
f"cf_payees_list={self.cf_payees_list!r}, "
- f"summary={self.summary!r})")
+ f"summary={self.summary!r}, "
+ f"status={status!r})")
--- /dev/null
+import unittest
+from budget_sync.test.mock_bug import MockBug
+from budget_sync.util import BugStatus
+
+
+class TestBugStatus(unittest.TestCase):
+ def test_values(self):
+ for i in BugStatus:
+ self.assertIs(i, getattr(BugStatus, i.value))
+ self.assertEqual(str(i), i.value)
+ self.assertEqual(repr(i), f"BugStatus.{i.value}")
+
+ def test_cast(self):
+ for i in BugStatus:
+ self.assertEqual(i, BugStatus.cast(i))
+ self.assertEqual(i, BugStatus.cast(str(i)))
+ self.assertEqual(i, BugStatus.cast(str(i), unknown_allowed=True))
+ with self.assertRaises(ValueError):
+ BugStatus.cast("<unknown>")
+ self.assertEqual("<unknown>",
+ BugStatus.cast("<unknown>", unknown_allowed=True))
+
+
+class TestMockBug(unittest.TestCase):
+ maxDiff = None
+
+ def test_repr(self):
+ bug = MockBug(bug_id=12)
+ self.assertEqual(
+ repr(bug),
+ "MockBug(bug_id=12, cf_budget_parent=None, cf_budget='0', "
+ "cf_total_budget='0', cf_nlnet_milestone='---', "
+ "cf_payees_list='', summary='<default summary>', "
+ "status=BugStatus.CONFIRMED)")
+ bug = MockBug(bug_id=34,
+ cf_budget_parent=1,
+ cf_budget="45",
+ cf_total_budget="23",
+ cf_nlnet_milestone="abc",
+ cf_payees_list="# a",
+ summary="blah blah",
+ status="blah")
+ self.assertEqual(
+ repr(bug),
+ "MockBug(bug_id=34, cf_budget_parent=1, cf_budget='45', "
+ "cf_total_budget='23', cf_nlnet_milestone='abc', "
+ "cf_payees_list='# a', summary='blah blah', status='blah')")
+
+ def test_cf_budget_parent(self):
+ bug = MockBug(bug_id=1, cf_budget_parent=None)
+ with self.assertRaises(AttributeError):
+ bug.cf_budget_parent
+ self.assertIsNone(getattr(bug, "cf_budget_parent", None))
+ bug.cf_budget_parent = 1
+ self.assertEqual(bug.cf_budget_parent, 1)
+ with self.assertRaises(TypeError):
+ bug.cf_budget_parent = "abc"
+ del bug.cf_budget_parent
+ with self.assertRaises(AttributeError):
+ bug.cf_budget_parent
+ with self.assertRaises(AttributeError):
+ del bug.cf_budget_parent
+ with self.assertRaises(AttributeError):
+ bug.cf_budget_parent
+ bug.cf_budget_parent = 5
+ self.assertEqual(bug.cf_budget_parent, 5)
+ bug = MockBug(bug_id=1, cf_budget_parent=2)
+ self.assertEqual(bug.cf_budget_parent, 2)
+
+
+if __name__ == "__main__":
+ unittest.main()
from bugzilla import Bugzilla
from bugzilla.bug import Bug
-from typing import Iterator
+from typing import Iterator, Union
+from enum import Enum
+
+
+class BugStatus(Enum):
+ UNCONFIRMED = "UNCONFIRMED"
+ CONFIRMED = "CONFIRMED"
+ IN_PROGRESS = "IN_PROGRESS"
+ DEFERRED = "DEFERRED"
+ RESOLVED = "RESOLVED"
+ VERIFIED = "VERIFIED"
+ PAYMENTPENDING = "PAYMENTPENDING"
+
+ def __str__(self):
+ return self.value
+
+ def __repr__(self):
+ return f"BugStatus.{self.value}"
+
+ @staticmethod
+ def cast(v: Union[str, "BugStatus"],
+ unknown_allowed: bool = False) -> Union[str, "BugStatus"]:
+ s = str(v)
+ try:
+ return BugStatus(s)
+ except ValueError:
+ if unknown_allowed:
+ return s
+ raise
def all_bugs(bz: Bugzilla) -> Iterator[Bug]: