From 06606e8d0d391700587ffab8aec152a5c7547d91 Mon Sep 17 00:00:00 2001 From: S4NKALP Date: Sat, 6 Jun 2026 21:52:10 +0545 Subject: [PATCH] feat(django_nepkit/tests): add cache behavior tests and render options improvementsAdds tests for cache hits, passthrough, and safe option rendering. --- django_nepkit/tests/test_models.py | 61 ++++++++++++++++++++++++++++++ django_nepkit/tests/test_views.py | 32 ++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/django_nepkit/tests/test_models.py b/django_nepkit/tests/test_models.py index 0a6d0dc..cfe86cb 100644 --- a/django_nepkit/tests/test_models.py +++ b/django_nepkit/tests/test_models.py @@ -307,3 +307,64 @@ class TestNepaliTimeField: def test_format_value_for_display(self): field = NepaliTimeField() assert field.format_value_for_display(python_time(9, 5)) == "09:05 AM" + + +class TestParseCache: + """``BaseNepaliBSField._parse_str`` should hit a process-level cache.""" + + def test_repeated_parse_hits_cache(self): + from django_nepkit.utils import ( + _cached_parse_nepali_date, + _cached_parse_nepali_datetime, + ) + + _cached_parse_nepali_date.cache_clear() + _cached_parse_nepali_datetime.cache_clear() + + field = NepaliDateField() + # First call: cache miss. + first = field._parse_str("2081-01-15") + info = _cached_parse_nepali_date.cache_info() + assert info.misses == 1 + assert info.hits == 0 + # Second call with the same string: cache hit. + second = field._parse_str("2081-01-15") + info = _cached_parse_nepali_date.cache_info() + assert info.hits == 1 + assert first is second # cached object reused + + def test_datetime_field_uses_datetime_cache(self): + from django_nepkit.utils import ( + _cached_parse_nepali_date, + _cached_parse_nepali_datetime, + ) + + _cached_parse_nepali_date.cache_clear() + _cached_parse_nepali_datetime.cache_clear() + + field = NepaliDateTimeField() + result = field._parse_str("2081-01-15 10:30:00") + assert isinstance(result, nepalidatetime) + date_info = _cached_parse_nepali_date.cache_info() + dt_info = _cached_parse_nepali_datetime.cache_info() + assert dt_info.misses == 1 + # The date cache must NOT have been touched. + assert date_info.misses == 0 + + def test_unparseable_input_caches_none(self): + from django_nepkit.utils import _cached_parse_nepali_date + + _cached_parse_nepali_date.cache_clear() + field = NepaliDateField() + a = field._parse_str("not-a-date") + b = field._parse_str("not-a-date") + assert a is None + assert b is None + info = _cached_parse_nepali_date.cache_info() + # Both calls count as cache hits/misses against the same key. + assert info.hits >= 1 + + def test_non_string_passthrough(self): + field = NepaliDateField() + assert field._parse_str(None) is None + assert field._parse_str(2081) is None # ints bypass the cache diff --git a/django_nepkit/tests/test_views.py b/django_nepkit/tests/test_views.py index c93284e..e5fa76d 100644 --- a/django_nepkit/tests/test_views.py +++ b/django_nepkit/tests/test_views.py @@ -76,6 +76,38 @@ class TestRenderOptions: assert "" not in html assert "<script>" in html + def test_missing_keys_use_empty_string(self): + """Items missing ``id`` / ``text`` render an empty option, not a crash.""" + from django_nepkit.views import _render_options + + data = [{"id": "KTM"}, {"text": "Only Text"}, {}] + response = _render_options(data, "Select") + html = response.content.decode() + assert 'value="KTM"' in html + assert ">Only Text<" in html + # The empty item should still produce a (value-less) option. + assert html.count("= 3 + + def test_non_dict_item_does_not_crash(self): + """Malformed rows (e.g. a stray string) are silently skipped.""" + from django_nepkit.views import _render_options + + data = ["not-a-dict", {"id": "KTM", "text": "KTM"}, None, 42] + response = _render_options(data, "Select") + html = response.content.decode() + assert 'value="KTM"' in html + + def test_escapes_quote_breakout_in_id_attribute(self): + """A ``">', "text": "x"}] + response = _render_options(data, "Select") + html = response.content.decode() + assert 'value=""' not in html or """ in html + assert "