1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
--- /dev/null
+++ b/pyrfc3339/tests/test_all.py
@@ -0,0 +1,155 @@
+"""
+Test suite for pyRFC3339.
+
+"""
+
+import unittest
+import zoneinfo
+from datetime import datetime, timezone
+from zoneinfo import ZoneInfo
+
+from pyrfc3339 import generate, parse
+
+
+class TestCore(unittest.TestCase):
+ """
+ This test case contains tests to address cases not tested in the doctests,
+ as well as additional tests for end-to-end verification.
+
+ """
+
+ def test_zero_offset(self) -> None:
+ """
+ Both +00:00 and -00:00 are equivalent to the offset 'Z' (UTC).
+
+ """
+ timestamp = "2009-01-01T10:02:03+00:00"
+ dt = parse(timestamp)
+ self.assertEqual(dt.tzinfo, timezone.utc)
+
+ timestamp = "2009-01-01T10:02:03-00:00"
+ dt = parse(timestamp)
+ self.assertEqual(dt.tzinfo, timezone.utc)
+
+ def test_parse_microseconds(self) -> None:
+ """
+ Test parsing timestamps with microseconds.
+
+ """
+ timestamp = "2009-01-01T10:02:03.25Z"
+ dt = parse(timestamp)
+ self.assertEqual(dt.microsecond, 250000)
+
+ def test_generate_microseconds(self) -> None:
+ """
+ Test generating timestamps with microseconds.
+
+ """
+ dt = datetime(2009, 1, 1, 10, 2, 3, 500000, tzinfo=timezone.utc)
+ timestamp = generate(dt, microseconds=True)
+ self.assertEqual(timestamp, "2009-01-01T10:02:03.500000Z")
+
+ def test_mixed_case(self) -> None:
+ """
+ Timestamps may use either 'T' or 't' and either 'Z' or 'z'
+ according to :RFC:`3339`.
+
+ """
+ dt1 = parse("2009-01-01t10:01:02z")
+ dt2 = datetime(2009, 1, 1, 10, 1, 2, tzinfo=timezone.utc)
+
+ self.assertEqual(dt1, dt2)
+
+ def test_parse_naive_utc(self) -> None:
+ """
+ Test parsing a UTC timestamp to a naive datetime.
+
+ """
+ dt1 = parse("2009-01-01T10:01:02Z", produce_naive=True)
+ self.assertEqual(dt1.tzinfo, None)
+
+ def test_parse_naive_local(self) -> None:
+ """
+ Test that parsing a local timestamp to a naive datetime fails.
+
+ """
+ with self.assertRaises(ValueError):
+ parse("2009-01-01T10:01:02-04:00", produce_naive=True)
+
+ def test_generate_utc_parse_utc(self) -> None:
+ """
+ Generate a UTC timestamp and parse it into a UTC datetime.
+
+ """
+ dt1 = datetime.now(timezone.utc)
+
+ dt2 = parse(generate(dt1, microseconds=True))
+ self.assertEqual(dt1, dt2)
+
+ def test_generate_local_parse_local(self) -> None:
+ """
+ Generate a local timestamp and parse it into a local datetime.
+
+ """
+ eastern = ZoneInfo("US/Eastern")
+ dt1 = datetime.now(eastern)
+ dt2 = parse(generate(dt1, utc=False, microseconds=True), utc=False)
+ self.assertEqual(dt1, dt2)
+
+ def test_generate_local_parse_utc(self) -> None:
+ """
+ Generate a local timestamp and parse it into a UTC datetime.
+
+ """
+ eastern = ZoneInfo("US/Eastern")
+ dt1 = datetime.now(eastern)
+ dt2 = parse(generate(dt1, utc=False, microseconds=True))
+ self.assertEqual(dt1, dt2)
+
+ @unittest.skip("fails due to python/cpython#120713")
+ def test_three_digit_year(self) -> None:
+ dt = datetime(999, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
+ self.assertEqual(generate(dt), "0999-01-01T00:00:00Z")
+
+
+class TestExhaustiveRoundtrip(unittest.TestCase):
+ """
+ This test case exhaustively tests parsing and generation by generating
+ a local RFC 3339 timestamp for every timezone supported by `zoneinfo`,
+ parsing that timestamp into a local datetime and a UTC datetime
+ and asserting that those represent the same instant.
+
+ """
+
+ def setUp(self) -> None:
+ self.available_timezones = zoneinfo.available_timezones()
+
+ def test_local_roundtrip(self) -> None:
+ """
+ Generates a local datetime using the given timezone,
+ produces a local timestamp from the datetime, parses the timestamp
+ to a local datetime, and verifies that the two datetimes are equal.
+
+ """
+ for tz_name in self.available_timezones:
+ with self.subTest(tz=tz_name):
+ tzinfo = ZoneInfo(tz_name)
+ dt1 = datetime.now(tzinfo)
+ timestamp = generate(dt1, utc=False, microseconds=True)
+ dt2 = parse(timestamp, utc=False)
+ self.assertEqual(dt1, dt2)
+
+ def test_utc_roundtrip(self) -> None:
+ """
+ Generates a local datetime using the given timezone,
+ produces a local timestamp from the datetime, parses the timestamp
+ to a UTC datetime, and verifies that the two datetimes are equal.
+
+ """
+ for tz_name in self.available_timezones:
+ with self.subTest(tz=tz_name):
+ tzinfo = ZoneInfo(tz_name)
+ dt1 = datetime.now(tzinfo)
+ timestamp = generate(dt1, utc=False, microseconds=True)
+ dt2 = parse(timestamp)
+ self.assertEqual(dt1, dt2)
|