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