test_approxidate.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. # test_approxidate.py -- tests for approxidate.py
  2. # Copyright (C) 2025 Jelmer Vernooij <jelmer@jelmer.uk>
  3. #
  4. # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  5. # Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU
  6. # General Public License as published by the Free Software Foundation; version 2.0
  7. # or (at your option) any later version. You can redistribute it and/or
  8. # modify it under the terms of either of these two licenses.
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. #
  16. # You should have received a copy of the licenses; if not, see
  17. # <http://www.gnu.org/licenses/> for a copy of the GNU General Public License
  18. # and <http://www.apache.org/licenses/LICENSE-2.0> for a copy of the Apache
  19. # License, Version 2.0.
  20. #
  21. """Tests for approxidate parsing."""
  22. import time
  23. from dulwich.approxidate import parse_approxidate, parse_relative_time
  24. from . import TestCase
  25. class ParseRelativeTimeTests(TestCase):
  26. """Test parse_relative_time."""
  27. def test_now(self) -> None:
  28. self.assertEqual(0, parse_relative_time("now"))
  29. def test_seconds_ago(self) -> None:
  30. self.assertEqual(5, parse_relative_time("5 seconds ago"))
  31. self.assertEqual(1, parse_relative_time("1 second ago"))
  32. def test_minutes_ago(self) -> None:
  33. self.assertEqual(5 * 60, parse_relative_time("5 minutes ago"))
  34. self.assertEqual(1 * 60, parse_relative_time("1 minute ago"))
  35. def test_hours_ago(self) -> None:
  36. self.assertEqual(5 * 3600, parse_relative_time("5 hours ago"))
  37. self.assertEqual(1 * 3600, parse_relative_time("1 hour ago"))
  38. def test_days_ago(self) -> None:
  39. self.assertEqual(5 * 86400, parse_relative_time("5 days ago"))
  40. self.assertEqual(1 * 86400, parse_relative_time("1 day ago"))
  41. def test_weeks_ago(self) -> None:
  42. self.assertEqual(2 * 604800, parse_relative_time("2 weeks ago"))
  43. self.assertEqual(1 * 604800, parse_relative_time("1 week ago"))
  44. def test_months_ago(self) -> None:
  45. self.assertEqual(2 * 2592000, parse_relative_time("2 months ago"))
  46. self.assertEqual(1 * 2592000, parse_relative_time("1 month ago"))
  47. def test_years_ago(self) -> None:
  48. self.assertEqual(2 * 31536000, parse_relative_time("2 years ago"))
  49. self.assertEqual(1 * 31536000, parse_relative_time("1 year ago"))
  50. def test_dot_separated_format(self) -> None:
  51. # Git supports both "2 weeks ago" and "2.weeks.ago"
  52. self.assertEqual(2 * 604800, parse_relative_time("2.weeks.ago"))
  53. self.assertEqual(5 * 86400, parse_relative_time("5.days.ago"))
  54. def test_invalid_format(self) -> None:
  55. self.assertRaises(ValueError, parse_relative_time, "not a time")
  56. self.assertRaises(ValueError, parse_relative_time, "5 weeks") # Missing "ago"
  57. def test_invalid_unit(self) -> None:
  58. self.assertRaises(ValueError, parse_relative_time, "5 fortnights ago")
  59. def test_invalid_number(self) -> None:
  60. self.assertRaises(ValueError, parse_relative_time, "abc weeks ago")
  61. class ParseApproxidateTests(TestCase):
  62. """Test parse_approxidate."""
  63. def test_now(self) -> None:
  64. result = parse_approxidate("now")
  65. # Should be close to current time
  66. self.assertAlmostEqual(result, time.time(), delta=2)
  67. def test_yesterday(self) -> None:
  68. result = parse_approxidate("yesterday")
  69. expected = time.time() - 86400
  70. self.assertAlmostEqual(result, expected, delta=2)
  71. def test_today(self) -> None:
  72. result = parse_approxidate("today")
  73. # Should be midnight of current day
  74. from datetime import datetime
  75. now = datetime.fromtimestamp(time.time())
  76. expected_dt = now.replace(hour=0, minute=0, second=0, microsecond=0)
  77. expected = int(expected_dt.timestamp())
  78. self.assertEqual(result, expected)
  79. def test_unix_timestamp(self) -> None:
  80. self.assertEqual(1234567890, parse_approxidate("1234567890"))
  81. self.assertEqual(0, parse_approxidate("0"))
  82. def test_relative_times(self) -> None:
  83. # Test relative time parsing
  84. result = parse_approxidate("2 weeks ago")
  85. expected = time.time() - (2 * 604800)
  86. self.assertAlmostEqual(result, expected, delta=2)
  87. result = parse_approxidate("5.days.ago")
  88. expected = time.time() - (5 * 86400)
  89. self.assertAlmostEqual(result, expected, delta=2)
  90. def test_absolute_date_iso(self) -> None:
  91. # Test ISO format date
  92. result = parse_approxidate("2009-02-13")
  93. # 2009-02-13 00:00:00 UTC
  94. from datetime import datetime
  95. expected = int(datetime(2009, 2, 13, 0, 0, 0).timestamp())
  96. self.assertEqual(result, expected)
  97. def test_absolute_datetime_iso(self) -> None:
  98. # Test ISO format datetime
  99. result = parse_approxidate("2009-02-13 23:31:30")
  100. from datetime import datetime
  101. expected = int(datetime(2009, 2, 13, 23, 31, 30).timestamp())
  102. self.assertEqual(result, expected)
  103. def test_absolute_datetime_iso8601(self) -> None:
  104. # Test ISO 8601 format
  105. result = parse_approxidate("2009-02-13T23:31:30")
  106. from datetime import datetime
  107. expected = int(datetime(2009, 2, 13, 23, 31, 30).timestamp())
  108. self.assertEqual(result, expected)
  109. def test_bytes_input(self) -> None:
  110. # Test that bytes input works
  111. result = parse_approxidate(b"1234567890")
  112. self.assertEqual(1234567890, result)
  113. result = parse_approxidate(b"yesterday")
  114. expected = time.time() - 86400
  115. self.assertAlmostEqual(result, expected, delta=2)
  116. def test_whitespace_handling(self) -> None:
  117. # Test that leading/trailing whitespace is handled
  118. self.assertEqual(1234567890, parse_approxidate(" 1234567890 "))
  119. result = parse_approxidate(" yesterday ")
  120. expected = time.time() - 86400
  121. self.assertAlmostEqual(result, expected, delta=2)
  122. def test_invalid_spec(self) -> None:
  123. self.assertRaises(ValueError, parse_approxidate, "not a valid time")
  124. self.assertRaises(ValueError, parse_approxidate, "abc123")