Skip to content

Commit 4ffb275

Browse files
authored
Merge pull request #10 from tempus2016/claude/analyze-test-coverage-LkM4P
Fix four bugs found during code audit
2 parents f314d6c + d995978 commit 4ffb275

4 files changed

Lines changed: 33 additions & 8 deletions

File tree

custom_components/taskmate/coordinator.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ def is_chore_available_for_child(self, chore, child_id: str) -> bool:
390390

391391
try:
392392
last_dt = date.fromisoformat(current_iso[:10])
393-
except ValueError:
393+
except (ValueError, TypeError):
394394
return True
395395

396396
# every_2_days with anchor — check alignment
@@ -676,10 +676,7 @@ async def async_approve_reward(self, claim_id: str) -> None:
676676

677677
async def async_reject_reward(self, claim_id: str) -> None:
678678
"""Reject a reward claim — no refund needed as points were never deducted."""
679-
self.storage._data["reward_claims"] = [
680-
c for c in self.storage._data.get("reward_claims", [])
681-
if c.get("id") != claim_id
682-
]
679+
self.storage.remove_reward_claim(claim_id)
683680
await self.storage.async_save()
684681
await self.async_refresh()
685682

custom_components/taskmate/sensor.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,22 @@
2323
_LOGGER = logging.getLogger(__name__)
2424

2525

26+
def _safe_float(value, default: float) -> float:
27+
"""Convert value to float, returning default on failure."""
28+
try:
29+
return float(value) if value is not None else default
30+
except (ValueError, TypeError):
31+
return default
32+
33+
34+
def _safe_int(value, default: int) -> int:
35+
"""Convert value to int, returning default on failure."""
36+
try:
37+
return int(value) if value is not None else default
38+
except (ValueError, TypeError):
39+
return default
40+
41+
2642
async def async_setup_entry(
2743
hass: HomeAssistant,
2844
entry: ConfigEntry,
@@ -147,7 +163,7 @@ def extra_state_attributes(self) -> dict:
147163
"completion_id": comp.id,
148164
"chore_id": comp.chore_id,
149165
"child_id": comp.child_id,
150-
"child_name": child_lookup.get(comp.child_id, None) and child_lookup[comp.child_id].name or "",
166+
"child_name": child_lookup[comp.child_id].name if comp.child_id in child_lookup else "",
151167
"chore_name": matched_chore.name if matched_chore else "",
152168
"points": matched_chore.points if matched_chore else 0,
153169
"approved": comp.approved,
@@ -231,11 +247,11 @@ def extra_state_attributes(self) -> dict:
231247
return {
232248
"today_day_of_week": today_dow,
233249
"streak_reset_mode": data.get("settings", {}).get("streak_reset_mode", "reset"),
234-
"weekend_multiplier": float(data.get("settings", {}).get("weekend_multiplier", "2.0") or "2.0"),
250+
"weekend_multiplier": _safe_float(data.get("settings", {}).get("weekend_multiplier"), 2.0),
235251
"streak_milestones_enabled": data.get("settings", {}).get("streak_milestones_enabled", "true") == "true",
236252
"streak_milestones": data.get("settings", {}).get("streak_milestones", "3:5, 7:10, 14:20, 30:50, 60:100, 100:200"),
237253
"perfect_week_enabled": data.get("settings", {}).get("perfect_week_enabled", "true") == "true",
238-
"perfect_week_bonus": int(data.get("settings", {}).get("perfect_week_bonus", "50") or "50"),
254+
"perfect_week_bonus": _safe_int(data.get("settings", {}).get("perfect_week_bonus"), 50),
239255
"total_children": len(children),
240256
"total_chores": len(chores),
241257
"total_rewards": len(rewards),

custom_components/taskmate/storage.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,12 @@ def update_reward_claim(self, claim: RewardClaim) -> None:
277277
claims[i] = claim.to_dict()
278278
return
279279

280+
def remove_reward_claim(self, claim_id: str) -> None:
281+
"""Remove a reward claim."""
282+
self._data["reward_claims"] = [
283+
c for c in self._data.get("reward_claims", []) if c.get("id") != claim_id
284+
]
285+
280286
# Points transactions management
281287
def get_points_transactions(self) -> list[PointsTransaction]:
282288
"""Get all points transactions."""

tests/test_coordinator_rewards.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ def _make_coord(*, children=None, rewards=None, claims=None):
4343
storage.async_save = AsyncMock()
4444
storage._data = {"reward_claims": [c.to_dict() for c in _claims]}
4545

46+
def _remove_reward_claim(claim_id):
47+
storage._data["reward_claims"] = [
48+
c for c in storage._data["reward_claims"] if c.get("id") != claim_id
49+
]
50+
storage.remove_reward_claim = MagicMock(side_effect=_remove_reward_claim)
51+
4652
coord.storage = storage
4753
coord.async_refresh = AsyncMock()
4854
return coord

0 commit comments

Comments
 (0)