Files
sankalp 0268bcfe98 chore(root): remove DRF and django-filter dependencies
drop DRF and django-filter to make django_nepkit framework‑agnostic, simplify dependencies, and align with v0.2.2 breaking change.
2026-06-06 21:06:03 +05:45

246 lines
8.2 KiB
Python

"""
Tests for the framework-agnostic serialization helpers in ``django_nepkit.api``.
"""
from datetime import datetime as python_datetime, time as python_time
from decimal import Decimal
import pytest
from nepali.datetime import nepalidate, nepalidatetime
from django_nepkit.api import (
_looks_numeric,
build_localized_payload,
deserialize_nepali_currency,
deserialize_nepali_date,
deserialize_nepali_datetime,
deserialize_nepali_time,
serialize_nepali_currency,
serialize_nepali_date,
serialize_nepali_datetime,
serialize_nepali_time,
to_decimal,
)
class TestSerializeNepaliDate:
def test_none_passthrough(self):
assert serialize_nepali_date(None) is None
def test_serializes_nepalidate(self):
assert serialize_nepali_date(nepalidate(2081, 1, 15)) == "2081-01-15"
def test_serializes_string_input(self):
assert serialize_nepali_date("2081-01-15") == "2081-01-15"
def test_ne_flag_uses_devanagari(self):
assert "२०८१" in serialize_nepali_date(nepalidate(2081, 1, 15), ne=True)
def test_custom_format(self):
assert (
serialize_nepali_date(nepalidate(2081, 1, 15), fmt="%Y/%m/%d")
== "2081/01/15"
)
def test_strict_raises_on_garbage(self):
with pytest.raises(ValueError, match="Cannot serialize"):
serialize_nepali_date("not-a-date", strict=True)
def test_non_strict_returns_str(self):
"""Non-strict mode is a passthrough so existing integrations don't break."""
assert serialize_nepali_date("not-a-date") == "not-a-date"
class TestDeserializeNepaliDate:
def test_none(self):
assert deserialize_nepali_date(None) is None
def test_empty_string(self):
assert deserialize_nepali_date("") is None
def test_round_trip(self):
result = deserialize_nepali_date("2081-01-15")
assert isinstance(result, nepalidate)
assert result.year == 2081
def test_strict_raises_on_garbage(self):
with pytest.raises(ValueError, match="Cannot parse"):
deserialize_nepali_date("not-a-date", strict=True)
def test_strict_raises_on_wrong_type(self):
with pytest.raises(ValueError, match="Cannot parse"):
deserialize_nepali_date(12345, strict=True)
class TestSerializeNepaliDatetime:
def test_serializes(self):
assert (
serialize_nepali_datetime(nepalidatetime(2081, 1, 15, 14, 30))
== "2081-01-15 14:30:00"
)
def test_ne_flag(self):
result = serialize_nepali_datetime(nepalidatetime(2081, 1, 15, 14, 30), ne=True)
assert "२०८१" in result
class TestDeserializeNepaliDatetime:
def test_round_trip(self):
result = deserialize_nepali_datetime("2081-01-15 14:30:00")
assert isinstance(result, nepalidatetime)
assert result.hour == 14
def test_strict_raises_on_garbage(self):
with pytest.raises(ValueError, match="Cannot parse"):
deserialize_nepali_datetime("not-a-datetime", strict=True)
class TestSerializeNepaliTime:
def test_none(self):
assert serialize_nepali_time(None) is None
def test_serializes_time(self):
assert serialize_nepali_time(python_time(14, 30)) == "02:30 PM"
def test_ne_flag(self):
result = serialize_nepali_time(python_time(14, 30), ne=True)
assert "०२" in result
def test_strict_raises_on_garbage(self):
with pytest.raises(ValueError, match="Cannot serialize"):
serialize_nepali_time("not-a-time", strict=True)
class TestDeserializeNepaliTime:
def test_round_trip(self):
result = deserialize_nepali_time("02:30 PM")
assert isinstance(result, python_time)
assert result.hour == 14
assert result.minute == 30
def test_from_datetime(self):
result = deserialize_nepali_time(python_datetime(2024, 1, 1, 9, 0))
assert result == python_time(9, 0)
def test_strict_raises_on_garbage(self):
with pytest.raises(ValueError, match="Cannot parse"):
deserialize_nepali_time("not-a-time", strict=True)
class TestSerializeNepaliCurrency:
def test_none(self):
assert serialize_nepali_currency(None) is None
def test_formats_with_symbol(self):
assert serialize_nepali_currency(1234567) == "Rs. 12,34,567.00"
def test_no_symbol(self):
assert serialize_nepali_currency(1234567, currency_symbol="") == "12,34,567.00"
def test_ne_flag(self):
assert "१२" in serialize_nepali_currency(12, ne=True)
def test_preserves_decimal_precision(self):
value = Decimal("123456789012345.67")
assert "12,34,56,78,90,12,345.67" in serialize_nepali_currency(value)
def test_non_numeric_string_passthrough(self):
"""Non-numeric strings are passed through so legacy callers don't crash."""
assert serialize_nepali_currency("n/a") == "n/a"
class TestDeserializeNepaliCurrency:
def test_none(self):
assert deserialize_nepali_currency(None) is None
def test_passes_through_numbers(self):
assert deserialize_nepali_currency(1234) == 1234
assert deserialize_nepali_currency(Decimal("12.50")) == Decimal("12.50")
def test_parses_formatted_string(self):
result = deserialize_nepali_currency("Rs. 12,34,567.00")
assert isinstance(result, Decimal)
assert result == Decimal("1234567.00")
def test_parses_nepali_digits(self):
result = deserialize_nepali_currency("Rs. १२,३४५")
assert isinstance(result, Decimal)
assert result == Decimal("12345")
def test_strict_raises_on_invalid_string(self):
with pytest.raises(ValueError, match="Cannot parse"):
deserialize_nepali_currency("not-a-number", strict=True)
class TestToDecimal:
def test_none(self):
assert to_decimal(None) is None
def test_decimal_passthrough(self):
assert to_decimal(Decimal("1.5")) == Decimal("1.5")
def test_int(self):
assert to_decimal(42) == Decimal("42")
def test_string(self):
assert to_decimal("12.34") == Decimal("12.34")
def test_invalid_string_returns_input(self):
assert to_decimal("not-a-number") == "not-a-number"
def test_strict_raises_on_invalid_string(self):
with pytest.raises(ValueError, match="Cannot convert"):
to_decimal("not-a-number", strict=True)
def test_strict_raises_on_bool(self):
with pytest.raises(ValueError, match="boolean"):
to_decimal(True, strict=True)
def test_strict_raises_on_non_finite(self):
with pytest.raises(ValueError, match="non-finite"):
to_decimal(float("inf"), strict=True)
class TestLooksNumeric:
def test_rejects_infinity_strings(self):
"""``1e1000`` overflows to ``inf`` and must be rejected."""
assert _looks_numeric("1e1000") is False
assert _looks_numeric("inf") is False
assert _looks_numeric("nan") is False
def test_accepts_plain_numbers(self):
assert _looks_numeric("1234") is True
assert _looks_numeric("-12.5") is True
assert _looks_numeric("1,234.5") is True
def test_rejects_empty_and_garbage(self):
assert _looks_numeric("") is False
assert _looks_numeric("abc") is False
assert _looks_numeric("12abc") is False
class TestBuildLocalizedPayload:
def test_disabled_returns_input(self):
data = {"a": 1}
assert build_localized_payload(data, ne=False) == {"a": 1}
def test_mirrors_nepalidate(self):
data = {"date": nepalidate(2080, 1, 1)}
out = build_localized_payload(data, ne=True, raw_values=data)
assert out["date_ne"] == "२०८०-०१-०१"
def test_mirrors_currency(self):
data = {"amount": 100000}
out = build_localized_payload(data, ne=True)
assert "१" in out["amount_ne"]
def test_does_not_overwrite_existing(self):
data = {"amount": 100, "amount_ne": "preexisting"}
out = build_localized_payload(data, ne=True)
assert out["amount_ne"] == "preexisting"
def test_no_mirror_when_ne_false(self):
data = {"date": nepalidate(2080, 1, 1)}
out = build_localized_payload(data, ne=False, raw_values=data)
assert "date_ne" not in out