• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zopefoundation / zope.i18n / 16399678496

27 Sep 2024 06:55AM UTC coverage: 98.997% (-0.02%) from 99.018%
16399678496

push

github

icemac
Back to development: 5.3

747 of 784 branches covered (95.28%)

Branch coverage included in aggregate %.

3203 of 3206 relevant lines covered (99.91%)

1.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.34
/src/zope/i18n/tests/test_formats.py
1
##############################################################################
2
#
3
# Copyright (c) 2002, 2003 Zope Foundation and Contributors.
4
# All Rights Reserved.
5
#
6
# This software is subject to the provisions of the Zope Public License,
7
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
8
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11
# FOR A PARTICULAR PURPOSE.
12
#
13
##############################################################################
14
"""This module tests the Formats and everything that goes with it.
15
"""
16
import datetime
1✔
17
import decimal
1✔
18
import pickle
1✔
19
from unittest import TestCase
1✔
20

21
import pytz
1✔
22

23
from zope.i18n.format import DateTimeFormat
1✔
24
from zope.i18n.format import DateTimeParseError
1✔
25
from zope.i18n.format import DateTimePatternParseError
1✔
26
from zope.i18n.format import NumberFormat
1✔
27
from zope.i18n.format import NumberParseError
1✔
28
from zope.i18n.format import NumberPatternParseError
1✔
29
from zope.i18n.format import buildDateTimeParseInfo
1✔
30
from zope.i18n.format import parseDateTimePattern
1✔
31
from zope.i18n.format import parseNumberPattern
1✔
32
from zope.i18n.interfaces import IDateTimeFormat
1✔
33
from zope.i18n.interfaces import INumberFormat
1✔
34

35

36
class LocaleStub:
1✔
37
    pass
1✔
38

39

40
class LocaleCalendarStub:
1✔
41

42
    type = "gregorian"
1✔
43

44
    months = {
1✔
45
        1: ('Januar', 'Jan'),
46
        2: ('Februar', 'Feb'),
47
        3: ('Maerz', 'Mrz'),
48
        4: ('April', 'Apr'),
49
        5: ('Mai', 'Mai'),
50
        6: ('Juni', 'Jun'),
51
        7: ('Juli', 'Jul'),
52
        8: ('August', 'Aug'),
53
        9: ('September', 'Sep'),
54
        10: ('Oktober', 'Okt'),
55
        11: ('November', 'Nov'),
56
        12: ('Dezember', 'Dez')
57
    }
58

59
    days = {
1✔
60
        1: ('Montag', 'Mo'),
61
        2: ('Dienstag', 'Di'),
62
        3: ('Mittwoch', 'Mi'),
63
        4: ('Donnerstag', 'Do'),
64
        5: ('Freitag', 'Fr'),
65
        6: ('Samstag', 'Sa'),
66
        7: ('Sonntag', 'So')
67
    }
68

69
    am = 'vorm.'
1✔
70
    pm = 'nachm.'
1✔
71

72
    eras = {1: (None, 'v. Chr.'), 2: (None, 'n. Chr.')}
1✔
73

74
    week = {'firstDay': 1, 'minDays': 1}
1✔
75

76
    def getMonthNames(self):
1✔
77
        return [
1✔
78
            self.months.get(type, (None, None))[0] for type in range(1, 13)
79
        ]
80

81
    def getMonthTypeFromName(self, name):
1✔
82
        for item in self.months.items():
1!
83
            if item[1][0] == name:
1!
84
                return item[0]
1✔
85

86
    def getMonthAbbreviations(self):
1✔
87
        return [
1✔
88
            self.months.get(type, (None, None))[1] for type in range(1, 13)
89
        ]
90

91
    def getMonthTypeFromAbbreviation(self, abbr):
1✔
92
        for item in self.months.items():
1!
93
            if item[1][1] == abbr:
1!
94
                return item[0]
1✔
95

96
    def getDayNames(self):
1✔
97
        return [self.days.get(type, (None, None))[0] for type in range(1, 8)]
1✔
98

99
    def getDayTypeFromName(self, name):
1✔
100
        raise NotImplementedError()
101

102
    def getDayAbbreviations(self):
1✔
103
        return [self.days.get(type, (None, None))[1] for type in range(1, 8)]
1✔
104

105
    def getDayTypeFromAbbreviation(self, abbr):
1✔
106
        raise NotImplementedError()
107

108

109
class TestDateTimePatternParser(TestCase):
1✔
110
    """Extensive tests for the ICU-based-syntax datetime pattern parser."""
111

112
    def testParseSimpleTimePattern(self):
1✔
113
        self.assertEqual(parseDateTimePattern('HH'), [('H', 2)])
1✔
114
        self.assertEqual(parseDateTimePattern('HH:mm'), [('H', 2), ':',
1✔
115
                                                         ('m', 2)])
116
        self.assertEqual(parseDateTimePattern('HH:mm:ss'), [('H', 2), ':',
1✔
117
                                                            ('m', 2), ':',
118
                                                            ('s', 2)])
119
        self.assertEqual(parseDateTimePattern('mm:ss'), [('m', 2), ':',
1✔
120
                                                         ('s', 2)])
121
        self.assertEqual(parseDateTimePattern('H:m:s'),
1✔
122
                         [('H', 1), ':', ('m', 1), ':', ('s', 1)])
123
        self.assertEqual(parseDateTimePattern('HHH:mmmm:sssss'),
1✔
124
                         [('H', 3), ':', ('m', 4), ':', ('s', 5)])
125

126
    def testParseGermanTimePattern(self):
1✔
127
        # German full
128
        self.assertEqual(parseDateTimePattern("H:mm' Uhr 'z"),
1✔
129
                         [('H', 1), ':', ('m', 2), ' Uhr ', ('z', 1)])
130
        # German long
131
        self.assertEqual(parseDateTimePattern("HH:mm:ss z"), [('H', 2), ':',
1✔
132
                                                              ('m', 2), ':',
133
                                                              ('s', 2), ' ',
134
                                                              ('z', 1)])
135
        # German medium
136
        self.assertEqual(parseDateTimePattern("HH:mm:ss"), [('H', 2), ':',
1✔
137
                                                            ('m', 2), ':',
138
                                                            ('s', 2)])
139
        # German short
140
        self.assertEqual(parseDateTimePattern("HH:mm"), [('H', 2), ':',
1✔
141
                                                         ('m', 2)])
142

143
    def testParseRealDate(self):
1✔
144
        # German full
145
        self.assertEqual(parseDateTimePattern("EEEE, d. MMMM yyyy"),
1✔
146
                         [('E', 4), ', ', ('d', 1), '. ', ('M', 4), ' ',
147
                          ('y', 4)])
148
        # German long
149
        self.assertEqual(parseDateTimePattern("d. MMMM yyyy"), [('d', 1), '. ',
1✔
150
                                                                ('M', 4), ' ',
151
                                                                ('y', 4)])
152
        # German medium
153
        self.assertEqual(parseDateTimePattern("dd.MM.yyyy"), [('d', 2), '.',
1✔
154
                                                              ('M', 2), '.',
155
                                                              ('y', 4)])
156
        # German short
157
        self.assertEqual(parseDateTimePattern("dd.MM.yy"), [('d', 2), '.',
1✔
158
                                                            ('M', 2), '.',
159
                                                            ('y', 2)])
160

161
    def testParseRealDateTime(self):
1✔
162
        # German full
163
        self.assertEqual(
1✔
164
            parseDateTimePattern("EEEE, d. MMMM yyyy H:mm' Uhr 'z"),
165
            [('E', 4), ', ', ('d', 1), '. ', ('M', 4), ' ', ('y', 4), ' ',
166
             ('H', 1), ':', ('m', 2), ' Uhr ', ('z', 1)])
167
        # German long
168
        self.assertEqual(parseDateTimePattern("d. MMMM yyyy HH:mm:ss z"),
1✔
169
                         [('d', 1), '. ', ('M', 4), ' ', ('y', 4), ' ',
170
                          ('H', 2), ':', ('m', 2), ':', ('s', 2), ' ',
171
                          ('z', 1)])
172
        # German medium
173
        self.assertEqual(parseDateTimePattern("dd.MM.yyyy HH:mm:ss"),
1✔
174
                         [('d', 2), '.', ('M', 2), '.', ('y', 4), ' ',
175
                          ('H', 2), ':', ('m', 2), ':', ('s', 2)])
176
        # German short
177
        self.assertEqual(parseDateTimePattern("dd.MM.yy HH:mm"),
1✔
178
                         [('d', 2), '.', ('M', 2), '.', ('y', 2), ' ',
179
                          ('H', 2), ':', ('m', 2)])
180

181
    def testParseQuotesInPattern(self):
1✔
182
        self.assertEqual(parseDateTimePattern("HH''mm"), [('H', 2), "'",
1✔
183
                                                          ('m', 2)])
184
        self.assertEqual(parseDateTimePattern("HH'HHmm'mm"), [('H', 2), 'HHmm',
1✔
185
                                                              ('m', 2)])
186
        self.assertEqual(parseDateTimePattern("HH':'''':'mm"),
1✔
187
                         [('H', 2), ":':", ('m', 2)])
188
        self.assertEqual(parseDateTimePattern("HH':' ':'mm"), [('H', 2), ": :",
1✔
189
                                                               ('m', 2)])
190

191
    def testParseDateTimePatternError(self):
1✔
192
        # Quote not closed
193
        with self.assertRaisesRegex(
1✔
194
                DateTimePatternParseError,
195
                'The quote starting at character 2 is not closed.'):
196
            parseDateTimePattern("HH' Uhr")
1✔
197

198
        # Test correct length of characters in datetime fields
199
        # XXX: This should actually fail, but it doesn't. Why not?
200
        parseDateTimePattern("HHHHH")
1✔
201

202
    def testParseDateTimePatternRepeatDateTimeChars(self):
1✔
203
        result = parseDateTimePattern('aG')
1✔
204
        self.assertEqual(result, [('a', 1), ('G', 1)])
1✔
205

206

207
class TestBuildDateTimeParseInfo(TestCase):
1✔
208
    """This class tests the functionality of the buildDateTimeParseInfo()
209
    method with the German locale.
210
    """
211

212
    def info(self, entry):
1✔
213
        info = buildDateTimeParseInfo(LocaleCalendarStub(), [entry])
1✔
214
        return info[entry]
1✔
215

216
    def testGenericNumbers(self):
1✔
217
        for char in 'dDFkKhHmsSwW':
1✔
218
            for length in range(1, 6):
1✔
219
                self.assertEqual(self.info((char, length)),
1✔
220
                                 '([0-9]{%i,1000})' % length)
221

222
    def testYear(self):
1✔
223
        self.assertEqual(self.info(('y', 2)), '([0-9]{2})')
1✔
224
        self.assertEqual(self.info(('y', 4)), '([0-9]{4})')
1✔
225
        self.assertRaises(DateTimePatternParseError, self.info, ('y', 1))
1✔
226
        self.assertRaises(DateTimePatternParseError, self.info, ('y', 3))
1✔
227
        self.assertRaises(DateTimePatternParseError, self.info, ('y', 5))
1✔
228

229
    def testAMPMMarker(self):
1✔
230
        names = ['vorm.', 'nachm.']
1✔
231
        for length in range(1, 6):
1✔
232
            self.assertEqual(self.info(('a', length)),
1✔
233
                             '(' + '|'.join(names) + ')')
234

235
    def testEra(self):
1✔
236
        self.assertEqual(self.info(('G', 1)), '(v. Chr.|n. Chr.)')
1✔
237

238
    def testTimeZone(self):
1✔
239
        self.assertEqual(self.info(('z', 1)), r'([\+-][0-9]{3,4})')
1✔
240
        self.assertEqual(self.info(('z', 2)), r'([\+-][0-9]{2}:[0-9]{2})')
1✔
241
        self.assertEqual(self.info(('z', 3)), r'([a-zA-Z]{3})')
1✔
242
        self.assertEqual(self.info(('z', 4)), r'([a-zA-Z /\.]*)')
1✔
243
        self.assertEqual(self.info(('z', 5)), r'([a-zA-Z /\.]*)')
1✔
244

245
    def testMonthNumber(self):
1✔
246
        self.assertEqual(self.info(('M', 1)), '([0-9]{1,2})')
1✔
247
        self.assertEqual(self.info(('M', 2)), '([0-9]{2})')
1✔
248

249
    def testMonthNames(self):
1✔
250
        names = [
1✔
251
            "Januar", "Februar", "Maerz", "April", "Mai", "Juni", "Juli",
252
            "August", "September", "Oktober", "November", "Dezember"
253
        ]
254
        self.assertEqual(self.info(('M', 4)), '(' + '|'.join(names) + ')')
1✔
255

256
    def testMonthAbbr(self):
1✔
257
        names = [
1✔
258
            'Jan', 'Feb', 'Mrz', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep',
259
            'Okt', 'Nov', 'Dez'
260
        ]
261
        self.assertEqual(self.info(('M', 3)), '(' + '|'.join(names) + ')')
1✔
262

263
    def testWeekdayNumber(self):
1✔
264
        self.assertEqual(self.info(('E', 1)), '([0-9])')
1✔
265
        self.assertEqual(self.info(('E', 2)), '([0-9]{2})')
1✔
266

267
    def testWeekdayNames(self):
1✔
268
        names = [
1✔
269
            'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag',
270
            'Samstag', 'Sonntag'
271
        ]
272
        self.assertEqual(self.info(('E', 4)), '(' + '|'.join(names) + ')')
1✔
273
        self.assertEqual(self.info(('E', 5)), '(' + '|'.join(names) + ')')
1✔
274
        self.assertEqual(self.info(('E', 10)), '(' + '|'.join(names) + ')')
1✔
275

276
    def testWeekdayAbbr(self):
1✔
277
        names = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So']
1✔
278
        self.assertEqual(self.info(('E', 3)), '(' + '|'.join(names) + ')')
1✔
279

280

281
class TestDateTimeFormat(TestCase):
1✔
282
    """Test the functionality of an implmentation of the ILocaleProvider
283
    interface."""
284

285
    format = DateTimeFormat(calendar=LocaleCalendarStub())
1✔
286

287
    def testInterfaceConformity(self):
1✔
288
        self.assertTrue(IDateTimeFormat.providedBy(self.format))
1✔
289

290
    def testParseSimpleDateTime(self):
1✔
291
        # German short
292
        self.assertEqual(self.format.parse('02.01.03 21:48', 'dd.MM.yy HH:mm'),
1✔
293
                         datetime.datetime(2003, 1, 2, 21, 48))
294

295
    def testParseRealDateTime(self):
1✔
296
        # German medium
297
        self.assertEqual(
1✔
298
            self.format.parse('02.01.2003 21:48:01', 'dd.MM.yyyy HH:mm:ss'),
299
            datetime.datetime(2003, 1, 2, 21, 48, 1))
300

301
        # German long
302
        # TODO: The parser does not support timezones yet.
303
        self.assertEqual(
1✔
304
            self.format.parse('2. Januar 2003 21:48:01 +100',
305
                              'd. MMMM yyyy HH:mm:ss z'),
306
            pytz.timezone('Europe/Berlin').localize(
307
                datetime.datetime(2003, 1, 2, 21, 48, 1)))
308

309
        # German full
310
        # TODO: The parser does not support timezones yet.
311
        self.assertEqual(
1✔
312
            self.format.parse('Donnerstag, 2. Januar 2003 21:48 Uhr +100',
313
                              "EEEE, d. MMMM yyyy H:mm' Uhr 'z"),
314
            pytz.timezone('Europe/Berlin').localize(
315
                datetime.datetime(2003, 1, 2, 21, 48)))
316

317
    def testParseAMPMDateTime(self):
1✔
318
        self.assertEqual(
1✔
319
            self.format.parse('02.01.03 09:48 nachm.', 'dd.MM.yy hh:mm a'),
320
            datetime.datetime(2003, 1, 2, 21, 48))
321

322
    def testParseTimeZone(self):
1✔
323
        dt = self.format.parse('09:48 -600', 'HH:mm z')
1✔
324
        self.assertEqual(pickle.loads(pickle.dumps(dt)), dt)
1✔
325
        self.assertEqual(dt.tzinfo.utcoffset(dt), datetime.timedelta(hours=-6))
1✔
326
        self.assertEqual(dt.tzinfo.zone, None)
1✔
327
        self.assertEqual(dt.tzinfo.tzname(dt), None)
1✔
328

329
        dt = self.format.parse('09:48 -06:00', 'HH:mm zz')
1✔
330
        self.assertEqual(pickle.loads(pickle.dumps(dt)), dt)
1✔
331
        self.assertEqual(dt.tzinfo.utcoffset(dt), datetime.timedelta(hours=-6))
1✔
332
        self.assertEqual(dt.tzinfo.zone, None)
1✔
333
        self.assertEqual(dt.tzinfo.tzname(dt), None)
1✔
334

335
    def testParseTimeZoneNames(self):
1✔
336
        # Note that EST is a deprecated timezone name since it is a US
337
        # interpretation (other countries also use the EST timezone
338
        # abbreviation)
339
        dt = self.format.parse('01.01.2003 09:48 EST', 'dd.MM.yyyy HH:mm zzz')
1✔
340
        self.assertEqual(pickle.loads(pickle.dumps(dt)), dt)
1✔
341
        self.assertEqual(dt.tzinfo.utcoffset(dt), datetime.timedelta(hours=-5))
1✔
342
        self.assertEqual(dt.tzinfo.zone, 'EST')
1✔
343
        self.assertEqual(dt.tzinfo.tzname(dt), 'EST')
1✔
344

345
        dt = self.format.parse('01.01.2003 09:48 US/Eastern',
1✔
346
                               'dd.MM.yyyy HH:mm zzzz')
347
        self.assertEqual(pickle.loads(pickle.dumps(dt)), dt)
1✔
348
        self.assertEqual(dt.tzinfo.utcoffset(dt), datetime.timedelta(hours=-5))
1✔
349
        self.assertEqual(dt.tzinfo.zone, 'US/Eastern')
1✔
350
        self.assertEqual(dt.tzinfo.tzname(dt), 'EST')
1✔
351

352
        dt = self.format.parse('01.01.2003 09:48 Canada/Eastern',
1✔
353
                               'dd.MM.yyyy HH:mm zzzz')
354
        self.assertEqual(dt.tzinfo.utcoffset(dt), datetime.timedelta(hours=-5))
1✔
355
        self.assertEqual(dt.tzinfo.zone, 'Canada/Eastern')
1✔
356
        self.assertEqual(dt.tzinfo.tzname(dt), 'EST')
1✔
357

358
        # Note that historical and future (as far as known)
359
        # timezones are handled happily using the pytz timezone database
360
        # US DST transition points are changing in 2007
361
        dt = self.format.parse('01.04.2006 09:48 US/Eastern',
1✔
362
                               'dd.MM.yyyy HH:mm zzzz')
363
        self.assertEqual(dt.tzinfo.zone, 'US/Eastern')
1✔
364
        self.assertEqual(dt.tzinfo.tzname(dt), 'EST')
1✔
365
        self.assertEqual(dt.tzinfo.utcoffset(dt), datetime.timedelta(hours=-5))
1✔
366
        dt = self.format.parse('01.04.2007 09:48 US/Eastern',
1✔
367
                               'dd.MM.yyyy HH:mm zzzz')
368
        self.assertEqual(dt.tzinfo.zone, 'US/Eastern')
1✔
369
        self.assertEqual(dt.tzinfo.tzname(dt), 'EDT')
1✔
370
        self.assertEqual(dt.tzinfo.utcoffset(dt), datetime.timedelta(hours=-4))
1✔
371

372
    def testDateTimeParseError(self):
1✔
373
        with self.assertRaises(DateTimeParseError):
1✔
374
            self.format.parse('02.01.03 21:48', 'dd.MM.yyyy HH:mm')
1✔
375
        with self.assertRaises(DateTimeParseError):
1✔
376
            self.format.parse('02.01.2003', 'dd.MM.yy')
1✔
377
        with self.assertRaises(DateTimeParseError):
1✔
378
            self.format.parse('ff02.01.03', 'dd.MM.yy')
1✔
379

380
    def testParse12PM(self):
1✔
381
        self.assertEqual(
1✔
382
            self.format.parse('01.01.03 12:00 nachm.', 'dd.MM.yy hh:mm a'),
383
            datetime.datetime(2003, 1, 1, 12, 00, 00, 00))
384

385
    def testParseUnusualFormats(self):
1✔
386
        self.assertEqual(
1✔
387
            self.format.parse('001. Januar 03 0012:00',
388
                              'ddd. MMMMM yy HHHH:mm'),
389
            datetime.datetime(2003, 1, 1, 12, 00, 00, 00))
390
        self.assertEqual(
1✔
391
            self.format.parse('0001. Jan 2003 0012:00 vorm.',
392
                              'dddd. MMM yyyy hhhh:mm a'),
393
            datetime.datetime(2003, 1, 1, 00, 00, 00, 00))
394

395
    def testParseNotObject(self):
1✔
396
        self.assertEqual(('2017', '01', '01'),
1✔
397
                         self.format.parse('2017-01-01',
398
                                           'yyyy-MM-dd',
399
                                           asObject=False))
400

401
    def testParseTwoDigitYearIs20thCentury(self):
1✔
402
        self.assertEqual(datetime.date(1952, 1, 1),
1✔
403
                         self.format.parse('52-01-01', 'yy-MM-dd'))
404

405
        # 30 is the cut off
406
        self.assertEqual(datetime.date(1931, 1, 1),
1✔
407
                         self.format.parse('31-01-01', 'yy-MM-dd'))
408

409
        self.assertEqual(datetime.date(2030, 1, 1),
1✔
410
                         self.format.parse('30-01-01', 'yy-MM-dd'))
411

412
    def testParseAMPMMissing(self):
1✔
413
        with self.assertRaisesRegex(
1✔
414
                DateTimeParseError,
415
                'Cannot handle 12-hour format without am/pm marker.'):
416
            self.format.parse('02.01.03 09:48', 'dd.MM.yy hh:mm')
1✔
417

418
    def testParseBadTimezone(self):
1✔
419
        # Produces an object without pytz info
420
        self.assertEqual(
1✔
421
            datetime.time(21, 48, 1),
422
            self.format.parse('21:48:01 Bad/Timezone', 'HH:mm:ss zzzz'))
423

424
    def testParsePyTzTimezone(self):
1✔
425
        tzinfo = pytz.timezone("US/Central")
1✔
426
        self.assertEqual(
1✔
427
            datetime.time(21, 48, 1, tzinfo=tzinfo),
428
            self.format.parse('21:48:01 US/Central', 'HH:mm:ss zzzz'))
429

430
    def testFormatSimpleDateTime(self):
1✔
431
        # German short
432
        self.assertEqual(
1✔
433
            self.format.format(datetime.datetime(2003, 1, 2, 21, 48),
434
                               'dd.MM.yy HH:mm'), '02.01.03 21:48')
435

436
    def testFormatRealDateTime(self):
1✔
437
        tz = pytz.timezone('Europe/Berlin')
1✔
438
        dt = tz.localize(datetime.datetime(2003, 1, 2, 21, 48, 1))
1✔
439
        # German medium
440
        self.assertEqual(self.format.format(dt, 'dd.MM.yyyy HH:mm:ss'),
1✔
441
                         '02.01.2003 21:48:01')
442

443
        # German long
444
        self.assertEqual(self.format.format(dt, 'd. MMMM yyyy HH:mm:ss z'),
1✔
445
                         '2. Januar 2003 21:48:01 +100')
446

447
        # German full
448
        self.assertEqual(
1✔
449
            self.format.format(dt, "EEEE, d. MMMM yyyy H:mm' Uhr 'z"),
450
            'Donnerstag, 2. Januar 2003 21:48 Uhr +100')
451

452
    def testFormatAMPMDateTime(self):
1✔
453
        self.assertEqual(
1✔
454
            self.format.format(datetime.datetime(2003, 1, 2, 21, 48),
455
                               'dd.MM.yy hh:mm a'), '02.01.03 09:48 nachm.')
456

457
    def testFormatAllWeekdays(self):
1✔
458
        for day in range(1, 8):
1✔
459
            self.assertEqual(
1✔
460
                self.format.format(datetime.datetime(2003, 1, day + 5, 21, 48),
461
                                   "EEEE, d. MMMM yyyy H:mm' Uhr 'z"),
462
                '%s, %i. Januar 2003 21:48 Uhr +000' %
463
                (self.format.calendar.days[day][0], day + 5))
464

465
    def testFormatTimeZone(self):
1✔
466
        self.assertEqual(
1✔
467
            self.format.format(datetime.datetime(2003, 1, 2, 12, 00), 'z'),
468
            '+000')
469
        self.assertEqual(
1✔
470
            self.format.format(datetime.datetime(2003, 1, 2, 12, 00), 'zz'),
471
            '+00:00')
472
        self.assertEqual(
1✔
473
            self.format.format(datetime.datetime(2003, 1, 2, 12, 00), 'zzz'),
474
            'UTC')
475
        self.assertEqual(
1✔
476
            self.format.format(datetime.datetime(2003, 1, 2, 12, 00), 'zzzz'),
477
            'UTC')
478
        tz = pytz.timezone('US/Eastern')
1✔
479
        self.assertEqual(
1✔
480
            self.format.format(tz.localize(datetime.datetime(2003, 1, 2, 12)),
481
                               'z'), '-500')
482
        self.assertEqual(
1✔
483
            self.format.format(tz.localize(datetime.datetime(2003, 1, 2, 12)),
484
                               'zz'), '-05:00')
485
        self.assertEqual(
1✔
486
            self.format.format(tz.localize(datetime.datetime(2003, 1, 2, 12)),
487
                               'zzz'), 'EST')
488
        self.assertEqual(
1✔
489
            self.format.format(tz.localize(datetime.datetime(2003, 1, 2, 12)),
490
                               'zzzz'), 'US/Eastern')
491

492
    def testFormatWeekDay(self):
1✔
493
        date = datetime.date(2003, 1, 2)
1✔
494
        self.assertEqual(self.format.format(date, "E"), '4')
1✔
495
        self.assertEqual(self.format.format(date, "EE"), '04')
1✔
496
        self.assertEqual(self.format.format(date, "EEE"), 'Do')
1✔
497
        self.assertEqual(self.format.format(date, "EEEE"), 'Donnerstag')
1✔
498

499
        # Create custom calendar, which has Sunday as the first day of the
500
        # week. I am assigning a totally new dict here, since dicts are
501
        # mutable and the value would be changed for the class and all its
502
        # instances.
503
        calendar = LocaleCalendarStub()
1✔
504
        calendar.week = {'firstDay': 7, 'minDays': 1}
1✔
505
        format = DateTimeFormat(calendar=calendar)
1✔
506

507
        self.assertEqual(format.format(date, "E"), '5')
1✔
508
        self.assertEqual(format.format(date, "EE"), '05')
1✔
509

510
    def testFormatDayOfWeekInMonth(self):
1✔
511
        date = datetime.date(2003, 1, 2)
1✔
512
        self.assertEqual(self.format.format(date, "F"), '1')
1✔
513
        self.assertEqual(self.format.format(date, "FF"), '01')
1✔
514
        self.assertEqual(self.format.format(datetime.date(2003, 1, 9), "F"),
1✔
515
                         '2')
516
        self.assertEqual(self.format.format(datetime.date(2003, 1, 16), "F"),
1✔
517
                         '3')
518
        self.assertEqual(self.format.format(datetime.date(2003, 1, 23), "F"),
1✔
519
                         '4')
520

521
    def testFormatWeekInMonth(self):
1✔
522
        self.assertEqual(self.format.format(datetime.date(2003, 1, 3), "W"),
1✔
523
                         '1')
524
        self.assertEqual(self.format.format(datetime.date(2003, 1, 3), "WW"),
1✔
525
                         '01')
526
        self.assertEqual(self.format.format(datetime.date(2003, 1, 8), "W"),
1✔
527
                         '2')
528
        self.assertEqual(self.format.format(datetime.date(2003, 1, 19), "W"),
1✔
529
                         '3')
530
        self.assertEqual(self.format.format(datetime.date(2003, 1, 20), "W"),
1✔
531
                         '4')
532
        self.assertEqual(self.format.format(datetime.date(2003, 1, 31), "W"),
1✔
533
                         '5')
534

535
    def testFormatHourInDayOneTo24(self):
1✔
536
        self.assertEqual(self.format.format(datetime.time(5, 0), "k"), '5')
1✔
537
        self.assertEqual(self.format.format(datetime.time(5, 0), "kk"), '05')
1✔
538
        self.assertEqual(self.format.format(datetime.time(0, 0), "k"), '24')
1✔
539
        self.assertEqual(self.format.format(datetime.time(1, 0), "k"), '1')
1✔
540

541
    def testFormatHourInDayZeroToEleven(self):
1✔
542
        self.assertEqual(self.format.format(datetime.time(5, 0), "K"), '5')
1✔
543
        self.assertEqual(self.format.format(datetime.time(5, 0), "KK"), '05')
1✔
544
        self.assertEqual(self.format.format(datetime.time(0, 0), "K"), '0')
1✔
545
        self.assertEqual(self.format.format(datetime.time(12, 0), "K"), '0')
1✔
546
        self.assertEqual(self.format.format(datetime.time(11, 0), "K"), '11')
1✔
547
        self.assertEqual(self.format.format(datetime.time(23, 0), "K"), '11')
1✔
548

549
    def testFormatSimpleHourRepresentation(self):
1✔
550
        self.assertEqual(
1✔
551
            self.format.format(datetime.datetime(2003, 1, 2, 23, 00),
552
                               'dd.MM.yy h:mm:ss a'),
553
            '02.01.03 11:00:00 nachm.')
554
        self.assertEqual(
1✔
555
            self.format.format(datetime.datetime(2003, 1, 2, 2, 00),
556
                               'dd.MM.yy h:mm:ss a'), '02.01.03 2:00:00 vorm.')
557
        self.assertEqual(self.format.format(datetime.time(0, 15), 'h:mm a'),
1✔
558
                         '12:15 vorm.')
559
        self.assertEqual(self.format.format(datetime.time(1, 15), 'h:mm a'),
1✔
560
                         '1:15 vorm.')
561
        self.assertEqual(self.format.format(datetime.time(12, 15), 'h:mm a'),
1✔
562
                         '12:15 nachm.')
563
        self.assertEqual(self.format.format(datetime.time(13, 15), 'h:mm a'),
1✔
564
                         '1:15 nachm.')
565

566
    def testFormatDayInYear(self):
1✔
567
        self.assertEqual(self.format.format(datetime.date(2003, 1, 3), 'D'),
1✔
568
                         "3")
569
        self.assertEqual(self.format.format(datetime.date(2003, 1, 3), 'DD'),
1✔
570
                         "03")
571
        self.assertEqual(self.format.format(datetime.date(2003, 1, 3), 'DDD'),
1✔
572
                         "003")
573
        self.assertEqual(self.format.format(datetime.date(2003, 12, 31), 'D'),
1✔
574
                         "365")
575
        self.assertEqual(self.format.format(datetime.date(2003, 12, 31), 'DD'),
1✔
576
                         "365")
577
        self.assertEqual(
1✔
578
            self.format.format(datetime.date(2003, 12, 31), 'DDD'), "365")
579
        self.assertEqual(
1✔
580
            self.format.format(datetime.date(2004, 12, 31), 'DDD'), "366")
581

582
    def testFormatDayOfWeekInMOnth(self):
1✔
583
        self.assertEqual(self.format.format(datetime.date(2003, 1, 3), 'F'),
1✔
584
                         "1")
585
        self.assertEqual(self.format.format(datetime.date(2003, 1, 10), 'F'),
1✔
586
                         "2")
587
        self.assertEqual(self.format.format(datetime.date(2003, 1, 17), 'F'),
1✔
588
                         "3")
589
        self.assertEqual(self.format.format(datetime.date(2003, 1, 24), 'F'),
1✔
590
                         "4")
591
        self.assertEqual(self.format.format(datetime.date(2003, 1, 31), 'F'),
1✔
592
                         "5")
593
        self.assertEqual(self.format.format(datetime.date(2003, 1, 6), 'F'),
1✔
594
                         "1")
595

596
    def testFormatUnusualFormats(self):
1✔
597
        self.assertEqual(
1✔
598
            self.format.format(datetime.date(2003, 1, 3), 'DDD-yyyy'),
599
            "003-2003")
600
        self.assertEqual(
1✔
601
            self.format.format(datetime.date(2003, 1, 10),
602
                               "F. EEEE 'im' MMMM, yyyy"),
603
            "2. Freitag im Januar, 2003")
604

605
    def testFormatGregorianEra(self):
1✔
606
        self.assertEqual(self.format.format(datetime.date(2017, 12, 17), 'G'),
1✔
607
                         'n. Chr.')
608

609
    def testFormateMonthLengthOne(self):
1✔
610
        self.assertEqual(self.format.format(datetime.date(2017, 12, 17), 'M'),
1✔
611
                         '12')
612

613

614
class TestNumberPatternParser(TestCase):
1✔
615
    """Extensive tests for the ICU-based-syntax number pattern parser."""
616

617
    def testParseSimpleIntegerPattern(self):
1✔
618
        self.assertEqual(parseNumberPattern('###0'),
1✔
619
                         ((None, '', None, '###0', '', '', None, '', None, ()),
620
                          (None, '', None, '###0', '', '', None, '', None,
621
                           ())))
622

623
    def testParseScientificIntegerPattern(self):
1✔
624
        self.assertEqual(parseNumberPattern('###0E#0'),
1✔
625
                         ((None, '', None, '###0', '', '#0', None, '', None,
626
                           ()),
627
                          (None, '', None, '###0', '', '#0', None, '', None,
628
                           ())))
629
        self.assertEqual(parseNumberPattern('###0E+#0'),
1✔
630
                         ((None, '', None, '###0', '', '+#0', None, '', None,
631
                           ()),
632
                          (None, '', None, '###0', '', '+#0', None, '', None,
633
                           ())))
634

635
    def testParsePosNegAlternativeIntegerPattern(self):
1✔
636
        self.assertEqual(parseNumberPattern('###0;#0'),
1✔
637
                         ((None, '', None, '###0', '', '', None, '', None, ()),
638
                          (None, '', None, '#0', '', '', None, '', None, ())))
639

640
    def testParsePrefixedIntegerPattern(self):
1✔
641
        self.assertEqual(parseNumberPattern('+###0'),
1✔
642
                         ((None, '+', None, '###0', '', '', None, '', None,
643
                           ()),
644
                          (None, '+', None, '###0', '', '', None, '', None,
645
                           ())))
646

647
    def testParsePosNegIntegerPattern(self):
1✔
648
        self.assertEqual(parseNumberPattern('+###0;-###0'),
1✔
649
                         ((None, '+', None, '###0', '', '', None, '', None,
650
                           ()),
651
                          (None, '-', None, '###0', '', '', None, '', None,
652
                           ())))
653

654
    def testParseScientificPosNegIntegerPattern(self):
1✔
655
        self.assertEqual(parseNumberPattern('+###0E0;-###0E#0'),
1✔
656
                         ((None, '+', None, '###0', '', '0', None, '', None,
657
                           ()),
658
                          (None, '-', None, '###0', '', '#0', None, '', None,
659
                           ())))
660

661
    def testParseThousandSeparatorIntegerPattern(self):
1✔
662
        self.assertEqual(parseNumberPattern('#,##0'),
1✔
663
                         ((None, '', None, '###0', '', '', None, '', None,
664
                           (3, 0)),
665
                          (None, '', None, '###0', '', '', None, '', None,
666
                           (3, 0))))
667

668
    def testParseSimpleDecimalPattern(self):
1✔
669
        self.assertEqual(parseNumberPattern('###0.00#'),
1✔
670
                         ((None, '', None, '###0', '00#', '', None, '', None,
671
                           ()),
672
                          (None, '', None, '###0', '00#', '', None, '', None,
673
                           ())))
674

675
    def testParseScientificDecimalPattern(self):
1✔
676
        self.assertEqual(parseNumberPattern('###0.00#E#0'),
1✔
677
                         ((None, '', None, '###0', '00#', '#0', None, '', None,
678
                           ()),
679
                          (None, '', None, '###0', '00#', '#0', None, '', None,
680
                           ())))
681

682
    def testParsePosNegAlternativeFractionPattern(self):
1✔
683
        self.assertEqual(parseNumberPattern('###0.00#;#0.0#'),
1✔
684
                         ((None, '', None, '###0', '00#', '', None, '', None,
685
                           ()),
686
                          (None, '', None, '#0', '0#', '', None, '', None,
687
                           ())))
688

689
    def testParsePosNegFractionPattern(self):
1✔
690
        self.assertEqual(parseNumberPattern('+###0.0##;-###0.0##'),
1✔
691
                         ((None, '+', None, '###0', '0##', '', None, '', None,
692
                           ()),
693
                          (None, '-', None, '###0', '0##', '', None, '', None,
694
                           ())))
695

696
    def testParseScientificPosNegFractionPattern(self):
1✔
697
        self.assertEqual(
1✔
698
            parseNumberPattern('+###0.0##E#0;-###0.0##E0'),
699
            ((None, '+', None, '###0', '0##', '#0', None, '', None, ()),
700
             (None, '-', None, '###0', '0##', '0', None, '', None, ())))
701

702
    def testParseThousandSeparatorFractionPattern(self):
1✔
703
        self.assertEqual(parseNumberPattern('#,##0.0#'),
1✔
704
                         ((None, '', None, '###0', '0#', '', None, '', None,
705
                           (3, 0)),
706
                          (None, '', None, '###0', '0#', '', None, '', None,
707
                           (3, 0))))
708

709
    def testParseThousandSeparatorPatterns(self):
1✔
710
        # the following patterns are present in the ICU XMLs:
711
        self.assertEqual(parseNumberPattern('#,##0.00;-#,##0.00'),
1✔
712
                         ((None, '', None, '###0', '00', '', None, '', None,
713
                           (3, 0)),
714
                          (None, '-', None, '###0', '00', '', None, '', None,
715
                           (3, 0))))
716

717
        self.assertEqual(
1✔
718
            parseNumberPattern('#,##,##0.###;-#,##,##0.###'),
719
            ((None, '', None, '#####0', '###', '', None, '', None, (3, 2, 0)),
720
             (None, '-', None, '#####0', '###', '', None, '', None,
721
              (3, 2, 0))))
722

723
        self.assertEqual(parseNumberPattern('#,##0.##;-#,##0.##'),
1✔
724
                         ((None, '', None, '###0', '##', '', None, '', None,
725
                           (3, 0)),
726
                          (None, '-', None, '###0', '##', '', None, '', None,
727
                           (3, 0))))
728

729
        self.assertEqual(parseNumberPattern('#,##0.###;-#,##0.###'),
1✔
730
                         ((None, '', None, '###0', '###', '', None, '', None,
731
                           (3, 0)),
732
                          (None, '-', None, '###0', '###', '', None, '', None,
733
                           (3, 0))))
734

735
        self.assertEqual(parseNumberPattern('#,##0.###;(#,##0.###)'),
1✔
736
                         ((None, '', None, '###0', '###', '', None, '', None,
737
                           (3, 0)),
738
                          (None, '(', None, '###0', '###', '', None, ')', None,
739
                           (3, 0))))
740

741
        self.assertEqual(parseNumberPattern('#,##0.###;#,##0.###-'),
1✔
742
                         ((None, '', None, '###0', '###', '', None, '', None,
743
                           (3, 0)),
744
                          (None, '', None, '###0', '###', '', None, '-', None,
745
                           (3, 0))))
746

747
        self.assertEqual(
1✔
748
            parseNumberPattern('##,##,##0.###;-##,##,##0.###'),
749
            ((None, '', None, '######0', '###', '', None, '', None, (3, 2, 0)),
750
             (None, '-', None, '######0', '###', '', None, '', None,
751
              (3, 2, 0))))
752

753
        self.assertEqual(parseNumberPattern('##,##0.##;-##,##0.##'),
1✔
754
                         ((None, '', None, '####0', '##', '', None, '', None,
755
                           (3, 0)),
756
                          (None, '-', None, '####0', '##', '', None, '', None,
757
                           (3, 0))))
758

759
        self.assertEqual(parseNumberPattern('###0.###;-###0.###'),
1✔
760
                         ((None, '', None, '###0', '###', '', None, '', None,
761
                           ()),
762
                          (None, '-', None, '###0', '###', '', None, '', None,
763
                           ())))
764

765
        self.assertEqual(parseNumberPattern('###0.###;###0.###-'),
1✔
766
                         ((None, '', None, '###0', '###', '', None, '', None,
767
                           ()),
768
                          (None, '', None, '###0', '###', '', None, '-', None,
769
                           ())))
770

771
        self.assertEqual(parseNumberPattern('#0.###;-#0.###'),
1✔
772
                         ((None, '', None, '#0', '###', '', None, '', None,
773
                           ()),
774
                          (None, '-', None, '#0', '###', '', None, '', None,
775
                           ())))
776

777
        self.assertEqual(parseNumberPattern('#,##0.###;#,##0.###'),
1✔
778
                         ((None, '', None, '###0', '###', '', None, '', None,
779
                           (3, 0)),
780
                          (None, '', None, '###0', '###', '', None, '', None,
781
                           (3, 0))))
782

783
        self.assertEqual(parseNumberPattern('###0.###;-###0.###'),
1✔
784
                         ((None, '', None, '###0', '###', '', None, '', None,
785
                           ()),
786
                          (None, '-', None, '###0', '###', '', None, '', None,
787
                           ())))
788

789
        self.assertEqual(parseNumberPattern('#,##0.00;-#,##0.00'),
1✔
790
                         ((None, '', None, '###0', '00', '', None, '', None,
791
                           (3, 0)),
792
                          (None, '-', None, '###0', '00', '', None, '', None,
793
                           (3, 0))))
794

795
        self.assertEqual(parseNumberPattern('#,##0.00;(#,##0.00)'),
1✔
796
                         ((None, '', None, '###0', '00', '', None, '', None,
797
                           (3, 0)),
798
                          (None, '(', None, '###0', '00', '', None, ')', None,
799
                           (3, 0))))
800

801
        self.assertEqual(parseNumberPattern('#,##0.00;-#,##0.00'),
1✔
802
                         ((None, '', None, '###0', '00', '', None, '', None,
803
                           (3, 0)),
804
                          (None, '-', None, '###0', '00', '', None, '', None,
805
                           (3, 0))))
806

807
        self.assertEqual(
1✔
808
            parseNumberPattern('##,##,##0.00;-##,##,##0.00'),
809
            ((None, '', None, '######0', '00', '', None, '', None, (3, 2, 0)),
810
             (None, '-', None, '######0', '00', '', None, '', None,
811
              (3, 2, 0))))
812

813
        self.assertEqual(parseNumberPattern('###0.00;-###0.00'),
1✔
814
                         ((None, '', None, '###0', '00', '', None, '', None,
815
                           ()),
816
                          (None, '-', None, '###0', '00', '', None, '', None,
817
                           ())))
818

819
        self.assertEqual(parseNumberPattern('#,##0;-#,##0'),
1✔
820
                         ((None, '', None, '###0', '', '', None, '', None,
821
                           (3, 0)),
822
                          (None, '-', None, '###0', '', '', None, '', None,
823
                           (3, 0))))
824

825
        self.assertEqual(parseNumberPattern('###0.00;-###0.00'),
1✔
826
                         ((None, '', None, '###0', '00', '', None, '', None,
827
                           ()),
828
                          (None, '-', None, '###0', '00', '', None, '', None,
829
                           ())))
830

831
    def testParsePadding1WithoutPrefixPattern(self):
1✔
832
        self.assertEqual(parseNumberPattern('* ###0'),
1✔
833
                         ((' ', '', None, '###0', '', '', None, '', None, ()),
834
                          (' ', '', None, '###0', '', '', None, '', None, ())))
835
        self.assertEqual(parseNumberPattern('* ###0.0##'),
1✔
836
                         ((' ', '', None, '###0', '0##', '', None, '', None,
837
                           ()),
838
                          (' ', '', None, '###0', '0##', '', None, '', None,
839
                           ())))
840
        self.assertEqual(parseNumberPattern('* ###0.0##;*_###0.0##'),
1✔
841
                         ((' ', '', None, '###0', '0##', '', None, '', None,
842
                           ()),
843
                          ('_', '', None, '###0', '0##', '', None, '', None,
844
                           ())))
845

846
    def testParsePadding1WithPrefixPattern(self):
1✔
847
        self.assertEqual(parseNumberPattern('* +###0'),
1✔
848
                         ((' ', '+', None, '###0', '', '', None, '', None, ()),
849
                          (' ', '+', None, '###0', '', '', None, '', None,
850
                           ())))
851
        self.assertEqual(parseNumberPattern('* +###0.0##'),
1✔
852
                         ((' ', '+', None, '###0', '0##', '', None, '', None,
853
                           ()),
854
                          (' ', '+', None, '###0', '0##', '', None, '', None,
855
                           ())))
856
        self.assertEqual(parseNumberPattern('* +###0.0##;*_-###0.0##'),
1✔
857
                         ((' ', '+', None, '###0', '0##', '', None, '', None,
858
                           ()),
859
                          ('_', '-', None, '###0', '0##', '', None, '', None,
860
                           ())))
861

862
    def testParsePadding1Padding2WithPrefixPattern(self):
1✔
863
        self.assertEqual(parseNumberPattern('* +* ###0'),
1✔
864
                         ((' ', '+', ' ', '###0', '', '', None, '', None, ()),
865
                          (' ', '+', ' ', '###0', '', '', None, '', None, ())))
866
        self.assertEqual(parseNumberPattern('* +* ###0.0##'),
1✔
867
                         ((' ', '+', ' ', '###0', '0##', '', None, '', None,
868
                           ()),
869
                          (' ', '+', ' ', '###0', '0##', '', None, '', None,
870
                           ())))
871
        self.assertEqual(parseNumberPattern('* +* ###0.0##;*_-*_###0.0##'),
1✔
872
                         ((' ', '+', ' ', '###0', '0##', '', None, '', None,
873
                           ()),
874
                          ('_', '-', '_', '###0', '0##', '', None, '', None,
875
                           ())))
876

877
    def testParsePadding3WithoutSuffixPattern(self):
1✔
878
        self.assertEqual(parseNumberPattern('###0* '),
1✔
879
                         ((None, '', None, '###0', '', '', ' ', '', None, ()),
880
                          (None, '', None, '###0', '', '', ' ', '', None, ())))
881
        self.assertEqual(parseNumberPattern('###0.0##* '),
1✔
882
                         ((None, '', None, '###0', '0##', '', ' ', '', None,
883
                           ()),
884
                          (None, '', None, '###0', '0##', '', ' ', '', None,
885
                           ())))
886
        self.assertEqual(parseNumberPattern('###0.0##* ;###0.0##*_'),
1✔
887
                         ((None, '', None, '###0', '0##', '', ' ', '', None,
888
                           ()),
889
                          (None, '', None, '###0', '0##', '', '_', '', None,
890
                           ())))
891

892
    def testParsePadding3InScientificPattern(self):
1✔
893
        self.assertEqual(parseNumberPattern('###0E#0* '),
1✔
894
                         ((None, '', None, '###0', '', '#0', ' ', '', None,
895
                           ()),
896
                          (None, '', None, '###0', '', '#0', ' ', '', None,
897
                           ())))
898
        self.assertEqual(parseNumberPattern('###0.0##E0* '),
1✔
899
                         ((None, '', None, '###0', '0##', '0', ' ', '', None,
900
                           ()),
901
                          (None, '', None, '###0', '0##', '0', ' ', '', None,
902
                           ())))
903
        self.assertEqual(parseNumberPattern('###0.0##E#0* ;###0.0##E0*_'),
1✔
904
                         ((None, '', None, '###0', '0##', '#0', ' ', '', None,
905
                           ()),
906
                          (None, '', None, '###0', '0##', '0', '_', '', None,
907
                           ())))
908

909
    def testParsePadding3WithSufffixPattern(self):
1✔
910
        self.assertEqual(parseNumberPattern('###0* /'),
1✔
911
                         ((None, '', None, '###0', '', '', ' ', '/', None, ()),
912
                          (None, '', None, '###0', '', '', ' ', '/', None,
913
                           ())))
914
        self.assertEqual(parseNumberPattern('###0.0#* /'),
1✔
915
                         ((None, '', None, '###0', '0#', '', ' ', '/', None,
916
                           ()),
917
                          (None, '', None, '###0', '0#', '', ' ', '/', None,
918
                           ())))
919
        self.assertEqual(parseNumberPattern('###0.0#* /;###0.0#*_/'),
1✔
920
                         ((None, '', None, '###0', '0#', '', ' ', '/', None,
921
                           ()),
922
                          (None, '', None, '###0', '0#', '', '_', '/', None,
923
                           ())))
924

925
    def testParsePadding3And4WithSuffixPattern(self):
1✔
926
        self.assertEqual(parseNumberPattern('###0* /* '),
1✔
927
                         ((None, '', None, '###0', '', '', ' ', '/', ' ', ()),
928
                          (None, '', None, '###0', '', '', ' ', '/', ' ', ())))
929
        self.assertEqual(parseNumberPattern('###0* /* ;###0*_/*_'),
1✔
930
                         ((None, '', None, '###0', '', '', ' ', '/', ' ', ()),
931
                          (None, '', None, '###0', '', '', '_', '/', '_', ())))
932

933
    def testParseMultipleCharacterPrefix(self):
1✔
934
        self.assertEqual(parseNumberPattern('DM###0'),
1✔
935
                         ((None, 'DM', None, '###0', '', '', None, '', None,
936
                           ()),
937
                          (None, 'DM', None, '###0', '', '', None, '', None,
938
                           ())))
939
        self.assertEqual(parseNumberPattern('DM* ###0'),
1✔
940
                         ((None, 'DM', ' ', '###0', '', '', None, '', None,
941
                           ()),
942
                          (None, 'DM', ' ', '###0', '', '', None, '', None,
943
                           ())))
944

945
    def testParseStringEscapedPrefix(self):
1✔
946
        self.assertEqual(parseNumberPattern("'DEM'###0"),
1✔
947
                         ((None, 'DEM', None, '###0', '', '', None, '', None,
948
                           ()),
949
                          (None, 'DEM', None, '###0', '', '', None, '', None,
950
                           ())))
951
        self.assertEqual(parseNumberPattern("D'EM'###0"),
1✔
952
                         ((None, 'DEM', None, '###0', '', '', None, '', None,
953
                           ()),
954
                          (None, 'DEM', None, '###0', '', '', None, '', None,
955
                           ())))
956
        self.assertEqual(parseNumberPattern("D'E'M###0"),
1✔
957
                         ((None, 'DEM', None, '###0', '', '', None, '', None,
958
                           ()),
959
                          (None, 'DEM', None, '###0', '', '', None, '', None,
960
                           ())))
961

962
    def testParseStringEscapedSuffix(self):
1✔
963
        self.assertEqual(parseNumberPattern("###0'DEM'"),
1✔
964
                         ((None, '', None, '###0', '', '', None, 'DEM', None,
965
                           ()),
966
                          (None, '', None, '###0', '', '', None, 'DEM', None,
967
                           ())))
968
        self.assertEqual(parseNumberPattern("###0D'EM'"),
1✔
969
                         ((None, '', None, '###0', '', '', None, 'DEM', None,
970
                           ()),
971
                          (None, '', None, '###0', '', '', None, 'DEM', None,
972
                           ())))
973
        self.assertEqual(parseNumberPattern("###0D'E'M"),
1✔
974
                         ((None, '', None, '###0', '', '', None, 'DEM', None,
975
                           ()),
976
                          (None, '', None, '###0', '', '', None, 'DEM', None,
977
                           ())))
978

979
    def testParseInvalidBegin(self):
1✔
980
        with self.assertRaisesRegex(NumberPatternParseError,
1✔
981
                                    "Wrong syntax at beginning"):
982
            parseNumberPattern(".")
1✔
983

984
    def testParseFractionQuote(self):
1✔
985
        pattern, neg_pattern = parseNumberPattern("0.'")
1✔
986
        self.assertEqual((None, '', None, '0', '', '', None, '', None, ()),
1✔
987
                         pattern)
988
        self.assertEqual((None, '', None, '0', '', '', None, '', None, ()),
1✔
989
                         neg_pattern)
990

991
    def testParseExponentialQuote(self):
1✔
992
        pattern, neg_pattern = parseNumberPattern("0E'")
1✔
993
        self.assertEqual((None, '', None, '0', '', '', None, '', None, ()),
1✔
994
                         pattern)
995
        self.assertEqual((None, '', None, '0', '', '', None, '', None, ()),
1✔
996
                         neg_pattern)
997

998
    def testParseExponentialNumber(self):
1✔
999
        pattern, neg_pattern = parseNumberPattern("0E1")
1✔
1000
        self.assertEqual((None, '', None, '0', '', '', None, '1', None, ()),
1✔
1001
                         pattern)
1002
        self.assertEqual((None, '', None, '0', '', '', None, '1', None, ()),
1✔
1003
                         neg_pattern)
1004

1005

1006
class TestNumberFormat(TestCase):
1✔
1007
    """Test the functionality of an implmentation of the NumberFormat."""
1008

1009
    format = NumberFormat(
1✔
1010
        symbols={
1011
            'decimal': '.',
1012
            'group': ',',
1013
            'list': ';',
1014
            'percentSign': '%',
1015
            'nativeZeroDigit': '0',
1016
            'patternDigit': '#',
1017
            'plusSign': '+',
1018
            'minusSign': '-',
1019
            'exponential': 'E',
1020
            'perMille': 'o/oo',
1021
            'infinity': 'oo',
1022
            'nan': 'N/A'
1023
        })
1024

1025
    def testInterfaceConformity(self):
1✔
1026
        self.assertTrue(INumberFormat.providedBy(self.format))
1✔
1027

1028
    def testParseSimpleInteger(self):
1✔
1029
        self.assertEqual(self.format.parse('23341', '###0'), 23341)
1✔
1030
        self.assertEqual(self.format.parse('041', '#000'), 41)
1✔
1031

1032
    def testParseScientificInteger(self):
1✔
1033
        self.assertEqual(self.format.parse('2.3341E4', '0.0###E0'), 23341)
1✔
1034
        self.assertEqual(self.format.parse('4.100E01', '0.000##E00'), 41)
1✔
1035
        self.assertEqual(self.format.parse('1E0', '0E0'), 1)
1✔
1036
        self.assertEqual(self.format.parse('0E0', '0E0'), 0)
1✔
1037
        # This is a special case I found not working, but is used frequently
1038
        # in the new LDML Locale files.
1039
        self.assertEqual(self.format.parse('2.3341E+04', '0.000###E+00'),
1✔
1040
                         23341)
1041

1042
    def testParsePosNegAlternativeInteger(self):
1✔
1043
        self.assertEqual(self.format.parse('23341', '#000;#00'), 23341)
1✔
1044
        self.assertEqual(self.format.parse('041', '#000;#00'), 41)
1✔
1045
        self.assertEqual(self.format.parse('41', '#000;#00'), -41)
1✔
1046
        self.assertEqual(self.format.parse('01', '#000;#00'), -1)
1✔
1047

1048
    def testParsePrefixedInteger(self):
1✔
1049
        self.assertEqual(self.format.parse('+23341', '+###0'), 23341)
1✔
1050
        self.assertEqual(self.format.parse('+041', '+#000'), 41)
1✔
1051

1052
    def testParsePosNegInteger(self):
1✔
1053
        self.assertEqual(self.format.parse('+23341', '+###0;-###0'), 23341)
1✔
1054
        self.assertEqual(self.format.parse('+041', '+#000;-#000'), 41)
1✔
1055
        self.assertEqual(self.format.parse('-23341', '+###0;-###0'), -23341)
1✔
1056
        self.assertEqual(self.format.parse('-041', '+#000;-#000'), -41)
1✔
1057

1058
    def testParseThousandSeparatorInteger(self):
1✔
1059
        self.assertEqual(self.format.parse('+23,341', '+#,##0;-#,##0'), 23341)
1✔
1060
        self.assertEqual(self.format.parse('-23,341', '+#,##0;-#,##0'), -23341)
1✔
1061
        self.assertEqual(self.format.parse('+0,041', '+#0,000;-#0,000'), 41)
1✔
1062
        self.assertEqual(self.format.parse('-0,041', '+#0,000;-#0,000'), -41)
1✔
1063

1064
    def testParseDecimal(self):
1✔
1065
        self.assertEqual(self.format.parse('43341.02', '###0.0#'), 43341.02)
1✔
1066
        self.assertEqual(self.format.parse('43341.1', '###0.0#'), 43341.1)
1✔
1067
        self.assertEqual(self.format.parse('43341.020', '###0.000#'), 43341.02)
1✔
1068

1069
    def testParseDecimalWithOptionalDecimalDigits(self):
1✔
1070
        self.assertEqual(self.format.parse('43341.02', '###0.##'), 43341.02)
1✔
1071
        self.assertEqual(self.format.parse('43341', '###0.#'), 43341.0)
1✔
1072
        self.assertEqual(self.format.parse('43341.', '###0.#'), 43341.0)
1✔
1073

1074
    def testParseScientificDecimal(self):
1✔
1075
        self.assertEqual(self.format.parse('4.334102E04', '0.00####E00'),
1✔
1076
                         43341.02)
1077
        self.assertEqual(self.format.parse('4.3341020E004', '0.0000000E000'),
1✔
1078
                         43341.02)
1079
        self.assertEqual(self.format.parse('0.0E0', '0.0#E0'), 0.0)
1✔
1080

1081
    def testParseScientificDecimalSmallerOne(self):
1✔
1082
        self.assertEqual(self.format.parse('4.357E-02', '0.00####E00'),
1✔
1083
                         0.04357)
1084
        self.assertEqual(self.format.parse('4.0000E-02', '0.0000E00'), 0.04)
1✔
1085

1086
    def testParsePadding1WithoutPrefix(self):
1✔
1087
        self.assertEqual(self.format.parse(' 41', '* ##0;*_##0'), 41)
1✔
1088
        self.assertEqual(self.format.parse('_41', '* ##0;*_##0'), -41)
1✔
1089

1090
    def testParsePadding1WithPrefix(self):
1✔
1091
        self.assertEqual(self.format.parse(' +41', '* +##0;*_-##0'), 41)
1✔
1092
        self.assertEqual(self.format.parse('_-41', '* +##0;*_-##0'), -41)
1✔
1093

1094
    def testParsePadding1Padding2WithPrefix(self):
1✔
1095
        self.assertEqual(self.format.parse('  + 41', '* +* ###0;*_-*_###0'),
1✔
1096
                         +41)
1097
        self.assertEqual(self.format.parse('__-_41', '* +* ###0;*_-*_###0'),
1✔
1098
                         -41)
1099

1100
    def testParsePadding1Scientific(self):
1✔
1101
        self.assertEqual(
1✔
1102
            self.format.parse('  4.102E1', '* 0.0####E0;*_0.0####E0'), 41.02)
1103
        self.assertEqual(
1✔
1104
            self.format.parse('__4.102E1', '* 0.0####E0;*_0.0####E0'), -41.02)
1105
        self.assertEqual(
1✔
1106
            self.format.parse(' +4.102E1', '* +0.0###E0;*_-0.0###E0'), 41.02)
1107
        self.assertEqual(
1✔
1108
            self.format.parse('_-4.102E1', '* +0.0###E0;*_-0.0###E0'), -41.02)
1109

1110
    def testParsePadding3WithoutSufffix(self):
1✔
1111
        self.assertEqual(self.format.parse('41.02  ', '#0.0###* ;#0.0###*_'),
1✔
1112
                         41.02)
1113
        self.assertEqual(self.format.parse('41.02__', '#0.0###* ;#0.0###*_'),
1✔
1114
                         -41.02)
1115

1116
    def testParsePadding3WithSufffix(self):
1✔
1117
        self.assertEqual(
1✔
1118
            self.format.parse('[41.02  ]', '[#0.0###* ];(#0.0###*_)'), 41.02)
1119
        self.assertEqual(
1✔
1120
            self.format.parse('(41.02__)', '[#0.0###* ];(#0.0###*_)'), -41.02)
1121

1122
    def testParsePadding3Scientific(self):
1✔
1123
        self.assertEqual(
1✔
1124
            self.format.parse('4.102E1  ', '0.0##E0##* ;0.0##E0##*_'), 41.02)
1125
        self.assertEqual(
1✔
1126
            self.format.parse('4.102E1__', '0.0##E0##* ;0.0##E0##*_'), -41.02)
1127
        self.assertEqual(
1✔
1128
            self.format.parse('(4.102E1  )', '(0.0##E0##* );0.0E0'), 41.02)
1129
        self.assertEqual(
1✔
1130
            self.format.parse('[4.102E1__]', '0.0E0;[0.0##E0##*_]'), -41.02)
1131

1132
    def testParsePadding3Padding4WithSuffix(self):
1✔
1133
        self.assertEqual(self.format.parse('(41.02 )  ', '(#0.0###* )* '),
1✔
1134
                         41.02)
1135
        self.assertEqual(self.format.parse('(4.102E1 )  ', '(0.0##E0##* )* '),
1✔
1136
                         41.02)
1137

1138
    def testParseDecimalWithGermanDecimalSeparator(self):
1✔
1139
        format = NumberFormat(symbols={'decimal': ',', 'group': '.'})
1✔
1140
        self.assertEqual(format.parse('1.234,567', '#,##0.000'), 1234.567)
1✔
1141

1142
    def testParseWithAlternativeExponentialSymbol(self):
1✔
1143
        format = NumberFormat(symbols={
1✔
1144
            'decimal': '.',
1145
            'group': ',',
1146
            'exponential': 'X'
1147
        })
1148
        self.assertEqual(format.parse('1.2X11', '#.#E0'), 1.2e11)
1✔
1149

1150
    def testParseFailWithInvalidCharacters(self):
1✔
1151
        with self.assertRaises(NumberParseError):
1✔
1152
            self.format.parse('123xx', '###0.0#')
1✔
1153
        with self.assertRaises(NumberParseError):
1✔
1154
            self.format.parse('xx123', '###0.0#')
1✔
1155
        with self.assertRaises(NumberParseError):
1✔
1156
            self.format.parse('1xx23', '###0.0#')
1✔
1157

1158
    def testParseFailWithInvalidGroupCharacterPosition(self):
1✔
1159
        with self.assertRaises(NumberParseError):
1✔
1160
            self.format.parse('123,00', '###0.0#')
1✔
1161
        with self.assertRaises(NumberParseError):
1✔
1162
            self.format.parse(',123', '###0.0#')
1✔
1163
        with self.assertRaises(NumberParseError):
1✔
1164
            self.format.parse('1,23.00', '###0.0#')
1✔
1165

1166
    def testChangeOutputType(self):
1✔
1167
        format = NumberFormat()
1✔
1168
        format.type = decimal.Decimal
1✔
1169
        self.assertEqual(format.parse('23341', '###0'),
1✔
1170
                         decimal.Decimal('23341'))
1171
        self.assertEqual(format.parse('233.41', '###0.00'),
1✔
1172
                         decimal.Decimal('233.41'))
1173

1174
    def testFormatSimpleInteger(self):
1✔
1175
        self.assertEqual(self.format.format(23341, '###0'), '23341')
1✔
1176
        self.assertEqual(self.format.format(41, '#000'), '041')
1✔
1177

1178
    def testFormatScientificInteger(self):
1✔
1179
        self.assertEqual(self.format.format(23341, '0.000#E0'), '2.3341E4')
1✔
1180
        self.assertEqual(self.format.format(23341, '0.000#E00'), '2.3341E04')
1✔
1181
        self.assertEqual(self.format.format(1, '0.##E0'), '1E0')
1✔
1182
        self.assertEqual(self.format.format(1, '0.00E00'), '1.00E00')
1✔
1183
        # This is a special case I found not working, but is used frequently
1184
        # in the new LDML Locale files.
1185
        self.assertEqual(self.format.format(23341, '0.000###E+00'),
1✔
1186
                         '2.3341E+04')
1187

1188
    def testFormatScientificZero(self):
1✔
1189
        self.assertEqual(self.format.format(0, '0.00E00'), '0.00E00')
1✔
1190
        self.assertEqual(self.format.format(0, '0E0'), '0E0')
1✔
1191

1192
    def testFormatPosNegAlternativeInteger(self):
1✔
1193
        self.assertEqual(self.format.format(23341, '#000;#00'), '23341')
1✔
1194
        self.assertEqual(self.format.format(41, '#000;#00'), '041')
1✔
1195
        self.assertEqual(self.format.format(-23341, '#000;#00'), '23341')
1✔
1196
        self.assertEqual(self.format.format(-41, '#000;#00'), '41')
1✔
1197
        self.assertEqual(self.format.format(-1, '#000;#00'), '01')
1✔
1198

1199
    def testFormatPrefixedInteger(self):
1✔
1200
        self.assertEqual(self.format.format(23341, '+###0'), '+23341')
1✔
1201
        self.assertEqual(self.format.format(41, '+#000'), '+041')
1✔
1202
        self.assertEqual(self.format.format(-23341, '+###0'), '+23341')
1✔
1203
        self.assertEqual(self.format.format(-41, '+#000'), '+041')
1✔
1204

1205
    def testFormatPosNegInteger(self):
1✔
1206
        self.assertEqual(self.format.format(23341, '+###0;-###0'), '+23341')
1✔
1207
        self.assertEqual(self.format.format(41, '+#000;-#000'), '+041')
1✔
1208
        self.assertEqual(self.format.format(-23341, '+###0;-###0'), '-23341')
1✔
1209
        self.assertEqual(self.format.format(-41, '+#000;-#000'), '-041')
1✔
1210

1211
    def testFormatPosNegScientificInteger(self):
1✔
1212
        self.assertEqual(self.format.format(23341, '+0.00###E00;-0.00###E00'),
1✔
1213
                         '+2.3341E04')
1214
        self.assertEqual(self.format.format(23341, '-0.00###E00;-0.00###E00'),
1✔
1215
                         '-2.3341E04')
1216

1217
    def testFormatThousandSeparatorInteger(self):
1✔
1218
        self.assertEqual(self.format.format(23341, '+#,##0;-#,##0'), '+23,341')
1✔
1219
        self.assertEqual(self.format.format(-23341, '+#,##0;-#,##0'),
1✔
1220
                         '-23,341')
1221
        self.assertEqual(self.format.format(41, '+#0,000;-#0,000'), '+0,041')
1✔
1222
        self.assertEqual(self.format.format(-41, '+#0,000;-#0,000'), '-0,041')
1✔
1223
        self.assertEqual(self.format.format(987654321, '+#,##0;-#,##0'),
1✔
1224
                         '+987,654,321')
1225
        self.assertEqual(self.format.format(-987654321, '+#,##0;-#,##0'),
1✔
1226
                         '-987,654,321')
1227
        self.assertEqual(
1✔
1228
            self.format.format(987654321, '+#,##,#0,000;-#,##,#0,000'),
1229
            '+98,76,54,321')
1230
        self.assertEqual(
1✔
1231
            self.format.format(-987654321, '+#,##,#0,000;-#,##,#0,000'),
1232
            '-98,76,54,321')
1233

1234
    def testFormatBadThousandSeparator(self):
1✔
1235
        self.assertRaises(ValueError, self.format.format, 23341, '0,')
1✔
1236

1237
    def testFormatDecimal(self):
1✔
1238
        self.assertEqual(self.format.format(23341.02357, '###0.0#'),
1✔
1239
                         '23341.02')
1240
        self.assertEqual(self.format.format(23341.02357, '###0.000#'),
1✔
1241
                         '23341.0236')
1242
        self.assertEqual(self.format.format(23341.02, '###0.000#'),
1✔
1243
                         '23341.020')
1244

1245
    def testRounding(self):
1✔
1246
        self.assertEqual(self.format.format(0.5, '#'), '1')
1✔
1247
        self.assertEqual(self.format.format(0.49, '#'), '0')
1✔
1248
        self.assertEqual(self.format.format(0.45, '0.0'), '0.5')
1✔
1249
        self.assertEqual(self.format.format(150, '0E0'), '2E2')
1✔
1250
        self.assertEqual(self.format.format(149, '0E0'), '1E2')
1✔
1251
        self.assertEqual(self.format.format(1.9999, '0.000'), '2.000')
1✔
1252
        self.assertEqual(self.format.format(1.9999, '0.0000'), '1.9999')
1✔
1253

1254
    def testFormatScientificDecimal(self):
1✔
1255
        self.assertEqual(self.format.format(23341.02357, '0.00####E00'),
1✔
1256
                         '2.334102E04')
1257
        self.assertEqual(self.format.format(23341.02, '0.0000000E000'),
1✔
1258
                         '2.3341020E004')
1259

1260
    def testFormatScientificDecimalSmallerOne(self):
1✔
1261
        self.assertEqual(self.format.format(0.02357, '0.00####E00'),
1✔
1262
                         '2.357E-02')
1263
        self.assertEqual(self.format.format(0.02, '0.0000E00'), '2.0000E-02')
1✔
1264

1265
    def testFormatPadding1WithoutPrefix(self):
1✔
1266
        self.assertEqual(self.format.format(41, '* ##0;*_##0'), ' 41')
1✔
1267
        self.assertEqual(self.format.format(-41, '* ##0;*_##0'), '_41')
1✔
1268

1269
    def testFormatPadding1WithPrefix(self):
1✔
1270
        self.assertEqual(self.format.format(41, '* +##0;*_-##0'), ' +41')
1✔
1271
        self.assertEqual(self.format.format(-41, '* +##0;*_-##0'), '_-41')
1✔
1272

1273
    def testFormatPadding1Scientific(self):
1✔
1274
        self.assertEqual(self.format.format(41.02, '* 0.0####E0;*_0.0####E0'),
1✔
1275
                         '  4.102E1')
1276
        self.assertEqual(self.format.format(-41.02, '* 0.0####E0;*_0.0####E0'),
1✔
1277
                         '__4.102E1')
1278
        self.assertEqual(self.format.format(41.02, '* +0.0###E0;*_-0.0###E0'),
1✔
1279
                         ' +4.102E1')
1280
        self.assertEqual(self.format.format(-41.02, '* +0.0###E0;*_-0.0###E0'),
1✔
1281
                         '_-4.102E1')
1282

1283
    def testFormatPadding1Padding2WithPrefix(self):
1✔
1284
        self.assertEqual(self.format.format(41, '* +* ###0;*_-*_###0'),
1✔
1285
                         '  + 41')
1286
        self.assertEqual(self.format.format(-41, '* +* ###0;*_-*_###0'),
1✔
1287
                         '__-_41')
1288

1289
    def testFormatPadding3WithoutSufffix(self):
1✔
1290
        self.assertEqual(self.format.format(41.02, '#0.0###* ;#0.0###*_'),
1✔
1291
                         '41.02  ')
1292
        self.assertEqual(self.format.format(-41.02, '#0.0###* ;#0.0###*_'),
1✔
1293
                         '41.02__')
1294

1295
    def testFormatPadding3WithSufffix(self):
1✔
1296
        self.assertEqual(self.format.format(41.02, '[#0.0###* ];(#0.0###*_)'),
1✔
1297
                         '[41.02  ]')
1298
        self.assertEqual(self.format.format(-41.02, '[#0.0###* ];(#0.0###*_)'),
1✔
1299
                         '(41.02__)')
1300

1301
    def testFormatPadding3Scientific(self):
1✔
1302
        self.assertEqual(self.format.format(41.02, '0.0##E0##* ;0.0##E0##*_'),
1✔
1303
                         '4.102E1  ')
1304
        self.assertEqual(self.format.format(-41.02, '0.0##E0##* ;0.0##E0##*_'),
1✔
1305
                         '4.102E1__')
1306
        self.assertEqual(self.format.format(41.02, '(0.0##E0##* );0.0E0'),
1✔
1307
                         '(4.102E1  )')
1308
        self.assertEqual(self.format.format(-41.02, '0.0E0;[0.0##E0##*_]'),
1✔
1309
                         '[4.102E1__]')
1310

1311
    def testFormatPadding3Padding4WithSuffix(self):
1✔
1312
        self.assertEqual(self.format.format(41.02, '(#0.0###* )* '),
1✔
1313
                         '(41.02 )  ')
1314
        self.assertEqual(self.format.format(41.02, '(0.0##E0##* )* '),
1✔
1315
                         '(4.102E1 )  ')
1316

1317
    def testFormatSmallNumbers(self):
1✔
1318
        self.assertEqual(
1✔
1319
            self.format.format(-1e-7, '(#0.00#####);(-#0.00#####)'),
1320
            '(-0.0000001)')
1321
        self.assertEqual(self.format.format(1e-9, '(#0.00###)'), '(0.00)')
1✔
1322
        self.assertEqual(self.format.format(1e-9, '(#0.00###)'), '(0.00)')
1✔
1323

1324
    def testFormatHighPrecisionNumbers(self):
1✔
1325
        self.assertEqual(
1✔
1326
            self.format.format(1 + 1e-7, '(#0.00#####);(-#0.00#####)'),
1327
            '(1.0000001)')
1328
        self.assertEqual(self.format.format(1 + 1e-7, '(#0.00###)'),
1✔
1329
                         '(1.00000)')
1330
        self.assertEqual(
1✔
1331
            self.format.format(1 + 1e-9, '(#0.00#######);(-#0.00#######)'),
1332
            '(1.000000001)')
1333
        self.assertEqual(self.format.format(1 + 1e-9, '(#0.00###)'),
1✔
1334
                         '(1.00000)')
1335
        self.assertEqual(
1✔
1336
            self.format.format(1 + 1e-12,
1337
                               '(#0.00##########);(-#0.00##########)'),
1338
            '(1.000000000001)')
1339
        self.assertEqual(self.format.format(1 + 1e-12, '(#0.00###)'),
1✔
1340
                         '(1.00000)')
1341

1342
    def testNoRounding(self):
1✔
1343
        # Witout Rounding
1344
        self.assertEqual(
1✔
1345
            self.format.format(decimal.Decimal('0.99999'),
1346
                               '0.###',
1347
                               rounding=False), '0.99999')
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc