feat: set up modularized version of project with testing
This commit is contained in:
commit
7bea08ddac
19 changed files with 1138 additions and 0 deletions
113
tests/test_output.py
Normal file
113
tests/test_output.py
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
import csv
|
||||
import io
|
||||
|
||||
import pytest
|
||||
|
||||
from timesheets.output import print_summary, write_csv
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Shared fixtures
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
PROJECT_MAP = {
|
||||
"bugs": {"Project": "[Factry] Historian", "Task": "[Historian] Bugs"},
|
||||
}
|
||||
|
||||
AGGREGATED = [
|
||||
{"project": "bugs", "description": "ticket 1", "quantity": 1.0},
|
||||
{"project": "bugs", "description": "ticket 2", "quantity": 0.5},
|
||||
{"project": "scrum", "description": "dsu", "quantity": 0.25},
|
||||
]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# write_csv
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestWriteCsv:
|
||||
def _run(self, aggregated=None, date_str="22/03/26", project_map=None):
|
||||
buf = io.StringIO()
|
||||
write_csv(
|
||||
aggregated or AGGREGATED,
|
||||
buf,
|
||||
date_str,
|
||||
project_map or {},
|
||||
)
|
||||
buf.seek(0)
|
||||
return list(csv.reader(buf))
|
||||
|
||||
def test_header_row(self):
|
||||
rows = self._run()
|
||||
assert rows[0] == ["Date*", "Project*", "Task", "Description", "Quantity"]
|
||||
|
||||
def test_row_count(self):
|
||||
rows = self._run()
|
||||
assert len(rows) == 1 + len(AGGREGATED)
|
||||
|
||||
def test_date_column(self):
|
||||
rows = self._run(date_str="01/01/26")
|
||||
assert all(r[0] == "01/01/26" for r in rows[1:])
|
||||
|
||||
def test_quantity_format(self):
|
||||
rows = self._run()
|
||||
assert rows[1][4] == "1.00"
|
||||
assert rows[2][4] == "0.50"
|
||||
|
||||
def test_project_map_applied(self):
|
||||
rows = self._run(project_map=PROJECT_MAP)
|
||||
assert rows[1][1] == "[Factry] Historian"
|
||||
assert rows[1][2] == "[Historian] Bugs"
|
||||
|
||||
def test_unmapped_project_fallback(self):
|
||||
rows = self._run(project_map=PROJECT_MAP)
|
||||
# "scrum" is not in the map
|
||||
scrum_row = next(r for r in rows[1:] if "dsu" in r)
|
||||
assert scrum_row[1] == "scrum"
|
||||
assert scrum_row[2] == ""
|
||||
|
||||
def test_description_column(self):
|
||||
rows = self._run()
|
||||
assert rows[1][3] == "ticket 1"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# print_summary
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestPrintSummary:
|
||||
def _run(self, aggregated=None, project_map=None, capsys=None):
|
||||
print_summary(aggregated or AGGREGATED, project_map or {})
|
||||
return capsys.readouterr().out
|
||||
|
||||
def test_contains_project_label(self, capsys):
|
||||
out = self._run(capsys=capsys)
|
||||
assert "scrum" in out
|
||||
|
||||
def test_contains_mapped_project_label(self, capsys):
|
||||
out = self._run(project_map=PROJECT_MAP, capsys=capsys)
|
||||
assert "[Factry] Historian" in out
|
||||
assert "[Historian] Bugs" in out
|
||||
|
||||
def test_contains_description(self, capsys):
|
||||
out = self._run(capsys=capsys)
|
||||
assert "ticket 1" in out
|
||||
assert "dsu" in out
|
||||
|
||||
def test_contains_total(self, capsys):
|
||||
out = self._run(capsys=capsys)
|
||||
assert "TOTAL" in out
|
||||
# 1.0 + 0.5 + 0.25 = 1.75 hours = 01:45
|
||||
assert "01:45" in out
|
||||
|
||||
def test_project_subtotal(self, capsys):
|
||||
out = self._run(capsys=capsys)
|
||||
# bugs total = 1.0 + 0.5 = 1.5 hours = 01:30
|
||||
assert "01:30" in out
|
||||
|
||||
def test_hhmm_durations_shown(self, capsys):
|
||||
out = self._run(capsys=capsys)
|
||||
assert "01:00" in out
|
||||
assert "00:30" in out
|
||||
assert "00:15" in out
|
||||
Loading…
Add table
Add a link
Reference in a new issue