"""Timestamp boundaries and UI translation coverage without HA dependencies.""" import importlib.util import json import unittest from datetime import datetime, timedelta, timezone from pathlib import Path ROOT = Path(__file__).resolve().parents[1] / 'custom_components' / 'heating_mpc' spec = importlib.util.spec_from_file_location('quality', ROOT / 'data_quality.py') quality = importlib.util.module_from_spec(spec) spec.loader.exec_module(quality) spec = importlib.util.spec_from_file_location('heating_mpc_const', ROOT / 'const.py') const = importlib.util.module_from_spec(spec) spec.loader.exec_module(const) class FreshnessTests(unittest.TestCase): def test_age_boundaries(self): now = datetime(2026, 10, 26, tzinfo=timezone.utc) for seconds, expected in ((0, 'valid'), (1800, 'valid'), (1801, 'stale'), (-1, 'future_timestamp')): with self.subTest(seconds=seconds): result = quality.freshness(now - timedelta(seconds=seconds), now, 1800) self.assertEqual(result['status'], expected) self.assertEqual(result['age_seconds'], seconds) def test_missing_naive_and_malformed_times(self): now = datetime.now(timezone.utc) for timestamp in (None, 'bad', datetime.now()): self.assertEqual(quality.freshness(timestamp, now, 1800)['status'], 'invalid_timestamp') def test_invalid_limits_rejected(self): now = datetime.now(timezone.utc) for limit in (0, -1, float('inf'), float('nan')): with self.assertRaises(ValueError): quality.freshness(now, now, limit) def test_report_age_history_keeps_24_hour_maximum(self): history = quality.ReportAgeHistory() start = datetime(2026, 10, 26, tzinfo=timezone.utc) self.assertEqual(history.observe('sensor.a', start, 2400), 2400) self.assertEqual(history.observe('sensor.b', start, 60), 60) for minutes in range(5, 24 * 60, 5): result = history.observe('sensor.a', start + timedelta(minutes=minutes), 300) self.assertEqual(result, 2400) # still inside the 24-hour window later = start + timedelta(hours=24, minutes=5) self.assertEqual(history.observe('sensor.a', later, 300), 300) self.assertEqual(history.observe('sensor.b', later, 30), 30) def test_freshness_settings_translated(self): for name in ('strings.json', 'translations/en.json', 'translations/ro.json'): data = json.loads((ROOT / name).read_text()) for section, step in (('config', 'user'), ('options', 'init')): labels = data[section]['step'][step]['data'] for key in ('room_max_age_minutes', 'weather_max_age_minutes', 'room_stale_use_last_value'): self.assertTrue(labels[key]) help_text = data[section]['step'][step]['data_description'] self.assertIn('24', help_text['room_stale_use_last_value']) # Every poll outcome has a translated state name. states = data['entity']['sensor']['last_sample']['state'] self.assertEqual(set(states), set(const.SAMPLE_RESULTS))