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