from datetime import date, datetime, time, timedelta, timezone as dt_timezone import jdatetime from django.test import TestCase, override_settings from apps.core.jalali import jalali_date, jalali_datetime, jalali_time from apps.core.settings_service import SettingsService class SettingsServiceTests(TestCase): def test_get_returns_schema_default(self): service = SettingsService() self.assertEqual(service.get("sms.provider"), "mock") self.assertIs(service.get("odoo.enabled"), False) self.assertEqual(service.get("camera.default_protocol"), "hls") self.assertIs(service.get("camera.enabled"), True) def test_set_and_get(self): service = SettingsService() service.set("odoo.url", "https://odoo.example.com") self.assertEqual(service.get("odoo.url"), "https://odoo.example.com") def test_secrets_are_masked(self): service = SettingsService() service.set("odoo.api_key", "super-secret") values = service.all_values() self.assertEqual(values["odoo.api_key"], "••••••") def test_camera_protocol_settings_are_in_schema(self): from apps.core.settings_registry import SETTINGS_SCHEMA keys = {e["key"] for e in SETTINGS_SCHEMA} self.assertIn("camera.default_protocol", keys) self.assertIn("camera.rtsp.transport", keys) self.assertIn("camera.webrtc.ice_servers", keys) proto = next(e for e in SETTINGS_SCHEMA if e["key"] == "camera.default_protocol") self.assertTrue(any(isinstance(o, dict) and o.get("value") == "rtsp" for o in proto["options"])) rtsp_transport = next(e for e in SETTINGS_SCHEMA if e["key"] == "camera.rtsp.transport") self.assertEqual(rtsp_transport["depends_on"], {"camera.default_protocol": ["rtsp"]}) class JalaliTests(TestCase): """The PDF and the customer SMS are the only places dates are rendered for humans; the API itself stays on ISO-8601.""" def test_known_reference_dates(self): self.assertEqual(jalali_date(date(2026, 3, 21)), "1405/01/01") # Nowruz 1405 self.assertEqual(jalali_date(date(2026, 3, 14)), "1404/12/23") self.assertEqual(jalali_date(date(1979, 2, 11)), "1357/11/22") def test_round_trips_against_jdatetime_over_two_decades(self): """A conversion error here silently misdates a quality report.""" day = date(2020, 1, 1) end = date(2040, 1, 1) while day < end: expected = jdatetime.date.fromgregorian(date=day) self.assertEqual( jalali_date(day), f"{expected.year:04d}/{expected.month:02d}/{expected.day:02d}", ) day += timedelta(days=1) def test_accepts_iso_strings(self): self.assertEqual(jalali_date("2026-03-14"), "1404/12/23") self.assertEqual(jalali_datetime("2026-03-14T05:00:00+00:00")[:10], "1404/12/23") def test_blank_and_malformed_input_is_empty_not_an_error(self): for value in (None, "", "not-a-date", 0): self.assertEqual(jalali_date(value), "") self.assertEqual(jalali_datetime(value), "") @override_settings(TIME_ZONE="Asia/Tehran") def test_aware_datetimes_render_in_the_project_time_zone(self): # 20:30Z is already the next calendar day in Tehran (+03:30). moment = datetime(2026, 3, 14, 20, 30, tzinfo=dt_timezone.utc) self.assertEqual(jalali_datetime(moment), "1404/12/24 00:00") @override_settings(TIME_ZONE="UTC") def test_aware_datetimes_follow_the_configured_zone(self): moment = datetime(2026, 3, 14, 20, 30, tzinfo=dt_timezone.utc) self.assertEqual(jalali_datetime(moment), "1404/12/23 20:30") def test_naive_datetimes_are_left_alone(self): self.assertEqual(jalali_datetime(datetime(2026, 3, 14, 8, 5)), "1404/12/23 08:05") def test_times(self): self.assertEqual(jalali_time(time(8, 0)), "08:00") self.assertEqual(jalali_time("08:30:15"), "08:30") self.assertEqual(jalali_time("09:05"), "09:05") self.assertEqual(jalali_time(""), "")