# -*- coding: utf-8 -*-
#
# badidatetime/test/test_timedateutils.py
#
__docformat__ = "restructuredtext en"
import os
import sys
import locale
import importlib
import unittest
from zoneinfo import ZoneInfo
from unittest.mock import patch, PropertyMock
PWD = os.path.dirname(os.path.abspath(__file__))
BASE_DIR = os.path.dirname(os.path.dirname(PWD))
sys.path.append(BASE_DIR)
from .._timedateutils import TimeDateUtils
datetime = importlib.import_module('badidatetime.datetime')
[docs]
class TestTimeDateUtils(unittest.TestCase):
"""
Notes on running these tests. If you live outside of the USA you may need
to install the USA local info on your computer or some tests will fail.
There is no way to test for changing local information when most tests
are hard coded.
"""
def __init__(self, name):
super().__init__(name)
[docs]
def setUp(self):
self.locale_patcher = patch(
'badidatetime._timedateutils.locale.nl_langinfo')
self.mock_nl_langinfo = self.locale_patcher.start()
def side_effect(item):
if item == locale.LC_TIME:
return 'en_US.UTF-8'
elif item == locale.AM_STR:
return 'AM'
elif item == locale.PM_STR:
return 'PM'
elif item == locale.D_FMT:
return '%m/%d/%Y'
elif item == locale.T_FMT:
return '%H:%M:%S'
else:
return 'Default Value'
self.mock_nl_langinfo.side_effect = side_effect
self._tdu = TimeDateUtils()
[docs]
def tearDown(self):
self.locale_patcher.stop()
#@unittest.skip("Temporarily skipped")
#@unittest.skip("Temporarily skipped")
[docs]
def test__find_time_order(self):
"""
Test that the _find_time_order method parses the time format properly.
"""
expected = '%I:%M:%S'
result = self._tdu._find_time_order()
msg = f"Expected {expected}, found {result}."
self.assertEqual(expected, result, msg)
#@unittest.skip("Temporarily skipped")
[docs]
def test_locale(self):
"""
Test that the locale property is set correctly.
"""
expected = "en_US.UTF-8"
result = self._tdu.locale
msg = f"Expected {expected}, found {result}."
self.assertEqual(expected, result, msg)
#@unittest.skip("Temporarily skipped")
[docs]
def test_am(self):
"""
Test that the am property is set correctly
"""
expected = 'AM'
result = self._tdu.am
msg = f"Expected {expected}, found {result}."
self.assertEqual(expected, result, msg)
#@unittest.skip("Temporarily skipped")
[docs]
def test_pm(self):
"""
Test that the pm property is set correctly
"""
expected = 'PM'
result = self._tdu.pm
msg = f"Expected {expected}, found {result}."
self.assertEqual(expected, result, msg)
#@unittest.skip("Temporarily skipped")
#@unittest.skip("Temporarily skipped")
#@unittest.skip("Temporarily skipped")
[docs]
def test__checktm(self):
"""
Test that the _checktm method does not raise an exception with
an invalid tupple type.
"""
bad_t, ttup_l, ttup_s, ttup_tl, ttup_ts = 0, 1, 2, 3, 4
def make_ttup(t_type):
if t_type == bad_t:
ttup = date
elif t_type == ttup_l:
ttup = self._tdu._build_struct_time(date, dstflag)
elif t_type == ttup_s:
ttup = self._tdu._build_struct_time(date, dstflag,
short_in=True)
else: # ttup_tl and ttup_ts
ttup = date + (dstflag,)
return ttup
MIN_K = self._tdu.KULLISHAY_MIN
MAX_K = self._tdu.KULLISHAY_MAX
MIN_Y = self._tdu.MINYEAR
MAX_Y = self._tdu.MAXYEAR
err_msg0 = ("Invalid kull-i-shay {}, it must be in the range "
f"of [{MIN_K}, {MAX_K}].")
err_msg1 = ("Invalid Váḥids '{}' in a Kull-i-Shay’, it must be in "
"the range of [1, 19].")
err_msg2 = ("Invalid year '{}' in a Váḥid, it must be in the "
"range of [1, 19].")
err_msg3 = ("Invalid year '{}' it must be in the range of ["
f"{MIN_Y}, {MAX_Y}].")
err_msg4 = "Invalid month '{}', it must be in the range of [0, 19]."
err_msg5 = ("Invalid day '{}' for month '{}', it must be in the "
"range of [1, {}].")
err_msg6 = "Invalid hour '{}', it must be in the range of [0, 24]."
err_msg7 = "Invalid minute '{}', it must be in the range of [0, 59]."
err_msg8 = "Invalid second '{}', it must be in the range of [0, 61]."
err_msg9 = "Invalid week day '{}', it must be in the range of [0, 6]."
err_msg10 = ("Invalid day '{}' in year, it must be in the range of "
"[1, 366].")
err_msg11 = "Invalid isdst '{}', it must be in the range of [-1, 1]."
err_msg12 = "The ttup argument {} is not a proper tuple."
err_msg13 = "Invalid timetuple, found length {}."
data = (
### Valid tuples
((MIN_K, 18, 1, 1, 1, 1, 1, 1), -1, ttup_l, False, ''),
((1, 10, 10, 9, 6, 8, 45, 1), -1, ttup_l, False, ''),
((MAX_K, 5, 2, 19, 19, 1, 1, 1), -1, ttup_l, False, ''),
((MIN_Y, 1, 1, 0, 0, 0), -1, ttup_s, False, ''),
((181, 9, 6, 8, 45, 1), -1, ttup_s, False, ''),
((MAX_Y, 19, 19, 0, 0, 0), -1, ttup_s, False, ''),
((1, 10, 10, 1, 1, 0, 0, 0, 4, 1), -1, ttup_tl, False, ''),
((181, 1, 1, 0, 0, 0, 4, 1), -1, ttup_ts, False, ''),
### Invalid tuples
# Long form NamedTuple errors
((-6, 1, 1, 1, 1, 1, 1, 1), -1, ttup_l, True,
err_msg3.format(-2526)),
((5, 1, 1, 1, 1, 1, 1, 1), -1, ttup_l, True,
err_msg3.format(1445)),
((1, 0, 1, 1, 1, 1, 1, 1), -1, ttup_l, True, err_msg1.format(0)),
((1, 20, 1, 1, 1, 1, 1, 1), -1, ttup_l, True, err_msg1.format(20)),
((1, 1, 0, 1, 1, 1, 1, 1), -1, ttup_l, True, err_msg2.format(0)),
((1, 1, 20, 1, 1, 1, 1, 1), -1, ttup_l, True, err_msg2.format(20)),
# Long form standard tuple errors
((-6, 1, 1, 1, 1, 1, 1, 1, 1, 1), -1, ttup_tl, True,
err_msg0.format(-6)),
((5, 1, 1, 1, 1, 1, 1, 1, 1, 1), -1, ttup_tl, True,
err_msg0.format(5)),
((1, 0, 1, 1, 1, 1, 1, 1, 1, 1), -1, ttup_tl, True,
err_msg1.format(0)),
((1, 20, 1, 1, 1, 1, 1, 1, 1, 1), -1, ttup_tl, True,
err_msg1.format(20)),
((1, 1, 0, 1, 1, 1, 1, 1, 1, 1), -1, ttup_tl, True,
err_msg2.format(0)),
((1, 1, 20, 1, 1, 1, 1, 1, 1, 1), -1, ttup_tl, True,
err_msg2.format(20)),
# Short for NamedTuple errors
((-1843, 1, 1, 0, 0, 0), -1, ttup_s, True, err_msg3.format(-1843)),
((1162, 1, 1, 0, 0, 0), -1, ttup_s, True, err_msg3.format(1162)),
# Short for standard tuple errors
((-1843, 1, 1, 0, 0, 0, 1, 1), -1, ttup_ts, True,
err_msg3.format(-1843)),
((1162, 1, 1, 0, 0, 0, 1, 1), -1, ttup_ts, True,
err_msg3.format(1162)),
# All tuple types use the same code for the month, day, hour,
# minute, second, wday, yday, and isdst fields.
# Month
((1, -1, 1, 0, 0, 0), -1, ttup_s, True, err_msg4.format(-1)),
((1, 20, 1, 0, 0, 0), -1, ttup_s, True, err_msg4.format(20)),
# Day
((1, 1, 1, 1, -1, 0, 0, 0, 1, 1), -1, ttup_tl, True,
err_msg5.format(-1, 1, 19)),
((1, 1, 1, 1, 20, 0, 0, 0, 1, 1), -1, ttup_tl, True,
err_msg5.format(20, 1, 19)),
# Day, leap year
((1, 0, 0, 0, 0, 0, 1, 1), -1, ttup_ts, True,
err_msg5.format(0, 0, 5)),
((1, 0, 6, 0, 0, 0, 1, 1), -1, ttup_ts, True,
err_msg5.format(6, 0, 5)),
# Hour
((1, 1, 1, 1, 1, -1, 1, 1), -1, ttup_l, True, err_msg6.format(-1)),
((1, 1, 1, 1, 1, 25, 1, 1), -1, ttup_l, True, err_msg6.format(25)),
# Minute
((1, 1, 1, 1, -1, 0), -1, ttup_s, True, err_msg7.format(-1)),
((1, 1, 1, 1, 60, 0), -1, ttup_s, True, err_msg7.format(60)),
# Second
((1, 1, 1, 1, 1, 1, 1, -1, 1, 1), -1, ttup_tl, True,
err_msg8.format(-1)),
((1, 1, 1, 1, 1, 1, 1, 62, 1, 1), -1, ttup_tl, True,
err_msg8.format(62)),
# Week day
((1, 1, 1, 0, 0, 0, -1, 1), -1, ttup_ts, True, err_msg9.format(-1)),
((1, 1, 1, 0, 0, 0, 7, 1), -1, ttup_ts, True, err_msg9.format(7)),
# Day in year
((1, 1, 1, 1, 1, 1, 1, 1, 1, -1), -1, ttup_tl, True,
err_msg10.format(-1)),
((1, 1, 1, 1, 1, 1, 1, 1, 1, 367), -1, ttup_tl, True,
err_msg10.format(367)),
# isdst (Daylight savings time)
((1, 1, 1, 1, 1, 1, 1, 1), -2, ttup_ts, True, err_msg11.format(-2)),
((1, 1, 1, 1, 1, 1, 1, 1), 2, ttup_ts, True, err_msg11.format(2)),
# Proper tuple
([1, 1, 1, 1, 1, 1], -1, bad_t, True,
err_msg12.format("<class 'list'>")),
((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1), -1, ttup_tl, True,
err_msg13.format(13)),
)
for date, dstflag, t_type, validity, expected_result in data:
if validity: # Invalid tests
try:
ttup = make_ttup(t_type)
self._tdu._checktm(ttup)
except (AssertionError, TypeError) as e:
self.assertEqual(expected_result, str(e))
else:
# Raise an error when an AssertionError is not raised.
raise AssertionError(
f"With date {date} an error was not raised.")
else: # Valid tests (Nothing to assert)
ttup = make_ttup(t_type)
self._tdu._checktm(ttup)
#@unittest.skip("Temporarily skipped")
[docs]
@patch('badidatetime._timedateutils.TimeDateUtils.date_format',
new_callable=PropertyMock)
def test_strftime(self, mock_property):
"""
Test that the strftime method returns the correct string.
"""
mock_property.return_value = ['/', 'm', 'd', 'Y']
ttup_l, ttup_s, ttup_tl, ttup_ts = 1, 2, 3, 4
data = (
('%a', (1, 1, 1, 1, 1, 0, 0, 0), -1, ttup_l, None, 'Fiḍ'),
('%A', (1, 1, 1, 0, 0, 0), -1, ttup_s, None, 'Fiḍāl'),
('%b', (1, 1, 1, 1, 1, 0, 0, 0, 1, 1), -1, ttup_tl, None, 'Bah'),
('%B', (1, 1, 1, 1, 1, 1, 1, 1), -1, ttup_ts, None, 'Bahá'),
('%c', (1, 1, 1, 1, 1, 3, 1, 1), -1, ttup_l, None,
'Fiḍ Bah 01 03:01:01 1 01 01'),
('%c', (1, 1, 1, 3, 1, 1), -1, ttup_s, None,
'Fiḍ Bah 01 03:01:01 0001'),
('%C', (1, 10, 10, 1, 1, 0, 0, 0, 1, 1), -1, ttup_tl, None, '01'),
('%C', (181, 1, 1, 0, 0, 0, 1, 1), -1, ttup_ts, None, '01'),
('%d', (1, 1, 1, 1, 8, 0, 0, 0), -1, ttup_l, None, '08'),
('%-d', (1, 1, 8, 0, 0, 0), -1, ttup_s, None, '8'),
('%D', (1, 10, 10, 19, 1, 0, 0, 0, 1, 1), -1, ttup_tl, None,
'19/01/81'),
('%e', (181, 1, 9, 0, 0, 0, 1, 1), -1, ttup_ts, None, ' 9'),
('%f', (1, 10, 10, 1, 1, 0, 0, 60.025), -1, ttup_l, None, '025000'),
('%G', (181, 1, 1, 0, 0, 0), -1, ttup_s, None, '0181'),
('%G', (self._tdu.MINYEAR, 1, 1, 0, 0, 0), -1, ttup_s, None,
'-1842'),
('%h', (1, 10, 10, 2, 1, 0, 0, 0, 1, 1), -1, ttup_tl, None, 'Jal'),
('%H', (181, 1, 1, 3, 0, 0, 1, 1), -1, ttup_ts, None, '03'),
('%-H', (1, 10, 10, 1, 1, 3, 0, 0), -1, ttup_l, None, '3'),
('%I', (181, 1, 1, 13, 0, 0), -1, ttup_s, None, '01'),
('%j', (1, 10, 10, 2, 1, 0, 0, 0), -1, ttup_l, None, '020'),
('%-j', (1, 10, 10, 2, 1, 0, 0, 0), -1, ttup_l, None, '20'),
('%k', (181, 1, 1, 3, 0, 0, 1, 1), -1, ttup_ts, None, '03'),
('%:K', (1, 10, 10, 1, 1, 0, 0, 0, 1, 1), -1, ttup_tl, None, '1'),
('%:K', (181, 1, 1, 0, 0, 0, 1, 1), -1, ttup_ts, None, '1'),
('%l', (1, 10, 10, 1, 1, 13, 0, 0), -1, ttup_l, None, ' 1'),
('%-l', (181, 1, 1, 13, 0, 0), -1, ttup_s, None, '1'),
('%m', (1, 1, 1, 9, 1, 0, 0, 0, 1, 1), -1, ttup_tl, None, '09'),
('%-m', (1, 9, 1, 0, 0, 0, 1, 1), -1, ttup_ts, None, '9'),
('%M', (1, 10, 10, 1, 1, 0, 9, 0), -1, ttup_l, None, '09'),
('%-M', (181, 1, 1, 0, 9, 0), -1, ttup_s, None, '9'),
('%n', (1, 1, 1, 1, 1, 1, 1, 1, 1, 1), -1, ttup_tl, None, '\n'),
('%p', (181, 1, 1, 9, 0, 0, 1, 1), -1, ttup_ts, None, 'AM'),
('%p', (181, 1, 1, 19, 0, 0, 1, 1), -1, ttup_ts, None, 'PM'),
('%r', (1, 1, 1, 1, 1, 13, 5, 2), -1, ttup_l, None, '01:05:02 PM'),
('%S', (1, 1, 1, 0, 0, 5), -1, ttup_s, None, '05'),
('%-S', (1, 1, 1, 1, 1, 0, 0, 5, 1, 1), -1, ttup_tl, None, '5'),
('%T', (181, 1, 1, 3, 10, 5, 1, 1), -1, ttup_ts, None, '03:10:05'),
('%u', (1, 10, 10, 1, 1, 0, 0, 0), -1, ttup_l, None, '4'),
('%U', (1, 1, 1, 0, 0, 0), -1, ttup_s, None, '01'),
('%U', (181, 1, 10, 0, 0, 0), -1, ttup_s, None, '02'),
('%V', (1, 10, 10, 2, 1, 0, 0, 0, 1, 1), -1, ttup_tl, None, '04'),
('%:V', (1, 10, 10, 1, 1, 0, 0, 0, 1, 1), -1, ttup_tl, None, '10'),
('%:V', (181, 1, 1, 0, 0, 0, 1, 1), -1, ttup_ts, None, '10'),
('%W', (1, 10, 10, 1, 1, 0, 0, 0), -1, ttup_l, None, '01'),
('%x', (181, 1, 1, 0, 0, 0), -1, ttup_s, None, '01/01/0181'),
('%X', (1, 1, 1, 1, 1, 1, 1, 1, 1, 1), -1, ttup_tl, None,
'01:01:01'),
('%y', (1, 10, 10, 1, 1, 0, 0, 0, 1, 1), -1, ttup_ts, None, '81'),
('%y', (181, 1, 1, 0, 0, 0, 1, 1), -1, ttup_ts, None, '81'),
('%-y', (1, 1, 1, 1, 1, 0, 0, 0, 1, 1), -1, ttup_ts, None, '1'),
('%-y', (1, 1, 1, 0, 0, 0, 1, 1), -1, ttup_ts, None, '1'),
('%Y', (181, 11, 17, 0, 0, 0), -1, ttup_s, None, '0181'),
('%z', (1, 1, 1, 1, 1, 13, 5, 2, 1, 1), -1, ttup_tl, None, ''),
('%z', (1, 1, 1, 1, 1, 13, 5, 2), -1, ttup_l, datetime.BADI,
'+0350'),
('%z', (1, 1, 1, 13, 5, 2), -1, ttup_s, datetime.BADI, '+0350'),
('%:z', (181, 1, 1, 13, 5, 2), -1, ttup_s, datetime.BADI, '+03:50'),
('%Z', (1, 10, 10, 2, 1, 0, 0, 0, 1, 1), -1, ttup_tl, None, ''),
('%Z', (1, 10, 10, 2, 1, 0, 0, 0), -1, ttup_l, datetime.BADI,
'Asia/Tehran'),
('%%', (181, 1, 1, 13, 5, 2, 1, 1), -1, ttup_ts, None, '%'),
# Some composit formats
('%d/%m/%Y, %H:%M:%S', (1, 10, 10, 1, 1, 12, 30, 30), -1, ttup_l,
None, '01/01/0181, 12:30:30'),
('%B %A %r', (181, 11, 16, 18, 40, 59), -1, ttup_s, None,
'Mashíyyat Istijlāl 06:40:59 PM'),
)
msg = "Expected {}, with format {} and date {}. found {}."
for fmt, date, dstflag, t_type, tz, expected_result in data:
if t_type == ttup_l:
ttup = self._tdu._build_struct_time(date, dstflag, tzinfo=tz)
elif t_type == ttup_s:
ttup = self._tdu._build_struct_time(date, dstflag, tzinfo=tz,
short_in=True)
else: # ttup_tl and ttup_ts
ttup = date + (dstflag,)
result = self._tdu.strftime(fmt, ttup)
self.assertEqual(expected_result, result, msg.format(
expected_result, fmt, date, result))
#@unittest.skip("Temporarily skipped")
#@unittest.skip("Temporarily skipped")
[docs]
def test__find_midday(self):
"""
Test that the _find_midday method returns the correct midday fraction
of the day with either long or short form dates.
"""
ttup_l, ttup_s = 1, 2
data = (
# 2024-03-19
# sunset = 18:12 -> approximate midday = 18:12 + 12:00 = 01T06:12
((1, 10, 10, 6, 12, 0, 0, 0), -1, ttup_l, 0.499833606882),
# 2025-03-19
# sunset = 18:12 -> approximate midday = 18:12 + 12:00 = 01T06:12
((182, 1, 1, 6, 12, 0), -1, ttup_s, 0.500587922288),
)
msg = "Expected {}, with {}. found {}."
for date, dstflag, t_type, expected_result in data:
if t_type == ttup_l:
ttup = self._tdu._build_struct_time(date, dstflag)
else: # t_type == ttup_s
ttup = self._tdu._build_struct_time(date, dstflag,
short_in=True)
result = self._tdu._find_midday(ttup)
self.assertEqual(expected_result, result, msg.format(
expected_result, date, result))
#@unittest.skip("Temporarily skipped")
[docs]
def test__get_year(self):
"""
Test that the _get_year returns the year converted from a long
form date or the year from a short date.
"""
ttup_l, ttup_s = 1, 2
data = (
((1, 10, 10, 11, 17, 9, 30, 30), -1, ttup_l, 181),
((182, 1, 1, 18, 30, 30), -1, ttup_s, 182),
)
msg = "Expected {}, with {}. found {}."
for date, dstflag, t_type, expected_result in data:
if t_type == ttup_l:
ttup = self._tdu._build_struct_time(date, dstflag)
else: # t_type == ttup_s
ttup = self._tdu._build_struct_time(date, dstflag,
short_in=True)
result = self._tdu._get_year(ttup)
self.assertEqual(expected_result, result, msg.format(
expected_result, date, result))
#@unittest.skip("Temporarily skipped")
[docs]
def test__year_week_day(self):
"""
Test that the _year_week_day return the year, week, and day of
the week.
"""
data = (
# year, mon, day -> year, week, day of week
((181, 11, 17), (181, 30, 7)),
((182, 1, 1), (181, 53, 5)),
((183, 19, 19), (183, 52, 7)),
# Last week of a leap year where the beginning of the year
# started on Fiḍāl.
((6, 19, 19), (6, 53, 4)),
((12, 19, 19), (12, 53, 4)),
# Year where the first day of the year starts on Kamál and
# is a leap year.
((174, 19, 17), (175, 1, 1)),
((174, 19, 18), (175, 1, 2)),
((174, 19, 19), (175, 1, 3)),
)
msg = "Expected {} with date {}, found {}."
for date, expected_result in data:
result = self._tdu._year_week_day(*date)
self.assertEqual(expected_result, result, msg.format(
expected_result, date, result))
#@unittest.skip("Temporarily skipped")
[docs]
def test__days_before_year(self):
"""
Test that the _days_before_year function returns the correct
number of days before the specified year.
"""
data = (
(-1842, 0),
(-1841, 366),
(-1840, 731),
(-1838, 1461), # Year -1838 was a leap year.
(181, 738886),
)
msg = "Expected {} with year {}, found {}."
for year, expected_result in data:
result = self._tdu._days_before_year(year)
self.assertEqual(expected_result, result,
msg.format(expected_result, year, result))
#@unittest.skip("Temporarily skipped")
[docs]
def test__days_before_month(self):
"""
Test that the _days_before_month function returns the correct
number of days in the year proceedings the first day in the correct
month.
"""
data = (
(181, 1, 0),
(181, 2, 19),
(181, 3, 38),
(181, 4, 57),
(181, 5, 76),
(181, 6, 95),
(181, 7, 114),
(181, 8, 133),
(181, 9, 152),
(181, 10, 171),
(181, 11, 190),
(181, 12, 209),
(181, 13, 228),
(181, 14, 247),
(181, 15, 266),
(181, 16, 285),
(181, 17, 304),
(181, 18, 323),
(181, 0, 342),
(181, 19, 346),
(183, 1, 0), # 182 is a leap year
)
msg = "Expected {} with year {} and month {}, found {}."
for year, month, expected_result in data:
result = self._tdu._days_before_month(year, month)
self.assertEqual(expected_result, result, msg.format(
expected_result, year, month, result))
#@unittest.skip("Temporarily skipped")
[docs]
def test__day_of_week(self):
"""
Test that the _day_of_week function returns the correct day of
the week (0 - 6) for a given year, month, and day.
All days before 1752-09-14 (-91, 10, 8, 5, 46, 17.1264) in the
Gregorian Calendar will seem wrong when compared to the Badi
Calendar in UK and the US. This is when the Gregorian Calendar was
adopted and compensated 11 days.
"""
data = (
((-1842, 1, 1), 2), # 0001-03-19 (Saturday -> Jamál)
((-91, 9, 15), 6), # 1752-09-02 (Wednesday -> `Idāl)
((-91, 10, 8), 4), # 1752-09-14 (Thursday -> Istijlāl)
((1, 1, 1), 3), # 1844-03-19 (Tuesday -> Fiḍāl)
((181, 9, 9), 2), # 2024-08-26 (Monday -> Kamál)
)
msg = "Expected {} with date {}, found {}."
for date, expected_result in data:
result = self._tdu._day_of_week(*date)
self.assertEqual(expected_result, result,
msg.format(expected_result, date, result))
#@unittest.skip("Temporarily skipped")
[docs]
def test__ymd2ord(self):
"""
Test that the _ymd2ord function returns the correct number of days
since Badi year -1842 including the current day.
"""
data = (
((-1842, 1, 1), 78),
((-1841, 1, 1), 444),
((-1796, 1, 1), 16881),
((-1792, 1, 1), 18342),
((-1788, 1, 1), 19803),
((181, 1, 1), 738964),
# 1st week of 181
((180, 19, 17), 738961),
((180, 19, 18), 738962),
((180, 19, 19), 738963),
((181, 1, 1), 738964),
((181, 1, 2), 738965),
((181, 1, 3), 738966),
((181, 1, 4), 738967),
)
msg = "Expected {} with date {}, found {}."
for date, expected_result in data:
result = self._tdu._ymd2ord(*date)
self.assertEqual(expected_result, result, msg.format(
expected_result, date, result))
#@unittest.skip("Temporarily skipped")
[docs]
def test__ord2ymd(self):
"""
Test that the _ord2ymd function returns the year, month, and day
from the Badi year -1842.
"""
data = (
(78, False, (-5, 18, 1, 1, 1)),
(78, True, (-1842, 1, 1)),
(444, True, (-1841, 1, 1)),
(673219, True, (0, 19, 19)),
(673220, True, (1, 1, 1)),
(675045, True, (5, 19, 18)),
(675046, True, (5, 19, 19)),
(738964, True, (181, 1, 1)),
# 1st week of 181
(738961, True, (180, 19, 17)),
(738962, True, (180, 19, 18)),
(738963, True, (180, 19, 19)),
(738964, True, (181, 1, 1)),
(738965, True, (181, 1, 2)),
(738966, True, (181, 1, 3)),
(738967, True, (181, 1, 4)),
(739100, True, (181, 8, 4)),
)
msg = "Expected {} with ordinal {} and short {}, found {}."
for ordinal, short, expected_result in data:
result = self._tdu._ord2ymd(ordinal, short=short)
self.assertEqual(expected_result, result, msg.format(
expected_result, ordinal, short, result))
#@unittest.skip("Temporarily skipped")
[docs]
def test__build_struct_time(self):
"""
Test that the _build_struct_time correctly builds a timetuple object.
"""
data = (
((181, 9, 6, 8, 45, 1), -1, None, True,
("structures.ShortFormStruct(tm_year=181, tm_mon=9, tm_mday=6, "
"tm_hour=8, tm_min=45, tm_sec=1, tm_wday=6, tm_yday=158, "
"tm_isdst=-1)", None, None)),
((1, 1, 1, 0, 0, 0), -1, datetime.BADI, True,
("structures.ShortFormStruct(tm_year=1, tm_mon=1, tm_mday=1, "
"tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, "
"tm_isdst=0)", 'Asia/Tehran', 12600.0)),
((1, 10, 10, 9, 6, 8, 45, 1), -1, None, False,
("structures.LongFormStruct(tm_kull_i_shay=1, tm_vahid=10, "
"tm_year=10, tm_mon=9, tm_mday=6, tm_hour=8, tm_min=45, "
"tm_sec=1, tm_wday=6, tm_yday=158, tm_isdst=-1)", None, None)),
)
msg0 = "Expected {} with dt {}, dst {}, and timezone {}, found {}."
msg1 = "Expected {}, found {}."
for dt, dst, tz, short_in, expected_result in data:
result = self._tdu._build_struct_time(dt, dst, tzinfo=tz,
short_in=short_in)
self.assertEqual(expected_result[0], str(result), msg0.format(
expected_result, dt, dst, tz, result))
self.assertEqual(expected_result[1], result.tm_zone,
msg1.format(expected_result[1], result.tm_zone))
self.assertEqual(expected_result[2], result.tm_gmtoff,
msg1.format(expected_result[2], result.tm_gmtoff))
#@unittest.skip("Temporarily skipped")
[docs]
def test__isoweek_to_badi(self):
"""
Test that the _isoweek_to_badi function returns the year, month,
and day for the beginning of the week either before or after
depending on what day in the week the day falls.
"""
err_msg0 = "Invalid week: {}"
err_msg1 = "Invalid weekday: {} (range is [1, 7])"
data = (
# year week day
((-1842, 1, 1), False, False, (-5, 17, 19, 19, 18)),
((-1842, 1, 1), True, False, (-1843, 19, 18)),
(( 1, 52, 1), True, False, (1, 19, 15)),
(( 46, 52, 1), True, False, (46, 19, 15)),
(( 175, 52, 1), True, False, (175, 19, 16)),
(( 176, 52, 1), True, False, (176, 19, 15)),
(( 181, 1, 1), True, False, (180, 19, 17)),
(( 181, 1, 7), True, False, (181, 1, 4)),
(( 181, 20, 7), True, False, (181, 8, 4)),
(( 181, 52, 1), True, False, (181, 19, 16)),
(( 181, 52, 7), True, False, (182, 1, 3)),
(( 182, 52, 1), True, False, (182, 19, 14)),
(( 183, 1, 1), True, False, (183, 1, 2)),
(( 187, 52, 1), True, False, (187, 19, 15)),
(( 192, 52, 1), True, False, (192, 19, 16)),
(( 193, 52, 1), True, False, (193, 19, 15)),
(( 194, 52, 1), True, False, (194, 19, 14)),
(( 198, 52, 1), True, False, (198, 19, 16)),
(( 199, 52, 1), True, False, (199, 19, 14)),
(( 203, 52, 1), True, False, (203, 19, 16)),
(( 204, 52, 1), True, False, (204, 19, 15)),
(( 209, 52, 1), True, False, (209, 19, 16)),
(( 210, 52, 1), True, False, (210, 19, 15)),
(( 215, 52, 1), True, False, (215, 19, 16)),
(( 216, 52, 1), True, False, (216, 19, 14)),
(( 181, 53, 1), True, True, err_msg0.format(53)),
(( 181, 20, 10), False, True, err_msg1.format(10)),
)
msg = "Expected {} with (year, week, day) {}, found {}."
for item, short, validity, expected_result in data:
if validity:
with self.assertRaises(AssertionError) as cm:
self._tdu._isoweek_to_badi(*item)
message = str(cm.exception)
self.assertEqual(expected_result, message)
else:
result = self._tdu._isoweek_to_badi(*item, short=short)
self.assertEqual(expected_result, result, msg.format(
expected_result, item, result))
#@unittest.skip("Temporarily skipped")
[docs]
def test__isoweek1jalal(self):
"""
Test that the _isoweek1jalal function returns the ordinal day number
of the first week with more than 3 days in it.
This can be checked with the Python standard
datetime.datetime(year, month, day).toordinal() method.
"""
data = (
(-1842, 76), # 0001-03-19 -> -1843-19-17
(-1841, 447), # 0002-03-19 -> -1841-01-04
( 1, 673217), # 1844-03-16 -> 0000-19-17
( 181, 738961), # 2024-03-16 -> 0180-19-17
( 182, 739332), # 2025-03-22 -> 0182-01-04
( 183, 739696), # 2026-03-21 -> 0183-01-02
)
msg = "Expected {} with year {}, found {}."
for year, expected_result in data:
result = self._tdu._isoweek1jalal(year)
self.assertEqual(expected_result, result, msg.format(
expected_result, year, result))
#@unittest.skip("Temporarily skipped")
#@unittest.skip("Temporarily skipped")
#@unittest.skip("Temporarily skipped")
#@unittest.skip("Temporarily skipped")
#@unittest.skip("Temporarily skipped")
[docs]
def test__check_date_fields(self):
"""
Test that the _check_date_fields function correctly raises
assertion exceptions.
A more complete test is in badidatetime/tests/test_badi_calendar.py.
"""
err_msg0 = ("Invalid Váḥids '{}' in a Kull-i-Shay’, it must be in "
"the range of [1, 19].")
err_msg1 = ("Invalid year '{}' in a Váḥid, it must be in the range "
"of [1, 19].")
err_msg2 = "Invalid month '{}', it must be in the range of [0, 19]."
err_msg3 = ("Invalid day '{}' for month '{}', it must be in the "
"range of [1, {}].")
data = (
# Valid short form Badi dates
((self._tdu.MINYEAR, 1, 1), False, ''),
((self._tdu.MAXYEAR, 1, 1), False, ''),
# Invalid Váḥid
((1, 0, 1, 1, 1), True, err_msg0.format(0)),
((1, 20, 1, 1, 1), True, err_msg0.format(20)),
# Invalid year
((1, 10, 0, 1, 1), True, err_msg1.format(0)),
((1, 10, 20, 1, 1), True, err_msg1.format(20)),
# Invalid month
((1, 10, 10, -1, 1), True, err_msg2.format(-1)),
((1, 10, 10, 20, 1), True, err_msg2.format(20)),
# Invalid Ayyám-i-Há day
((1, 10, 3, 0, 0), True, err_msg3.format(0, 0, 5)),
((1, 10, 3, 0, 6), True, err_msg3.format(6, 0, 5)),
# Invalid normal day
((1, 10, 3, 2, 0), True, err_msg3.format(0, 2, 19)),
((1, 10, 3, 2, 20), True, err_msg3.format(20, 2, 19)),
# Test short form date.
((181, 20, 1), True, err_msg2.format(20)),
)
for date, validity, err_msg in data:
short_in = False if len(date) == 5 else True
if validity:
try:
self._tdu._check_date_fields(*date, short_in=short_in)
except AssertionError as e:
self.assertEqual(err_msg, str(e))
else:
raise AssertionError(f"date {date}")
else:
self._tdu._check_date_fields(*date, short_in=short_in)
#@unittest.skip("Temporarily skipped")
[docs]
def test__check_time_fields(self):
"""
Test that the _check_time_fields function correctly raises
assertion exceptions.
"""
err_msg0 = "Invalid hour '{}', it must be in the range of [0, 24]."
err_msg1 = "Invalid minute '{}', it must be in the range of [0, 59]."
err_msg2 = "Invalid second '{}', it must be in the range of [0, 61]."
err_msg3 = ("Invalid microseconds '{}', it must be in the range of "
"[0, 999999].")
err_msg4 = "The fold argument '{}' must be either 0 or 1."
data = (
((0, 0, 0, 0, 0), False, ''),
((24, 59, 59, 999999, 1), False, ''),
((-1, 0, 0, 0, 0), True, err_msg0.format(-1)),
((25, 0, 0, 0, 0), True, err_msg0.format(25)),
((0, -1, 0, 0, 0), True, err_msg1.format(-1)),
((0, 60, 0, 0, 0), True, err_msg1.format(60)),
((0, 0, -1, 0, 0), True, err_msg2.format(-1)),
((0, 0, 61, 0, 0), True, err_msg2.format(61)),
((0, 0, 0, -1, 0), True, err_msg3.format(-1)),
((0, 0, 0, 1000000, 0), True, err_msg3.format(1000000)),
((0, 0, 0, 0, -1), True, err_msg4.format(-1)),
((0, 0, 0, 0, 2), True, err_msg4.format(2)),
)
for time, validity, err_msg in data:
if validity:
try:
self._tdu._check_time_fields(*time)
except AssertionError as e:
self.assertEqual(err_msg, str(e))
else:
raise AssertionError(f"time {time}")
else:
self._tdu._check_time_fields(*time)
#@unittest.skip("Temporarily skipped")
[docs]
def test__wrap_strftime(self):
"""
Test that the _wrap_strftime function returns a formatted time
string.
"""
d_t, dt_t = 1, 2
tz = ZoneInfo('US/Eastern')
data = (
((181, 1, 1), '%d/%m/%Y, %H:%M:%S', d_t, '01/01/0181, 00:00:00'),
((1, 1, 8), '%-d', d_t, '8'),
((181, 1, 1, None, None, 0, 9, 0), '%-M', dt_t, '9'),
((182, 2, 4, None, None, 12, 30, 30, 500000),
'%a %b %d %H:%M:%S.%f %Y', dt_t,
'Isj Jal 04 12:30:30.500000 0182'),
((182, 2, 4, None, None, 0, 0, 0, 0, tz), '%Y-%m-%dT%H:%M:%S%z',
dt_t, '0182-02-04T00:00:00-0400'),
)
msg = "Expected {} with date {} and format {}, found {}."
for date, fmt, obj_t, expected_result in data:
if obj_t == d_t:
d = datetime.date(*date)
else:
d = datetime.datetime(*date)
tt = d.timetuple()
result = self._tdu._wrap_strftime(d, fmt, tt)
self.assertEqual(expected_result, result, msg.format(
expected_result, date, format, result))