| 12
 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
 
 | #!/usr/bin/python2.7
import os.path
import sys
sys.path.insert(0, os.path.join('build', 'dist'))
from datetime import datetime, timedelta
import re
from time import strptime
import unittest
import pytz
class ZdumpTestCase(unittest.TestCase):
    def utc_to_local_check(self, zone, utc_dt, loc_dt, loc_tzname, is_dst):
        loc_tz = pytz.timezone(zone)
        self.assertEqual(
            utc_dt.astimezone(loc_tz).replace(tzinfo=None),
            loc_dt.replace(tzinfo=None)
        )
    def local_to_utc_check(self, zone, utc_dt, loc_dt, loc_tzname, is_dst):
        self.assertEqual(
            loc_dt.astimezone(pytz.utc).replace(tzinfo=None),
            utc_dt.replace(tzinfo=None)
        )
def test_suite():
    testcases = []
    raw_data = open(
        os.path.join(os.path.dirname(__file__), 'zdump.out'), 'r').readlines()
    last_zone = None
    test_class = None
    zdump_line_re = re.compile(r'''(?x)
        ^([^\s]+) \s+ (.+) \s UT \s+ = \s+ (.+) \s ([^\s]+) \s+
                               isdst=(0|1) \s+ gmtoff=[\-\d]+ \s*$
        ''')
    for i in range(0, len(raw_data)):
        line = raw_data[i]
        m = zdump_line_re.search(line)
        if m is None:
            raise RuntimeError('Dud line %r' % (line,))
        zone, utc_string, loc_string, tzname, is_dst = m.groups()
        is_dst = bool(int(is_dst))
        if zone != last_zone:
            classname = zone.replace(
                '+', '_plus_').replace('-', '_minus_').replace('/', '_')
            test_class = type(classname, (ZdumpTestCase,), {})
            testcases.append(test_class)
            last_zone = zone
            skip_next_local = False
        utc_dt = datetime(
            *strptime(utc_string, '%a %b %d %H:%M:%S %Y')[:6])
        loc_dt = datetime(
            *strptime(loc_string, '%a %b %d %H:%M:%S %Y')[:6])
        def round_dt(loc_dt, utc_dt):
            # Urgh - utcoffset() and dst() have to be rounded to the nearest
            # minute, so we need to break our tests to match this limitation
            real_offset = loc_dt - utc_dt
            secs = real_offset.seconds + real_offset.days * 86400
            fake_offset = timedelta(seconds=int((secs + 30) // 60) * 60)
            return utc_dt + fake_offset
        loc_dt = round_dt(loc_dt, utc_dt)
        # If the naive time on the next line is less than on this
        # line, and we aren't seeing an end-of-dst transition, then
        # we can't do our local->utc tests for either this nor the
        # next line since we are in an ambiguous time period (ie.
        # we have wound back the clock but don't have differing
        # is_dst flags to resolve the ambiguity)
        skip_local = skip_next_local
        skip_next_local = False
        try:
            m = zdump_line_re.match(raw_data[i + 1])
        except IndexError:
            m = None
        if m is not None:
            (next_zone, next_utc_string, next_loc_string,
                next_tzname, next_is_dst) = m.groups()
            next_is_dst = bool(int(next_is_dst))
            if next_zone == zone and next_is_dst == is_dst:
                next_utc_dt = datetime(
                    *strptime(next_utc_string, '%a %b %d %H:%M:%S %Y')[:6])
                next_loc_dt = round_dt(
                    datetime(*strptime(
                        next_loc_string, '%a %b %d %H:%M:%S %Y')[:6]),
                    next_utc_dt)
                if next_loc_dt <= loc_dt:
                    skip_local = True
                    skip_next_local = True
        loc_tz = pytz.timezone(zone)
        loc_dt = loc_tz.localize(loc_dt, is_dst)
        utc_dt = pytz.utc.localize(utc_dt)
        test_name = 'test_utc_to_local_%04d_%02d_%02d_%02d_%02d_%02d' % (
            utc_dt.year, utc_dt.month, utc_dt.day,
            utc_dt.hour, utc_dt.minute, utc_dt.second)
        def test_utc_to_local(
                self, zone=zone, utc_dt=utc_dt, loc_dt=loc_dt,
                tzname=tzname, is_dst=is_dst):
            self.utc_to_local_check(zone, utc_dt, loc_dt, tzname, is_dst)
        test_utc_to_local.__name__ = test_name
        setattr(test_class, test_name, test_utc_to_local)
        if not skip_local:
            test_name = 'test_local_to_utc_%04d_%02d_%02d_%02d_%02d_%02d' % (
                loc_dt.year, loc_dt.month, loc_dt.day,
                loc_dt.hour, loc_dt.minute, loc_dt.second)
            if is_dst:
                test_name += '_dst'
            else:
                test_name += '_nodst'
            def test_local_to_utc(
                    self, zone=zone, utc_dt=utc_dt, loc_dt=loc_dt,
                    tzname=tzname, is_dst=is_dst):
                self.local_to_utc_check(zone, utc_dt, loc_dt, tzname, is_dst)
            test_local_to_utc.__name__ = test_name
            setattr(test_class, test_name, test_local_to_utc)
    classname = zone.replace(
        '+', '_plus_').replace('-', '_minus_').replace('/', '_')
    test_class = type(classname, (ZdumpTestCase,), {})
    testcases.append(test_class)
    suite = unittest.TestSuite()
    while testcases:
        suite.addTest(unittest.makeSuite(testcases.pop()))
    return suite
if __name__ == '__main__':
    unittest.main(defaultTest='test_suite')
 |