• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# coding: utf-8
2from __future__ import unicode_literals, division, absolute_import, print_function
3
4import os
5import platform
6import sys
7import unittest
8from datetime import date, datetime, time, timedelta
9
10from asn1crypto import util
11
12from .unittest_data import data_decorator
13from ._unittest_compat import patch
14
15patch()
16
17if sys.version_info < (3,):
18    py2 = True
19    byte_cls = str
20    num_cls = long  # noqa
21else:
22    py2 = False
23    byte_cls = bytes
24    num_cls = int
25
26
27tests_root = os.path.dirname(__file__)
28fixtures_dir = os.path.join(tests_root, 'fixtures')
29utc = util.timezone.utc
30
31
32@data_decorator
33class UtilTests(unittest.TestCase):
34
35    def test_int_to_bytes(self):
36        self.assertEqual(util.int_to_bytes(0, False, 0), b'')
37        self.assertEqual(util.int_to_bytes(0, False), b'\x00')
38        self.assertEqual(util.int_to_bytes(0, False, 3), b'\x00\x00\x00')
39        self.assertEqual(util.int_to_bytes(0, True, 0), b'')
40        self.assertEqual(util.int_to_bytes(0, True), b'\x00')
41        self.assertEqual(util.int_to_bytes(0, True, 3), b'\x00\x00\x00')
42
43        self.assertEqual(util.int_to_bytes(128, False), b'\x80')
44        self.assertEqual(util.int_to_bytes(128, False, 3), b'\x00\x00\x80')
45        self.assertEqual(util.int_to_bytes(-128, True), b'\x80')
46        self.assertEqual(util.int_to_bytes(-128, True, 3), b'\xff\xff\x80')
47
48        self.assertEqual(util.int_to_bytes(255, False), b'\xff')
49        self.assertEqual(util.int_to_bytes(255, False, 3), b'\x00\x00\xff')
50        self.assertEqual(util.int_to_bytes(-1, True), b'\xff')
51        self.assertEqual(util.int_to_bytes(-1, True, 3), b'\xff\xff\xff')
52
53        self.assertEqual(util.int_to_bytes(12345678, False), b'\xbc\x61\x4e')
54        self.assertEqual(util.int_to_bytes(12345678, False, 3), b'\xbc\x61\x4e')
55        self.assertEqual(util.int_to_bytes(12345678, False, 5), b'\x00\x00\xbc\x61\x4e')
56        self.assertEqual(util.int_to_bytes(12345678 - 2 ** 24, True), b'\xbc\x61\x4e')
57        self.assertEqual(util.int_to_bytes(12345678 - 2 ** 24, True, 3), b'\xbc\x61\x4e')
58        self.assertEqual(util.int_to_bytes(12345678 - 2 ** 24, True, 5), b'\xff\xff\xbc\x61\x4e')
59
60        with self.assertRaises(OverflowError):
61            util.int_to_bytes(123456789, width=3)
62        with self.assertRaises(OverflowError):
63            util.int_to_bytes(50000, signed=True, width=2)
64
65    def test_int_from_bytes(self):
66        self.assertEqual(util.int_from_bytes(b'', False), 0)
67        self.assertEqual(util.int_from_bytes(b'', True), 0)
68        self.assertEqual(util.int_from_bytes(b'\x00', False), 0)
69        self.assertEqual(util.int_from_bytes(b'\x00', True), 0)
70        self.assertEqual(util.int_from_bytes(b'\x80', False), 128)
71        self.assertEqual(util.int_from_bytes(b'\x80', True), -128)
72        self.assertEqual(util.int_from_bytes(b'\xff', False), 255)
73        self.assertEqual(util.int_from_bytes(b'\xff', True), -1)
74        self.assertEqual(util.int_from_bytes(b'\xbc\x61\x4e', False), 12345678)
75        self.assertEqual(util.int_from_bytes(b'\xbc\x61\x4e', True), 12345678 - 2 ** 24)
76
77    def test_int_fromto_bytes(self):
78        for i in range(-300, 301):
79            self.assertEqual(i, util.int_from_bytes(util.int_to_bytes(i, True), True))
80        for i in range(0, 301):
81            self.assertEqual(i, util.int_from_bytes(util.int_to_bytes(i, False), False))
82
83    def test_timezone(self):
84        delta_plus_5_42 = timedelta(hours=5, minutes=42)
85        delta_minus_5_42 = -delta_plus_5_42
86
87        # limited to +24h
88        with self.assertRaises(ValueError):
89            util.timezone(delta_plus_5_42 * 5)
90
91        # limited to -24h
92        with self.assertRaises(ValueError):
93            util.timezone(delta_minus_5_42 * 5)
94
95        # py2 implementation supports no sub-minutes time zones
96        if py2:
97            with self.assertRaises(ValueError):
98                util.timezone(timedelta(hours=5, minutes=42, seconds=13))
99
100            with self.assertRaises(ValueError):
101                util.timezone(timedelta(hours=5, minutes=42, microseconds=13))
102
103        # test __eq__
104        tz0 = util.timezone(delta_plus_5_42)
105        tz1 = util.timezone(delta_minus_5_42)
106        self.assertEqual(tz0, tz0)
107        self.assertEqual(tz1, tz1)
108        self.assertNotEqual(tz0, tz1)
109        self.assertFalse(tz0 == "not equal to a str")
110
111        # test tzname
112        self.assertEqual('5_42', util.timezone(delta_plus_5_42, '5_42').tzname(None))
113        self.assertEqual('UTC+05:42', util.timezone(delta_plus_5_42).tzname(None))
114        self.assertEqual('UTC-05:42', util.timezone(delta_minus_5_42).tzname(None))
115        if py2 or sys.version_info >= (3, 6):
116            # bpo22241
117            self.assertEqual('UTC', util.timezone(timedelta(0)).tzname(None))
118
119        # test utcoffset
120        self.assertEqual(delta_minus_5_42, util.timezone(delta_minus_5_42).utcoffset(None))
121
122        # test dst
123        self.assertTrue(util.timezone(delta_minus_5_42).dst(None) in set((timedelta(0), None)))
124
125        # test create_timezone
126        self.assertTrue(util.create_timezone(delta_plus_5_42) is util.create_timezone(timedelta(hours=5, minutes=42)))
127        self.assertFalse(util.create_timezone(delta_plus_5_42) is util.create_timezone(delta_minus_5_42))
128
129    def test_utc_with_dst(self):
130        self.assertEqual('UTC', util.utc_with_dst.tzname(None))
131
132    def test_extended_date_strftime(self):
133        self.assertEqual('0000-01-01', util.extended_date(0, 1, 1).strftime('%Y-%m-%d'))
134        self.assertEqual('Sat Saturday Jan January', util.extended_date(0, 1, 1).strftime('%a %A %b %B'))
135        self.assertEqual('Tue Tuesday Feb February 29', util.extended_date(0, 2, 29).strftime('%a %A %b %B %d'))
136        if sys.platform == 'win32' and sys.version_info < (3, 5) and platform.python_implementation() != 'PyPy':
137            self.assertEqual('01/01/00 00:00:00', util.extended_date(0, 1, 1).strftime('%c'))
138        else:
139            self.assertEqual('Sat Jan  1 00:00:00 0000', util.extended_date(0, 1, 1).strftime('%c'))
140        self.assertEqual('01/01/00', util.extended_date(0, 1, 1).strftime('%x'))
141
142    def test_extended_datetime_init(self):
143        with self.assertRaises(ValueError):
144            util.extended_datetime(2000, 11, 27)
145
146    def test_extended_date_init(self):
147        with self.assertRaises(ValueError):
148            util.extended_date(2000, 11, 27)
149
150    def test_extended_datetime_properties(self):
151        zone = util.create_timezone(timedelta(hours=12, minutes=45))
152        dt = util.extended_datetime(0, 11, 27, 5, 44, 31, 14889, zone)
153        self.assertEqual(dt.year, 0)
154        self.assertEqual(dt.month, 11)
155        self.assertEqual(dt.day, 27)
156        self.assertEqual(dt.hour, 5)
157        self.assertEqual(dt.minute, 44)
158        self.assertEqual(dt.second, 31)
159        self.assertEqual(dt.microsecond, 14889)
160        self.assertEqual(dt.tzinfo, zone)
161
162    def test_extended_date_properties(self):
163        ext_date = util.extended_date(0, 11, 27)
164        self.assertEqual(ext_date.year, 0)
165        self.assertEqual(ext_date.month, 11)
166        self.assertEqual(ext_date.day, 27)
167
168    def test_extended_datetime_isoformat(self):
169        self.assertEqual('0000-01-01T00:00:00', util.extended_datetime(0, 1, 1).isoformat())
170        self.assertEqual('0000-01-01T00:00:00.001000', util.extended_datetime(0, 1, 1, microsecond=1000).isoformat())
171        self.assertEqual('0000-01-01%00:00:00', util.extended_datetime(0, 1, 1).isoformat(sep='%'))
172
173    def test_extended_date_isoformat(self):
174        self.assertEqual('0000-01-01', util.extended_date(0, 1, 1).isoformat())
175        self.assertEqual('0000-11-27', util.extended_date(0, 11, 27).isoformat())
176
177    def test_extended_datetime_strftime(self):
178        self.assertEqual('0000-01-01 00:00:00', util.extended_datetime(0, 1, 1).strftime('%Y-%m-%d %H:%M:%S'))
179        self.assertEqual('Sat Saturday Jan January', util.extended_datetime(0, 1, 1).strftime('%a %A %b %B'))
180        self.assertEqual('Tue Tuesday Feb February 29', util.extended_datetime(0, 2, 29).strftime('%a %A %b %B %d'))
181        if sys.platform == 'win32' and sys.version_info < (3, 5) and platform.python_implementation() != 'PyPy':
182            self.assertEqual('01/01/00 00:00:00', util.extended_datetime(0, 1, 1).strftime('%c'))
183        else:
184            self.assertEqual('Sat Jan  1 00:00:00 0000', util.extended_datetime(0, 1, 1).strftime('%c'))
185        self.assertEqual('01/01/00', util.extended_datetime(0, 1, 1).strftime('%x'))
186        self.assertEqual('%Y', util.extended_datetime(0, 1, 1).strftime('%%Y'))
187
188    def test_extended_datetime_replace(self):
189        zone = util.create_timezone(timedelta(hours=12, minutes=45))
190        ext_dt = util.extended_datetime(0, 1, 1, 23, tzinfo=zone)
191        self.assertEqual(ext_dt.replace(year=2040, minute=59), datetime(2040, 1, 1, 23, 59, tzinfo=zone))
192        self.assertEqual(ext_dt.replace(minute=59), util.extended_datetime(0, 1, 1, 23, 59, tzinfo=zone))
193
194    def test_extended_date_replace(self):
195        ext_date = util.extended_date(0, 2, 27)
196        self.assertEqual(ext_date.replace(year=2040), date(2040, 2, 27))
197        self.assertEqual(ext_date.replace(day=29), util.extended_date(0, 2, 29))
198        with self.assertRaises(ValueError):
199            ext_date.replace(day=30)
200
201    def test_extended_datetime_encodings(self):
202        zone = util.create_timezone(timedelta(hours=12, minutes=45))
203
204        # test with microseconds
205        ext_dt = util.extended_datetime(0, 2, 29, 9, 17, 45, 14889, zone)
206        self.assertEqual(str(ext_dt), '0000-02-29 09:17:45.014889+12:45')
207        if py2:
208            self.assertEqual(unicode(ext_dt), '0000-02-29 09:17:45.014889+12:45')  # noqa: F821
209
210        # test without microseconds
211        ext_dt = util.extended_datetime(0, 2, 29, 9, 17, 45, 0, zone)
212        self.assertEqual(str(ext_dt), '0000-02-29 09:17:45+12:45')
213        if py2:
214            self.assertEqual(unicode(ext_dt), '0000-02-29 09:17:45+12:45')  # noqa: F821
215
216    def test_extended_date_encodings(self):
217        ext_date = util.extended_date(0, 2, 29)
218        self.assertEqual(str(ext_date), '0000-02-29')
219        if py2:
220            self.assertEqual(unicode(ext_date), '0000-02-29')  # noqa: F821
221
222    def test_extended_datetime_timestamp(self):
223        if sys.version_info >= (3, 3):
224            zone = util.create_timezone(timedelta(hours=12, minutes=45))
225            ext_dt = util.extended_datetime(0, 12, 31, 23, 0, 0, 14889, zone)
226            dt = datetime(1, 1, 1, 0, 0, 0, 14889, zone)
227            self.assertTrue(abs(dt.timestamp() - ext_dt.timestamp() - 3600.0) < 0.0000001)
228
229    def test_extended_date_compare(self):
230        self.assertTrue(util.extended_date(0, 1, 1) < date(1, 1, 1))
231        self.assertTrue(util.extended_date(0, 1, 1) <= date(1, 1, 1))
232        self.assertTrue(util.extended_date(0, 1, 1) != date(1, 1, 1))
233        self.assertFalse(util.extended_date(0, 1, 1) == date(1, 1, 1))
234        self.assertFalse(util.extended_date(0, 1, 1) >= date(1, 1, 1))
235        self.assertFalse(util.extended_date(0, 1, 1) > date(1, 1, 1))
236
237        self.assertFalse(util.extended_date(0, 1, 1) < util.extended_date(0, 1, 1))
238        self.assertTrue(util.extended_date(0, 1, 1) <= util.extended_date(0, 1, 1))
239        self.assertFalse(util.extended_date(0, 1, 1) != util.extended_date(0, 1, 1))
240        self.assertTrue(util.extended_date(0, 1, 1) == util.extended_date(0, 1, 1))
241        self.assertTrue(util.extended_date(0, 1, 1) >= util.extended_date(0, 1, 1))
242        self.assertFalse(util.extended_date(0, 1, 1) > util.extended_date(0, 1, 1))
243
244        self.assertTrue(util.extended_date(0, 1, 1) < util.extended_date(0, 1, 2))
245        self.assertTrue(util.extended_date(0, 1, 1) <= util.extended_date(0, 1, 2))
246        self.assertTrue(util.extended_date(0, 1, 1) != util.extended_date(0, 1, 2))
247        self.assertFalse(util.extended_date(0, 1, 1) == util.extended_date(0, 1, 2))
248        self.assertFalse(util.extended_date(0, 1, 1) >= util.extended_date(0, 1, 2))
249        self.assertFalse(util.extended_date(0, 1, 1) > util.extended_date(0, 1, 2))
250
251        self.assertFalse(util.extended_date(0, 1, 3) < util.extended_date(0, 1, 2))
252        self.assertFalse(util.extended_date(0, 1, 3) <= util.extended_date(0, 1, 2))
253        self.assertTrue(util.extended_date(0, 1, 3) != util.extended_date(0, 1, 2))
254        self.assertFalse(util.extended_date(0, 1, 3) == util.extended_date(0, 1, 2))
255        self.assertTrue(util.extended_date(0, 1, 3) >= util.extended_date(0, 1, 2))
256        self.assertTrue(util.extended_date(0, 1, 3) > util.extended_date(0, 1, 2))
257
258        with self.assertRaises(TypeError):
259            util.extended_date(0, 1, 1) < "0000-01-02"
260
261    def test_extended_datetime_compare(self):
262        self.assertTrue(util.extended_datetime(0, 1, 1) < datetime(1, 1, 1))
263        self.assertTrue(util.extended_datetime(0, 1, 1) <= datetime(1, 1, 1))
264        self.assertTrue(util.extended_datetime(0, 1, 1) != datetime(1, 1, 1))
265        self.assertFalse(util.extended_datetime(0, 1, 1) == datetime(1, 1, 1))
266        self.assertFalse(util.extended_datetime(0, 1, 1) >= datetime(1, 1, 1))
267        self.assertFalse(util.extended_datetime(0, 1, 1) > datetime(1, 1, 1))
268
269        self.assertFalse(util.extended_datetime(0, 1, 1) < util.extended_datetime(0, 1, 1))
270        self.assertTrue(util.extended_datetime(0, 1, 1) <= util.extended_datetime(0, 1, 1))
271        self.assertFalse(util.extended_datetime(0, 1, 1) != util.extended_datetime(0, 1, 1))
272        self.assertTrue(util.extended_datetime(0, 1, 1) == util.extended_datetime(0, 1, 1))
273        self.assertTrue(util.extended_datetime(0, 1, 1) >= util.extended_datetime(0, 1, 1))
274        self.assertFalse(util.extended_datetime(0, 1, 1) > util.extended_datetime(0, 1, 1))
275
276        self.assertTrue(util.extended_datetime(0, 1, 1) < util.extended_datetime(0, 1, 2))
277        self.assertTrue(util.extended_datetime(0, 1, 1) <= util.extended_datetime(0, 1, 2))
278        self.assertTrue(util.extended_datetime(0, 1, 1) != util.extended_datetime(0, 1, 2))
279        self.assertFalse(util.extended_datetime(0, 1, 1) == util.extended_datetime(0, 1, 2))
280        self.assertFalse(util.extended_datetime(0, 1, 1) >= util.extended_datetime(0, 1, 2))
281        self.assertFalse(util.extended_datetime(0, 1, 1) > util.extended_datetime(0, 1, 2))
282
283        self.assertFalse(util.extended_datetime(0, 1, 3) < util.extended_datetime(0, 1, 2))
284        self.assertFalse(util.extended_datetime(0, 1, 3) <= util.extended_datetime(0, 1, 2))
285        self.assertTrue(util.extended_datetime(0, 1, 3) != util.extended_datetime(0, 1, 2))
286        self.assertFalse(util.extended_datetime(0, 1, 3) == util.extended_datetime(0, 1, 2))
287        self.assertTrue(util.extended_datetime(0, 1, 3) >= util.extended_datetime(0, 1, 2))
288        self.assertTrue(util.extended_datetime(0, 1, 3) > util.extended_datetime(0, 1, 2))
289        self.assertTrue(
290            util.extended_datetime(0, 12, 31, 21, 4, 5, 6, util.create_timezone(timedelta(hours=-8)))
291            == datetime(1, 1, 1, 5, 4, 5, 6, utc)
292        )
293        self.assertTrue(
294            util.extended_datetime(0, 12, 31, 21, 4, 5, 6, util.create_timezone(timedelta(hours=-8)))
295            == datetime(1, 1, 1, 5, 7, 5, 6, util.create_timezone(timedelta(hours=0, minutes=3)))
296        )
297        self.assertFalse(
298            util.extended_datetime(0, 12, 31, 21, 4, 5, 6, util.create_timezone(timedelta(hours=-7)))
299            == datetime(1, 1, 1, 5, 4, 5, 6, utc)
300        )
301        self.assertFalse(util.extended_datetime(0, 1, 1) == util.extended_datetime(0, 1, 1, tzinfo=utc))
302        self.assertFalse(util.extended_datetime(0, 1, 1) == "0000-01-01")
303
304        with self.assertRaises(TypeError):
305            util.extended_datetime(0, 1, 1) < "0000-01-02"
306
307    def test_extended_datetime_arithmetic(self):
308        zone = util.create_timezone(timedelta(hours=12, minutes=45))
309        ext_dt = util.extended_datetime(0, 12, 31, 9, 17, 45, 14889, zone)
310        self.assertEqual(ext_dt + timedelta(hours=20), datetime(1, 1, 1, 5, 17, 45, 14889, zone))
311        self.assertEqual(ext_dt - timedelta(hours=20), util.extended_datetime(0, 12, 30, 13, 17, 45, 14889, zone))
312        self.assertEqual(ext_dt - ext_dt, timedelta(0))
313
314        zone2 = util.create_timezone(timedelta(hours=-8, minutes=-31))
315        ext_dt2 = util.extended_datetime(0, 11, 14, 13, 44, 20, 876543, zone2)
316        expected_diff = timedelta(days=47, hours=-4, minutes=-27, seconds=25, microseconds=-861654)
317        expected_diff -= timedelta(hours=20, minutes=76)
318        self.assertEqual(ext_dt - ext_dt2, expected_diff)
319
320        dt = datetime(400, 12, 31, 9, 17, 45, 14889, zone)
321        self.assertEqual(dt - ext_dt, timedelta(days=util.extended_datetime.DAYS_IN_400_YEARS))
322        self.assertEqual(ext_dt - dt, -timedelta(days=util.extended_datetime.DAYS_IN_400_YEARS))
323
324        with self.assertRaises(TypeError):
325            ext_dt - "test"
326
327    def test_extended_datetime_compare_tzinfo(self):
328        with self.assertRaises(TypeError):
329            self.assertTrue(util.extended_datetime(0, 1, 1, tzinfo=utc) < datetime(1, 1, 1))
330        with self.assertRaises(TypeError):
331            self.assertTrue(util.extended_datetime(0, 1, 1) < datetime(1, 1, 1, tzinfo=utc))
332
333    def test_extended_datetime_date_time(self):
334        self.assertEqual(util.extended_date(0, 1, 1), util.extended_datetime(0, 1, 1).date())
335        self.assertEqual(util.extended_date(0, 2, 29), util.extended_datetime(0, 2, 29).date())
336        self.assertEqual(time(0, 0, 0), util.extended_datetime(0, 1, 1).time())
337
338    def test_iri_to_uri(self):
339        self.assertEqual(
340            b'ldap://ldap.e-szigno.hu/CN=Microsec%20e-Szigno%20Root%20CA,OU=e-Szigno%20CA,'
341            b'O=Microsec%20Ltd.,L=Budapest,C=HU?certificateRevocationList;binary',
342            util.iri_to_uri(
343                'ldap://ldap.e-szigno.hu/CN=Microsec e-Szigno Root CA,'
344                'OU=e-Szigno CA,O=Microsec Ltd.,L=Budapest,C=HU?certificateRevocationList;binary'
345            )
346        )
347        self.assertEqual(
348            b'ldap://directory.d-trust.net/CN=D-TRUST%20Root%20Class%203%20CA%202%202009,'
349            b'O=D-Trust%20GmbH,C=DE?certificaterevocationlist',
350            util.iri_to_uri(
351                'ldap://directory.d-trust.net/CN=D-TRUST Root Class 3 CA 2 2009,'
352                'O=D-Trust GmbH,C=DE?certificaterevocationlist'
353            )
354        )
355        self.assertEqual(
356            b'ldap://directory.d-trust.net/CN=D-TRUST%20Root%20Class%203%20CA%202%20EV%202009,'
357            b'O=D-Trust%20GmbH,C=DE?certificaterevocationlist',
358            util.iri_to_uri(
359                'ldap://directory.d-trust.net/CN=D-TRUST Root Class 3 CA 2 EV 2009,'
360                'O=D-Trust GmbH,C=DE?certificaterevocationlist'
361            )
362        )
363