blob: ec5db9fa423ae08cccd72df1a66d07300fc9b620 [file] [log] [blame]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001# Copyright (c) 2004 Python Software Foundation.
2# All rights reserved.
3
4# Written by Eric Price <eprice at tjhsst.edu>
5# and Facundo Batista <facundo at taniquetil.com.ar>
6# and Raymond Hettinger <python at rcn.com>
7# and Aahz (aahz at pobox.com)
8# and Tim Peters
9
10"""
11These are the test cases for the Decimal module.
12
13There are two groups of tests, Arithmetic and Behaviour. The former test
14the Decimal arithmetic using the tests provided by Mike Cowlishaw. The latter
15test the pythonic behaviour according to PEP 327.
16
17Cowlishaw's tests can be downloaded from:
18
Stefan Krah1919b7e2012-03-21 18:25:23 +010019 http://speleotrove.com/decimal/dectest.zip
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000020
21This test module can be called from command line with one parameter (Arithmetic
22or Behaviour) to test each part, or without parameter to test both parts. If
23you're working through IDLE, you can import this test module and call test_main()
24with the corresponding argument.
25"""
26
Christian Heimes400adb02008-02-01 08:12:03 +000027import math
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000028import os, sys
Mark Dickinsonac256ab2010-04-03 11:08:14 +000029import operator
Mark Dickinsonb1d8e322010-05-22 18:35:36 +000030import warnings
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000031import pickle, copy
Christian Heimes400adb02008-02-01 08:12:03 +000032import unittest
Raymond Hettinger82417ca2009-02-03 03:54:28 +000033import numbers
Stefan Krah1919b7e2012-03-21 18:25:23 +010034import locale
Eric Smith3ab08ca2010-12-04 15:17:38 +000035from test.support import (run_unittest, run_doctest, is_resource_enabled,
36 requires_IEEE_754)
Stefan Krah6fb204a2012-09-28 16:18:54 +020037from test.support import (check_warnings, import_fresh_module, TestFailed,
38 run_with_locale)
Raymond Hettinger0aeac102004-07-05 22:53:03 +000039import random
Stefan Krah1919b7e2012-03-21 18:25:23 +010040import time
41import warnings
Raymond Hettinger7e71fa52004-12-18 19:07:19 +000042try:
43 import threading
44except ImportError:
45 threading = None
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000046
Raymond Hettingerfed52962004-07-14 15:41:57 +000047
Stefan Krah1919b7e2012-03-21 18:25:23 +010048C = import_fresh_module('decimal', fresh=['_decimal'])
49P = import_fresh_module('decimal', blocked=['_decimal'])
50orig_sys_decimal = sys.modules['decimal']
51
52# fractions module must import the correct decimal module.
53cfractions = import_fresh_module('fractions', fresh=['fractions'])
54sys.modules['decimal'] = P
55pfractions = import_fresh_module('fractions', fresh=['fractions'])
56sys.modules['decimal'] = C
57fractions = {C:cfractions, P:pfractions}
58sys.modules['decimal'] = orig_sys_decimal
59
60
61# Useful Test Constant
62Signals = {
63 C: tuple(C.getcontext().flags.keys()) if C else None,
64 P: tuple(P.getcontext().flags.keys())
65}
Mark Dickinsonc69160e2010-05-04 14:35:33 +000066# Signals ordered with respect to precedence: when an operation
67# produces multiple signals, signals occurring later in the list
68# should be handled before those occurring earlier in the list.
Stefan Krah1919b7e2012-03-21 18:25:23 +010069OrderedSignals = {
70 C: [C.Clamped, C.Rounded, C.Inexact, C.Subnormal, C.Underflow,
71 C.Overflow, C.DivisionByZero, C.InvalidOperation,
72 C.FloatOperation] if C else None,
73 P: [P.Clamped, P.Rounded, P.Inexact, P.Subnormal, P.Underflow,
74 P.Overflow, P.DivisionByZero, P.InvalidOperation,
75 P.FloatOperation]
76}
77def assert_signals(cls, context, attr, expected):
78 d = getattr(context, attr)
79 cls.assertTrue(all(d[s] if s in expected else not d[s] for s in d))
80
81RoundingModes = {
82 C: (C.ROUND_UP, C.ROUND_DOWN, C.ROUND_CEILING, C.ROUND_FLOOR,
83 C.ROUND_HALF_UP, C.ROUND_HALF_DOWN, C.ROUND_HALF_EVEN,
84 C.ROUND_05UP) if C else None,
85 P: (P.ROUND_UP, P.ROUND_DOWN, P.ROUND_CEILING, P.ROUND_FLOOR,
86 P.ROUND_HALF_UP, P.ROUND_HALF_DOWN, P.ROUND_HALF_EVEN,
87 P.ROUND_05UP)
88}
Mark Dickinsonc69160e2010-05-04 14:35:33 +000089
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000090# Tests are built around these assumed context defaults.
91# test_main() restores the original context.
Stefan Krah1919b7e2012-03-21 18:25:23 +010092ORIGINAL_CONTEXT = {
93 C: C.getcontext().copy() if C else None,
94 P: P.getcontext().copy()
95}
96def init(m):
97 if not m: return
98 DefaultTestContext = m.Context(
99 prec=9, rounding=m.ROUND_HALF_EVEN, traps=dict.fromkeys(Signals[m], 0)
100 )
101 m.setcontext(DefaultTestContext)
Raymond Hettinger6ea48452004-07-03 12:26:21 +0000102
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000103TESTDATADIR = 'decimaltestdata'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000104if __name__ == '__main__':
105 file = sys.argv[0]
106else:
107 file = __file__
108testdir = os.path.dirname(file) or os.curdir
Raymond Hettinger267b8682005-03-27 10:47:39 +0000109directory = testdir + os.sep + TESTDATADIR + os.sep
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000110
Raymond Hettinger267b8682005-03-27 10:47:39 +0000111skip_expected = not os.path.isdir(directory)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000112
113# Make sure it actually raises errors when not expected and caught in flags
114# Slower, since it runs some things several times.
115EXTENDEDERRORTEST = False
116
Stefan Krah1919b7e2012-03-21 18:25:23 +0100117# Test extra functionality in the C version (-DEXTRA_FUNCTIONALITY).
118EXTRA_FUNCTIONALITY = True if hasattr(C, 'DecClamped') else False
119requires_extra_functionality = unittest.skipUnless(
120 EXTRA_FUNCTIONALITY, "test requires build with -DEXTRA_FUNCTIONALITY")
121skip_if_extra_functionality = unittest.skipIf(
122 EXTRA_FUNCTIONALITY, "test requires regular build")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000123
124
Stefan Krah1919b7e2012-03-21 18:25:23 +0100125class IBMTestCases(unittest.TestCase):
126 """Class which tests the Decimal class against the IBM test cases."""
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000127
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000128 def setUp(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100129 self.context = self.decimal.Context()
130 self.readcontext = self.decimal.Context()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000131 self.ignore_list = ['#']
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000132
Stefan Krah1919b7e2012-03-21 18:25:23 +0100133 # List of individual .decTest test ids that correspond to tests that
134 # we're skipping for one reason or another.
135 self.skipped_test_ids = set([
136 # Skip implementation-specific scaleb tests.
137 'scbx164',
138 'scbx165',
139
140 # For some operations (currently exp, ln, log10, power), the decNumber
141 # reference implementation imposes additional restrictions on the context
142 # and operands. These restrictions are not part of the specification;
143 # however, the effect of these restrictions does show up in some of the
144 # testcases. We skip testcases that violate these restrictions, since
145 # Decimal behaves differently from decNumber for these testcases so these
146 # testcases would otherwise fail.
147 'expx901',
148 'expx902',
149 'expx903',
150 'expx905',
151 'lnx901',
152 'lnx902',
153 'lnx903',
154 'lnx905',
155 'logx901',
156 'logx902',
157 'logx903',
158 'logx905',
159 'powx1183',
160 'powx1184',
161 'powx4001',
162 'powx4002',
163 'powx4003',
164 'powx4005',
165 'powx4008',
166 'powx4010',
167 'powx4012',
168 'powx4014',
169 ])
170
171 if self.decimal == C:
172 # status has additional Subnormal, Underflow
173 self.skipped_test_ids.add('pwsx803')
174 self.skipped_test_ids.add('pwsx805')
175 # Correct rounding (skipped for decNumber, too)
176 self.skipped_test_ids.add('powx4302')
177 self.skipped_test_ids.add('powx4303')
178 self.skipped_test_ids.add('powx4342')
179 self.skipped_test_ids.add('powx4343')
180 # http://bugs.python.org/issue7049
181 self.skipped_test_ids.add('pwmx325')
182 self.skipped_test_ids.add('pwmx326')
183
184 # Map test directives to setter functions.
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000185 self.ChangeDict = {'precision' : self.change_precision,
Stefan Krah1919b7e2012-03-21 18:25:23 +0100186 'rounding' : self.change_rounding_method,
187 'maxexponent' : self.change_max_exponent,
188 'minexponent' : self.change_min_exponent,
189 'clamp' : self.change_clamp}
190
191 # Name adapter to be able to change the Decimal and Context
192 # interface without changing the test files from Cowlishaw.
193 self.NameAdapter = {'and':'logical_and',
194 'apply':'_apply',
195 'class':'number_class',
196 'comparesig':'compare_signal',
197 'comparetotal':'compare_total',
198 'comparetotmag':'compare_total_mag',
199 'copy':'copy_decimal',
200 'copyabs':'copy_abs',
201 'copynegate':'copy_negate',
202 'copysign':'copy_sign',
203 'divideint':'divide_int',
204 'invert':'logical_invert',
205 'iscanonical':'is_canonical',
206 'isfinite':'is_finite',
207 'isinfinite':'is_infinite',
208 'isnan':'is_nan',
209 'isnormal':'is_normal',
210 'isqnan':'is_qnan',
211 'issigned':'is_signed',
212 'issnan':'is_snan',
213 'issubnormal':'is_subnormal',
214 'iszero':'is_zero',
215 'maxmag':'max_mag',
216 'minmag':'min_mag',
217 'nextminus':'next_minus',
218 'nextplus':'next_plus',
219 'nexttoward':'next_toward',
220 'or':'logical_or',
221 'reduce':'normalize',
222 'remaindernear':'remainder_near',
223 'samequantum':'same_quantum',
224 'squareroot':'sqrt',
225 'toeng':'to_eng_string',
226 'tointegral':'to_integral_value',
227 'tointegralx':'to_integral_exact',
228 'tosci':'to_sci_string',
229 'xor':'logical_xor'}
230
231 # Map test-case names to roundings.
232 self.RoundingDict = {'ceiling' : self.decimal.ROUND_CEILING,
233 'down' : self.decimal.ROUND_DOWN,
234 'floor' : self.decimal.ROUND_FLOOR,
235 'half_down' : self.decimal.ROUND_HALF_DOWN,
236 'half_even' : self.decimal.ROUND_HALF_EVEN,
237 'half_up' : self.decimal.ROUND_HALF_UP,
238 'up' : self.decimal.ROUND_UP,
239 '05up' : self.decimal.ROUND_05UP}
240
241 # Map the test cases' error names to the actual errors.
242 self.ErrorNames = {'clamped' : self.decimal.Clamped,
243 'conversion_syntax' : self.decimal.InvalidOperation,
244 'division_by_zero' : self.decimal.DivisionByZero,
245 'division_impossible' : self.decimal.InvalidOperation,
246 'division_undefined' : self.decimal.InvalidOperation,
247 'inexact' : self.decimal.Inexact,
248 'invalid_context' : self.decimal.InvalidOperation,
249 'invalid_operation' : self.decimal.InvalidOperation,
250 'overflow' : self.decimal.Overflow,
251 'rounded' : self.decimal.Rounded,
252 'subnormal' : self.decimal.Subnormal,
253 'underflow' : self.decimal.Underflow}
254
255 # The following functions return True/False rather than a
256 # Decimal instance.
257 self.LogicalFunctions = ('is_canonical',
258 'is_finite',
259 'is_infinite',
260 'is_nan',
261 'is_normal',
262 'is_qnan',
263 'is_signed',
264 'is_snan',
265 'is_subnormal',
266 'is_zero',
267 'same_quantum')
268
269 def read_unlimited(self, v, context):
270 """Work around the limitations of the 32-bit _decimal version. The
271 guaranteed maximum values for prec, Emax etc. are 425000000,
272 but higher values usually work, except for rare corner cases.
273 In particular, all of the IBM tests pass with maximum values
274 of 1070000000."""
275 if self.decimal == C and self.decimal.MAX_EMAX == 425000000:
276 self.readcontext._unsafe_setprec(1070000000)
277 self.readcontext._unsafe_setemax(1070000000)
278 self.readcontext._unsafe_setemin(-1070000000)
279 return self.readcontext.create_decimal(v)
280 else:
281 return self.decimal.Decimal(v, context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000282
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000283 def eval_file(self, file):
284 global skip_expected
285 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +0000286 raise unittest.SkipTest
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000287 return
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000288 with open(file) as f:
289 for line in f:
290 line = line.replace('\r\n', '').replace('\n', '')
291 #print line
292 try:
293 t = self.eval_line(line)
Stefan Krah1919b7e2012-03-21 18:25:23 +0100294 except self.decimal.DecimalException as exception:
Ezio Melotti13925002011-03-16 11:05:33 +0200295 #Exception raised where there shouldn't have been one.
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000296 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000297
298 return
299
300 def eval_line(self, s):
301 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
302 s = (s.split('->')[0] + '->' +
303 s.split('->')[1].split('--')[0]).strip()
304 else:
305 s = s.split('--')[0].strip()
306
307 for ignore in self.ignore_list:
308 if s.find(ignore) >= 0:
309 #print s.split()[0], 'NotImplemented--', ignore
310 return
311 if not s:
312 return
313 elif ':' in s:
314 return self.eval_directive(s)
315 else:
316 return self.eval_equation(s)
317
318 def eval_directive(self, s):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000319 funct, value = (x.strip().lower() for x in s.split(':'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000320 if funct == 'rounding':
Stefan Krah1919b7e2012-03-21 18:25:23 +0100321 value = self.RoundingDict[value]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000322 else:
323 try:
324 value = int(value)
325 except ValueError:
326 pass
327
Stefan Krah1919b7e2012-03-21 18:25:23 +0100328 funct = self.ChangeDict.get(funct, (lambda *args: None))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000329 funct(value)
330
331 def eval_equation(self, s):
Raymond Hettingered20ad82004-09-04 20:09:13 +0000332
333 if not TEST_ALL and random.random() < 0.90:
334 return
335
Stefan Krah1919b7e2012-03-21 18:25:23 +0100336 self.context.clear_flags()
337
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000338 try:
339 Sides = s.split('->')
340 L = Sides[0].strip().split()
341 id = L[0]
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000342 if DEBUG:
343 print("Test ", id, end=" ")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000344 funct = L[1].lower()
345 valstemp = L[2:]
346 L = Sides[1].strip().split()
347 ans = L[0]
348 exceptions = L[1:]
349 except (TypeError, AttributeError, IndexError):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100350 raise self.decimal.InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000351 def FixQuotes(val):
352 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
353 val = val.replace("'", '').replace('"', '')
354 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
355 return val
Mark Dickinson8a546532009-10-08 16:30:38 +0000356
Stefan Krah1919b7e2012-03-21 18:25:23 +0100357 if id in self.skipped_test_ids:
Mark Dickinson8a546532009-10-08 16:30:38 +0000358 return
359
Stefan Krah1919b7e2012-03-21 18:25:23 +0100360 fname = self.NameAdapter.get(funct, funct)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000361 if fname == 'rescale':
362 return
363 funct = getattr(self.context, fname)
364 vals = []
365 conglomerate = ''
366 quote = 0
Stefan Krah1919b7e2012-03-21 18:25:23 +0100367 theirexceptions = [self.ErrorNames[x.lower()] for x in exceptions]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000368
Stefan Krah1919b7e2012-03-21 18:25:23 +0100369 for exception in Signals[self.decimal]:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000370 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000371 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000372 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000373 for i, val in enumerate(valstemp):
374 if val.count("'") % 2 == 1:
375 quote = 1 - quote
376 if quote:
377 conglomerate = conglomerate + ' ' + val
378 continue
379 else:
380 val = conglomerate + val
381 conglomerate = ''
382 v = FixQuotes(val)
383 if fname in ('to_sci_string', 'to_eng_string'):
384 if EXTENDEDERRORTEST:
385 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000386 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000387 try:
388 funct(self.context.create_decimal(v))
389 except error:
390 pass
Stefan Krah1919b7e2012-03-21 18:25:23 +0100391 except Signals[self.decimal] as e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000392 self.fail("Raised %s in %s when %s disabled" % \
393 (e, s, error))
394 else:
395 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000396 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000397 v = self.context.create_decimal(v)
398 else:
Stefan Krah1919b7e2012-03-21 18:25:23 +0100399 v = self.read_unlimited(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000400 vals.append(v)
401
402 ans = FixQuotes(ans)
403
404 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
405 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000406 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000407 try:
408 funct(*vals)
409 except error:
410 pass
Stefan Krah1919b7e2012-03-21 18:25:23 +0100411 except Signals[self.decimal] as e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000412 self.fail("Raised %s in %s when %s disabled" % \
413 (e, s, error))
414 else:
415 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000416 self.context.traps[error] = 0
Mark Dickinsonc69160e2010-05-04 14:35:33 +0000417
418 # as above, but add traps cumulatively, to check precedence
Stefan Krah1919b7e2012-03-21 18:25:23 +0100419 ordered_errors = [e for e in OrderedSignals[self.decimal] if e in theirexceptions]
Mark Dickinsonc69160e2010-05-04 14:35:33 +0000420 for error in ordered_errors:
421 self.context.traps[error] = 1
422 try:
423 funct(*vals)
424 except error:
425 pass
Stefan Krah1919b7e2012-03-21 18:25:23 +0100426 except Signals[self.decimal] as e:
Mark Dickinsonc69160e2010-05-04 14:35:33 +0000427 self.fail("Raised %s in %s; expected %s" %
428 (type(e), s, error))
429 else:
430 self.fail("Did not raise %s in %s" % (error, s))
431 # reset traps
432 for error in ordered_errors:
433 self.context.traps[error] = 0
434
435
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000436 if DEBUG:
437 print("--", self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000438 try:
439 result = str(funct(*vals))
Stefan Krah1919b7e2012-03-21 18:25:23 +0100440 if fname in self.LogicalFunctions:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000441 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Stefan Krah1919b7e2012-03-21 18:25:23 +0100442 except Signals[self.decimal] as error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000443 self.fail("Raised %s in %s" % (error, s))
444 except: #Catch any error long enough to state the test case.
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000445 print("ERROR:", s)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000446 raise
447
448 myexceptions = self.getexceptions()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000449
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000450 myexceptions.sort(key=repr)
451 theirexceptions.sort(key=repr)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000452
453 self.assertEqual(result, ans,
454 'Incorrect answer for ' + s + ' -- got ' + result)
Stefan Krah1919b7e2012-03-21 18:25:23 +0100455
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000456 self.assertEqual(myexceptions, theirexceptions,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000457 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000458 return
459
460 def getexceptions(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100461 return [e for e in Signals[self.decimal] if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000462
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000463 def change_precision(self, prec):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100464 if self.decimal == C and self.decimal.MAX_PREC == 425000000:
465 self.context._unsafe_setprec(prec)
466 else:
467 self.context.prec = prec
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000468 def change_rounding_method(self, rounding):
469 self.context.rounding = rounding
470 def change_min_exponent(self, exp):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100471 if self.decimal == C and self.decimal.MAX_PREC == 425000000:
472 self.context._unsafe_setemin(exp)
473 else:
474 self.context.Emin = exp
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000475 def change_max_exponent(self, exp):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100476 if self.decimal == C and self.decimal.MAX_PREC == 425000000:
477 self.context._unsafe_setemax(exp)
478 else:
479 self.context.Emax = exp
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000480 def change_clamp(self, clamp):
Mark Dickinsonb1d8e322010-05-22 18:35:36 +0000481 self.context.clamp = clamp
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000482
Stefan Krah1919b7e2012-03-21 18:25:23 +0100483class CIBMTestCases(IBMTestCases):
484 decimal = C
485class PyIBMTestCases(IBMTestCases):
486 decimal = P
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000487
488# The following classes test the behaviour of Decimal according to PEP 327
489
Stefan Krah1919b7e2012-03-21 18:25:23 +0100490class ExplicitConstructionTest(unittest.TestCase):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000491 '''Unit tests for Explicit Construction cases of Decimal.'''
492
493 def test_explicit_empty(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100494 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000495 self.assertEqual(Decimal(), Decimal("0"))
496
497 def test_explicit_from_None(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100498 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000499 self.assertRaises(TypeError, Decimal, None)
500
501 def test_explicit_from_int(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100502 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000503
504 #positive
505 d = Decimal(45)
506 self.assertEqual(str(d), '45')
507
508 #very large positive
509 d = Decimal(500000123)
510 self.assertEqual(str(d), '500000123')
511
512 #negative
513 d = Decimal(-45)
514 self.assertEqual(str(d), '-45')
515
516 #zero
517 d = Decimal(0)
518 self.assertEqual(str(d), '0')
519
Stefan Krah1919b7e2012-03-21 18:25:23 +0100520 # single word longs
521 for n in range(0, 32):
522 for sign in (-1, 1):
523 for x in range(-5, 5):
524 i = sign * (2**n + x)
525 d = Decimal(i)
526 self.assertEqual(str(d), str(i))
527
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000528 def test_explicit_from_string(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100529 Decimal = self.decimal.Decimal
530 InvalidOperation = self.decimal.InvalidOperation
531 localcontext = self.decimal.localcontext
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000532
533 #empty
534 self.assertEqual(str(Decimal('')), 'NaN')
535
536 #int
537 self.assertEqual(str(Decimal('45')), '45')
538
539 #float
540 self.assertEqual(str(Decimal('45.34')), '45.34')
541
542 #engineer notation
543 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
544
545 #just not a number
546 self.assertEqual(str(Decimal('ugly')), 'NaN')
547
Christian Heimesa62da1d2008-01-12 19:39:10 +0000548 #leading and trailing whitespace permitted
549 self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
550 self.assertEqual(str(Decimal(' -7.89')), '-7.89')
Stefan Krah1919b7e2012-03-21 18:25:23 +0100551 self.assertEqual(str(Decimal(" 3.45679 ")), '3.45679')
552
553 # unicode whitespace
554 for lead in ["", ' ', '\u00a0', '\u205f']:
555 for trail in ["", ' ', '\u00a0', '\u205f']:
556 self.assertEqual(str(Decimal(lead + '9.311E+28' + trail)),
557 '9.311E+28')
558
559 with localcontext() as c:
560 c.traps[InvalidOperation] = True
561 # Invalid string
562 self.assertRaises(InvalidOperation, Decimal, "xyz")
563 # Two arguments max
564 self.assertRaises(TypeError, Decimal, "1234", "x", "y")
565
566 # space within the numeric part
567 self.assertRaises(InvalidOperation, Decimal, "1\u00a02\u00a03")
568 self.assertRaises(InvalidOperation, Decimal, "\u00a01\u00a02\u00a0")
569
570 # unicode whitespace
571 self.assertRaises(InvalidOperation, Decimal, "\u00a0")
572 self.assertRaises(InvalidOperation, Decimal, "\u00a0\u00a0")
573
574 # embedded NUL
575 self.assertRaises(InvalidOperation, Decimal, "12\u00003")
576
Christian Heimesa62da1d2008-01-12 19:39:10 +0000577
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000578 def test_explicit_from_tuples(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100579 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000580
581 #zero
582 d = Decimal( (0, (0,), 0) )
583 self.assertEqual(str(d), '0')
584
585 #int
586 d = Decimal( (1, (4, 5), 0) )
587 self.assertEqual(str(d), '-45')
588
589 #float
590 d = Decimal( (0, (4, 5, 3, 4), -2) )
591 self.assertEqual(str(d), '45.34')
592
593 #weird
594 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
595 self.assertEqual(str(d), '-4.34913534E-17')
596
Stefan Krah1919b7e2012-03-21 18:25:23 +0100597 #inf
598 d = Decimal( (0, (), "F") )
599 self.assertEqual(str(d), 'Infinity')
600
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000601 #wrong number of items
602 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
603
604 #bad sign
605 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000606 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
607 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000608
609 #bad exp
610 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000611 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
612 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000613
614 #bad coefficients
Stefan Krah1919b7e2012-03-21 18:25:23 +0100615 self.assertRaises(ValueError, Decimal, (1, "xyz", 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000616 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
617 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000618 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Guido van Rossum0d3fb8a2007-11-26 23:23:18 +0000619 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000620
Stefan Krah1919b7e2012-03-21 18:25:23 +0100621 def test_explicit_from_list(self):
622 Decimal = self.decimal.Decimal
623
624 d = Decimal([0, [0], 0])
625 self.assertEqual(str(d), '0')
626
627 d = Decimal([1, [4, 3, 4, 9, 1, 3, 5, 3, 4], -25])
628 self.assertEqual(str(d), '-4.34913534E-17')
629
630 d = Decimal([1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25])
631 self.assertEqual(str(d), '-4.34913534E-17')
632
633 d = Decimal((1, [4, 3, 4, 9, 1, 3, 5, 3, 4], -25))
634 self.assertEqual(str(d), '-4.34913534E-17')
635
Antoine Pitrou503ab332010-03-30 18:56:19 +0000636 def test_explicit_from_bool(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100637 Decimal = self.decimal.Decimal
638
Antoine Pitrou503ab332010-03-30 18:56:19 +0000639 self.assertIs(bool(Decimal(0)), False)
640 self.assertIs(bool(Decimal(1)), True)
641 self.assertEqual(Decimal(False), Decimal(0))
642 self.assertEqual(Decimal(True), Decimal(1))
643
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000644 def test_explicit_from_Decimal(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100645 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000646
647 #positive
648 d = Decimal(45)
649 e = Decimal(d)
650 self.assertEqual(str(e), '45')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000651
652 #very large positive
653 d = Decimal(500000123)
654 e = Decimal(d)
655 self.assertEqual(str(e), '500000123')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000656
657 #negative
658 d = Decimal(-45)
659 e = Decimal(d)
660 self.assertEqual(str(e), '-45')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000661
662 #zero
663 d = Decimal(0)
664 e = Decimal(d)
665 self.assertEqual(str(e), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000666
Raymond Hettinger96798592010-04-02 16:58:27 +0000667 @requires_IEEE_754
668 def test_explicit_from_float(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100669
670 Decimal = self.decimal.Decimal
671
Raymond Hettinger96798592010-04-02 16:58:27 +0000672 r = Decimal(0.1)
673 self.assertEqual(type(r), Decimal)
674 self.assertEqual(str(r),
675 '0.1000000000000000055511151231257827021181583404541015625')
676 self.assertTrue(Decimal(float('nan')).is_qnan())
677 self.assertTrue(Decimal(float('inf')).is_infinite())
678 self.assertTrue(Decimal(float('-inf')).is_infinite())
679 self.assertEqual(str(Decimal(float('nan'))),
680 str(Decimal('NaN')))
681 self.assertEqual(str(Decimal(float('inf'))),
682 str(Decimal('Infinity')))
683 self.assertEqual(str(Decimal(float('-inf'))),
684 str(Decimal('-Infinity')))
685 self.assertEqual(str(Decimal(float('-0.0'))),
686 str(Decimal('-0')))
687 for i in range(200):
688 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
689 self.assertEqual(x, float(Decimal(x))) # roundtrip
690
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000691 def test_explicit_context_create_decimal(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100692 Decimal = self.decimal.Decimal
693 InvalidOperation = self.decimal.InvalidOperation
694 Rounded = self.decimal.Rounded
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000695
Stefan Krah1919b7e2012-03-21 18:25:23 +0100696 nc = copy.copy(self.decimal.getcontext())
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000697 nc.prec = 3
698
699 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000700 d = Decimal()
701 self.assertEqual(str(d), '0')
702 d = nc.create_decimal()
703 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000704
705 # from None
706 self.assertRaises(TypeError, nc.create_decimal, None)
707
708 # from int
709 d = nc.create_decimal(456)
Ezio Melottie9615932010-01-24 19:26:24 +0000710 self.assertIsInstance(d, Decimal)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000711 self.assertEqual(nc.create_decimal(45678),
712 nc.create_decimal('457E+2'))
713
714 # from string
715 d = Decimal('456789')
716 self.assertEqual(str(d), '456789')
717 d = nc.create_decimal('456789')
718 self.assertEqual(str(d), '4.57E+5')
Christian Heimesa62da1d2008-01-12 19:39:10 +0000719 # leading and trailing whitespace should result in a NaN;
720 # spaces are already checked in Cowlishaw's test-suite, so
721 # here we just check that a trailing newline results in a NaN
722 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000723
724 # from tuples
725 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
726 self.assertEqual(str(d), '-4.34913534E-17')
727 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
728 self.assertEqual(str(d), '-4.35E-17')
729
730 # from Decimal
731 prevdec = Decimal(500000123)
732 d = Decimal(prevdec)
733 self.assertEqual(str(d), '500000123')
734 d = nc.create_decimal(prevdec)
735 self.assertEqual(str(d), '5.00E+8')
736
Stefan Krah1919b7e2012-03-21 18:25:23 +0100737 # more integers
738 nc.prec = 28
739 nc.traps[InvalidOperation] = True
740
741 for v in [-2**63-1, -2**63, -2**31-1, -2**31, 0,
742 2**31-1, 2**31, 2**63-1, 2**63]:
743 d = nc.create_decimal(v)
744 self.assertTrue(isinstance(d, Decimal))
745 self.assertEqual(int(d), v)
746
747 nc.prec = 3
748 nc.traps[Rounded] = True
749 self.assertRaises(Rounded, nc.create_decimal, 1234)
750
751 # from string
752 nc.prec = 28
753 self.assertEqual(str(nc.create_decimal('0E-017')), '0E-17')
754 self.assertEqual(str(nc.create_decimal('45')), '45')
755 self.assertEqual(str(nc.create_decimal('-Inf')), '-Infinity')
756 self.assertEqual(str(nc.create_decimal('NaN123')), 'NaN123')
757
758 # invalid arguments
759 self.assertRaises(InvalidOperation, nc.create_decimal, "xyz")
760 self.assertRaises(ValueError, nc.create_decimal, (1, "xyz", -25))
761 self.assertRaises(TypeError, nc.create_decimal, "1234", "5678")
762
763 # too many NaN payload digits
764 nc.prec = 3
765 self.assertRaises(InvalidOperation, nc.create_decimal, 'NaN12345')
766 self.assertRaises(InvalidOperation, nc.create_decimal,
767 Decimal('NaN12345'))
768
769 nc.traps[InvalidOperation] = False
770 self.assertEqual(str(nc.create_decimal('NaN12345')), 'NaN')
771 self.assertTrue(nc.flags[InvalidOperation])
772
773 nc.flags[InvalidOperation] = False
774 self.assertEqual(str(nc.create_decimal(Decimal('NaN12345'))), 'NaN')
775 self.assertTrue(nc.flags[InvalidOperation])
776
777 def test_explicit_context_create_from_float(self):
778
779 Decimal = self.decimal.Decimal
780
781 nc = self.decimal.Context()
782 r = nc.create_decimal(0.1)
783 self.assertEqual(type(r), Decimal)
784 self.assertEqual(str(r), '0.1000000000000000055511151231')
785 self.assertTrue(nc.create_decimal(float('nan')).is_qnan())
786 self.assertTrue(nc.create_decimal(float('inf')).is_infinite())
787 self.assertTrue(nc.create_decimal(float('-inf')).is_infinite())
788 self.assertEqual(str(nc.create_decimal(float('nan'))),
789 str(nc.create_decimal('NaN')))
790 self.assertEqual(str(nc.create_decimal(float('inf'))),
791 str(nc.create_decimal('Infinity')))
792 self.assertEqual(str(nc.create_decimal(float('-inf'))),
793 str(nc.create_decimal('-Infinity')))
794 self.assertEqual(str(nc.create_decimal(float('-0.0'))),
795 str(nc.create_decimal('-0')))
796 nc.prec = 100
797 for i in range(200):
798 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
799 self.assertEqual(x, float(nc.create_decimal(x))) # roundtrip
800
Mark Dickinson345adc42009-08-02 10:14:23 +0000801 def test_unicode_digits(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100802 Decimal = self.decimal.Decimal
803
Mark Dickinson345adc42009-08-02 10:14:23 +0000804 test_values = {
805 '\uff11': '1',
806 '\u0660.\u0660\u0663\u0667\u0662e-\u0663' : '0.0000372',
807 '-nan\u0c68\u0c6a\u0c66\u0c66' : '-NaN2400',
808 }
809 for input, expected in test_values.items():
810 self.assertEqual(str(Decimal(input)), expected)
811
Stefan Krah1919b7e2012-03-21 18:25:23 +0100812class CExplicitConstructionTest(ExplicitConstructionTest):
813 decimal = C
814class PyExplicitConstructionTest(ExplicitConstructionTest):
815 decimal = P
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000816
Stefan Krah1919b7e2012-03-21 18:25:23 +0100817class ImplicitConstructionTest(unittest.TestCase):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000818 '''Unit tests for Implicit Construction cases of Decimal.'''
819
820 def test_implicit_from_None(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100821 Decimal = self.decimal.Decimal
822 self.assertRaises(TypeError, eval, 'Decimal(5) + None', locals())
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000823
824 def test_implicit_from_int(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100825 Decimal = self.decimal.Decimal
826
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000827 #normal
828 self.assertEqual(str(Decimal(5) + 45), '50')
829 #exceeding precision
830 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
831
832 def test_implicit_from_string(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100833 Decimal = self.decimal.Decimal
834 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', locals())
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000835
836 def test_implicit_from_float(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100837 Decimal = self.decimal.Decimal
838 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', locals())
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000839
840 def test_implicit_from_Decimal(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100841 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000842 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
843
Raymond Hettinger267b8682005-03-27 10:47:39 +0000844 def test_rop(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100845 Decimal = self.decimal.Decimal
846
Raymond Hettinger267b8682005-03-27 10:47:39 +0000847 # Allow other classes to be trained to interact with Decimals
848 class E:
849 def __divmod__(self, other):
850 return 'divmod ' + str(other)
851 def __rdivmod__(self, other):
852 return str(other) + ' rdivmod'
853 def __lt__(self, other):
854 return 'lt ' + str(other)
855 def __gt__(self, other):
856 return 'gt ' + str(other)
857 def __le__(self, other):
858 return 'le ' + str(other)
859 def __ge__(self, other):
860 return 'ge ' + str(other)
861 def __eq__(self, other):
862 return 'eq ' + str(other)
863 def __ne__(self, other):
864 return 'ne ' + str(other)
865
866 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
867 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
868 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
869 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
870 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
871 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
872 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
873 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
874
875 # insert operator methods and then exercise them
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000876 oplist = [
877 ('+', '__add__', '__radd__'),
878 ('-', '__sub__', '__rsub__'),
879 ('*', '__mul__', '__rmul__'),
Thomas Woutersdcc6d322006-04-21 11:30:52 +0000880 ('/', '__truediv__', '__rtruediv__'),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000881 ('%', '__mod__', '__rmod__'),
882 ('//', '__floordiv__', '__rfloordiv__'),
883 ('**', '__pow__', '__rpow__')
884 ]
Raymond Hettinger267b8682005-03-27 10:47:39 +0000885
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000886 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000887 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
888 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
889 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
890 'str' + lop + '10')
891 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
892 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000893
Stefan Krah1919b7e2012-03-21 18:25:23 +0100894class CImplicitConstructionTest(ImplicitConstructionTest):
895 decimal = C
896class PyImplicitConstructionTest(ImplicitConstructionTest):
897 decimal = P
Mark Dickinson79f52032009-03-17 23:12:51 +0000898
Stefan Krah1919b7e2012-03-21 18:25:23 +0100899class FormatTest(unittest.TestCase):
Christian Heimesf16baeb2008-02-29 14:57:44 +0000900 '''Unit tests for the format function.'''
901 def test_formatting(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100902 Decimal = self.decimal.Decimal
903
Christian Heimesf16baeb2008-02-29 14:57:44 +0000904 # triples giving a format, a Decimal, and the expected result
905 test_values = [
906 ('e', '0E-15', '0e-15'),
907 ('e', '2.3E-15', '2.3e-15'),
908 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
909 ('e', '2.30000E-15', '2.30000e-15'),
910 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
911 ('e', '1.5', '1.5e+0'),
912 ('e', '0.15', '1.5e-1'),
913 ('e', '0.015', '1.5e-2'),
914 ('e', '0.0000000000015', '1.5e-12'),
915 ('e', '15.0', '1.50e+1'),
916 ('e', '-15', '-1.5e+1'),
917 ('e', '0', '0e+0'),
918 ('e', '0E1', '0e+1'),
919 ('e', '0.0', '0e-1'),
920 ('e', '0.00', '0e-2'),
921 ('.6e', '0E-15', '0.000000e-9'),
922 ('.6e', '0', '0.000000e+6'),
923 ('.6e', '9.999999', '9.999999e+0'),
924 ('.6e', '9.9999999', '1.000000e+1'),
925 ('.6e', '-1.23e5', '-1.230000e+5'),
926 ('.6e', '1.23456789e-3', '1.234568e-3'),
927 ('f', '0', '0'),
928 ('f', '0.0', '0.0'),
929 ('f', '0E-2', '0.00'),
930 ('f', '0.00E-8', '0.0000000000'),
931 ('f', '0E1', '0'), # loses exponent information
932 ('f', '3.2E1', '32'),
933 ('f', '3.2E2', '320'),
934 ('f', '3.20E2', '320'),
935 ('f', '3.200E2', '320.0'),
936 ('f', '3.2E-6', '0.0000032'),
937 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
938 ('.6f', '0E1', '0.000000'),
939 ('.6f', '0', '0.000000'),
940 ('.0f', '0', '0'), # no decimal point
941 ('.0f', '0e-2', '0'),
942 ('.0f', '3.14159265', '3'),
943 ('.1f', '3.14159265', '3.1'),
944 ('.4f', '3.14159265', '3.1416'),
945 ('.6f', '3.14159265', '3.141593'),
946 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
947 ('.8f', '3.14159265', '3.14159265'),
948 ('.9f', '3.14159265', '3.141592650'),
949
950 ('g', '0', '0'),
951 ('g', '0.0', '0.0'),
952 ('g', '0E1', '0e+1'),
953 ('G', '0E1', '0E+1'),
954 ('g', '0E-5', '0.00000'),
955 ('g', '0E-6', '0.000000'),
956 ('g', '0E-7', '0e-7'),
957 ('g', '-0E2', '-0e+2'),
958 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
Stefan Krah1919b7e2012-03-21 18:25:23 +0100959 ('.0n', '3.14159265', '3'), # same for 'n'
Christian Heimesf16baeb2008-02-29 14:57:44 +0000960 ('.1g', '3.14159265', '3'),
961 ('.2g', '3.14159265', '3.1'),
962 ('.5g', '3.14159265', '3.1416'),
963 ('.7g', '3.14159265', '3.141593'),
964 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
965 ('.9g', '3.14159265', '3.14159265'),
966 ('.10g', '3.14159265', '3.14159265'), # don't pad
967
968 ('%', '0E1', '0%'),
969 ('%', '0E0', '0%'),
970 ('%', '0E-1', '0%'),
971 ('%', '0E-2', '0%'),
972 ('%', '0E-3', '0.0%'),
973 ('%', '0E-4', '0.00%'),
974
975 ('.3%', '0', '0.000%'), # all zeros treated equally
976 ('.3%', '0E10', '0.000%'),
977 ('.3%', '0E-10', '0.000%'),
978 ('.3%', '2.34', '234.000%'),
979 ('.3%', '1.234567', '123.457%'),
980 ('.0%', '1.23', '123%'),
981
982 ('e', 'NaN', 'NaN'),
983 ('f', '-NaN123', '-NaN123'),
984 ('+g', 'NaN456', '+NaN456'),
985 ('.3e', 'Inf', 'Infinity'),
986 ('.16f', '-Inf', '-Infinity'),
987 ('.0g', '-sNaN', '-sNaN'),
988
989 ('', '1.00', '1.00'),
Mark Dickinsonad416342009-03-17 18:10:15 +0000990
Mark Dickinson79f52032009-03-17 23:12:51 +0000991 # test alignment and padding
Mark Dickinson46ab5d02009-09-08 20:22:46 +0000992 ('6', '123', ' 123'),
Mark Dickinsonad416342009-03-17 18:10:15 +0000993 ('<6', '123', '123 '),
994 ('>6', '123', ' 123'),
995 ('^6', '123', ' 123 '),
996 ('=+6', '123', '+ 123'),
Mark Dickinson79f52032009-03-17 23:12:51 +0000997 ('#<10', 'NaN', 'NaN#######'),
998 ('#<10', '-4.3', '-4.3######'),
999 ('#<+10', '0.0130', '+0.0130###'),
1000 ('#< 10', '0.0130', ' 0.0130###'),
1001 ('@>10', '-Inf', '@-Infinity'),
1002 ('#>5', '-Inf', '-Infinity'),
1003 ('?^5', '123', '?123?'),
1004 ('%^6', '123', '%123%%'),
1005 (' ^6', '-45.6', '-45.6 '),
1006 ('/=10', '-45.6', '-/////45.6'),
1007 ('/=+10', '45.6', '+/////45.6'),
1008 ('/= 10', '45.6', ' /////45.6'),
1009
1010 # thousands separator
1011 (',', '1234567', '1,234,567'),
1012 (',', '123456', '123,456'),
1013 (',', '12345', '12,345'),
1014 (',', '1234', '1,234'),
1015 (',', '123', '123'),
1016 (',', '12', '12'),
1017 (',', '1', '1'),
1018 (',', '0', '0'),
1019 (',', '-1234567', '-1,234,567'),
1020 (',', '-123456', '-123,456'),
1021 ('7,', '123456', '123,456'),
Mark Dickinson46ab5d02009-09-08 20:22:46 +00001022 ('8,', '123456', ' 123,456'),
Mark Dickinson79f52032009-03-17 23:12:51 +00001023 ('08,', '123456', '0,123,456'), # special case: extra 0 needed
1024 ('+08,', '123456', '+123,456'), # but not if there's a sign
1025 (' 08,', '123456', ' 123,456'),
1026 ('08,', '-123456', '-123,456'),
1027 ('+09,', '123456', '+0,123,456'),
1028 # ... with fractional part...
1029 ('07,', '1234.56', '1,234.56'),
1030 ('08,', '1234.56', '1,234.56'),
1031 ('09,', '1234.56', '01,234.56'),
1032 ('010,', '1234.56', '001,234.56'),
1033 ('011,', '1234.56', '0,001,234.56'),
1034 ('012,', '1234.56', '0,001,234.56'),
1035 ('08,.1f', '1234.5', '01,234.5'),
1036 # no thousands separators in fraction part
1037 (',', '1.23456789', '1.23456789'),
1038 (',%', '123.456789', '12,345.6789%'),
1039 (',e', '123456', '1.23456e+5'),
1040 (',E', '123456', '1.23456E+5'),
Mark Dickinson7718d2b2009-09-07 16:21:56 +00001041
1042 # issue 6850
1043 ('a=-7.0', '0.12345', 'aaaa0.1'),
Christian Heimesf16baeb2008-02-29 14:57:44 +00001044 ]
1045 for fmt, d, result in test_values:
1046 self.assertEqual(format(Decimal(d), fmt), result)
1047
Stefan Krah1919b7e2012-03-21 18:25:23 +01001048 # bytes format argument
1049 self.assertRaises(TypeError, Decimal(1).__format__, b'-020')
1050
Mark Dickinson79f52032009-03-17 23:12:51 +00001051 def test_n_format(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001052 Decimal = self.decimal.Decimal
1053
Mark Dickinson79f52032009-03-17 23:12:51 +00001054 try:
1055 from locale import CHAR_MAX
1056 except ImportError:
1057 return
1058
Stefan Krah1919b7e2012-03-21 18:25:23 +01001059 def make_grouping(lst):
1060 return ''.join([chr(x) for x in lst]) if self.decimal == C else lst
1061
1062 def get_fmt(x, override=None, fmt='n'):
1063 if self.decimal == C:
1064 return Decimal(x).__format__(fmt, override)
1065 else:
1066 return Decimal(x).__format__(fmt, _localeconv=override)
1067
Mark Dickinson79f52032009-03-17 23:12:51 +00001068 # Set up some localeconv-like dictionaries
1069 en_US = {
1070 'decimal_point' : '.',
Stefan Krah1919b7e2012-03-21 18:25:23 +01001071 'grouping' : make_grouping([3, 3, 0]),
1072 'thousands_sep' : ','
Mark Dickinson79f52032009-03-17 23:12:51 +00001073 }
1074
1075 fr_FR = {
1076 'decimal_point' : ',',
Stefan Krah1919b7e2012-03-21 18:25:23 +01001077 'grouping' : make_grouping([CHAR_MAX]),
Mark Dickinson79f52032009-03-17 23:12:51 +00001078 'thousands_sep' : ''
1079 }
1080
1081 ru_RU = {
1082 'decimal_point' : ',',
Stefan Krah1919b7e2012-03-21 18:25:23 +01001083 'grouping': make_grouping([3, 3, 0]),
Mark Dickinson79f52032009-03-17 23:12:51 +00001084 'thousands_sep' : ' '
1085 }
1086
1087 crazy = {
1088 'decimal_point' : '&',
Stefan Krah1919b7e2012-03-21 18:25:23 +01001089 'grouping': make_grouping([1, 4, 2, CHAR_MAX]),
Mark Dickinson79f52032009-03-17 23:12:51 +00001090 'thousands_sep' : '-'
1091 }
1092
Stefan Krah1919b7e2012-03-21 18:25:23 +01001093 dotsep_wide = {
1094 'decimal_point' : b'\xc2\xbf'.decode('utf-8'),
1095 'grouping': make_grouping([3, 3, 0]),
1096 'thousands_sep' : b'\xc2\xb4'.decode('utf-8')
1097 }
Mark Dickinson79f52032009-03-17 23:12:51 +00001098
1099 self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7')
1100 self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7')
1101 self.assertEqual(get_fmt(Decimal('12.7'), ru_RU), '12,7')
1102 self.assertEqual(get_fmt(Decimal('12.7'), crazy), '1-2&7')
1103
1104 self.assertEqual(get_fmt(123456789, en_US), '123,456,789')
1105 self.assertEqual(get_fmt(123456789, fr_FR), '123456789')
1106 self.assertEqual(get_fmt(123456789, ru_RU), '123 456 789')
1107 self.assertEqual(get_fmt(1234567890123, crazy), '123456-78-9012-3')
1108
1109 self.assertEqual(get_fmt(123456789, en_US, '.6n'), '1.23457e+8')
1110 self.assertEqual(get_fmt(123456789, fr_FR, '.6n'), '1,23457e+8')
1111 self.assertEqual(get_fmt(123456789, ru_RU, '.6n'), '1,23457e+8')
1112 self.assertEqual(get_fmt(123456789, crazy, '.6n'), '1&23457e+8')
1113
Mark Dickinson7303b592009-03-18 08:25:36 +00001114 # zero padding
1115 self.assertEqual(get_fmt(1234, fr_FR, '03n'), '1234')
1116 self.assertEqual(get_fmt(1234, fr_FR, '04n'), '1234')
1117 self.assertEqual(get_fmt(1234, fr_FR, '05n'), '01234')
1118 self.assertEqual(get_fmt(1234, fr_FR, '06n'), '001234')
1119
1120 self.assertEqual(get_fmt(12345, en_US, '05n'), '12,345')
1121 self.assertEqual(get_fmt(12345, en_US, '06n'), '12,345')
1122 self.assertEqual(get_fmt(12345, en_US, '07n'), '012,345')
1123 self.assertEqual(get_fmt(12345, en_US, '08n'), '0,012,345')
1124 self.assertEqual(get_fmt(12345, en_US, '09n'), '0,012,345')
1125 self.assertEqual(get_fmt(12345, en_US, '010n'), '00,012,345')
1126
1127 self.assertEqual(get_fmt(123456, crazy, '06n'), '1-2345-6')
1128 self.assertEqual(get_fmt(123456, crazy, '07n'), '1-2345-6')
1129 self.assertEqual(get_fmt(123456, crazy, '08n'), '1-2345-6')
1130 self.assertEqual(get_fmt(123456, crazy, '09n'), '01-2345-6')
1131 self.assertEqual(get_fmt(123456, crazy, '010n'), '0-01-2345-6')
1132 self.assertEqual(get_fmt(123456, crazy, '011n'), '0-01-2345-6')
1133 self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6')
1134 self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6')
1135
Stefan Krah1919b7e2012-03-21 18:25:23 +01001136 # wide char separator and decimal point
1137 self.assertEqual(get_fmt(Decimal('-1.5'), dotsep_wide, '020n'),
1138 '-0\u00b4000\u00b4000\u00b4000\u00b4001\u00bf5')
Mark Dickinson79f52032009-03-17 23:12:51 +00001139
Stefan Krah6fb204a2012-09-28 16:18:54 +02001140 @run_with_locale('LC_ALL', 'ps_AF')
Stefan Krah1919b7e2012-03-21 18:25:23 +01001141 def test_wide_char_separator_decimal_point(self):
1142 # locale with wide char separator and decimal point
Stefan Krah8a491a82012-09-28 17:17:11 +02001143 import locale
Stefan Krah1919b7e2012-03-21 18:25:23 +01001144 Decimal = self.decimal.Decimal
1145
Stefan Krah8a491a82012-09-28 17:17:11 +02001146 decimal_point = locale.localeconv()['decimal_point']
1147 thousands_sep = locale.localeconv()['thousands_sep']
1148 if decimal_point != '\u066b' or thousands_sep != '\u066c':
1149 return
1150
Stefan Krah1919b7e2012-03-21 18:25:23 +01001151 self.assertEqual(format(Decimal('100000000.123'), 'n'),
1152 '100\u066c000\u066c000\u066b123')
Stefan Krah1919b7e2012-03-21 18:25:23 +01001153
1154class CFormatTest(FormatTest):
1155 decimal = C
1156class PyFormatTest(FormatTest):
1157 decimal = P
1158
1159class ArithmeticOperatorsTest(unittest.TestCase):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001160 '''Unit tests for all arithmetic operators, binary and unary.'''
1161
1162 def test_addition(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001163 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001164
1165 d1 = Decimal('-11.1')
1166 d2 = Decimal('22.2')
1167
1168 #two Decimals
1169 self.assertEqual(d1+d2, Decimal('11.1'))
1170 self.assertEqual(d2+d1, Decimal('11.1'))
1171
1172 #with other type, left
1173 c = d1 + 5
1174 self.assertEqual(c, Decimal('-6.1'))
1175 self.assertEqual(type(c), type(d1))
1176
1177 #with other type, right
1178 c = 5 + d1
1179 self.assertEqual(c, Decimal('-6.1'))
1180 self.assertEqual(type(c), type(d1))
1181
1182 #inline with decimal
1183 d1 += d2
1184 self.assertEqual(d1, Decimal('11.1'))
1185
1186 #inline with other type
1187 d1 += 5
1188 self.assertEqual(d1, Decimal('16.1'))
1189
1190 def test_subtraction(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001191 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001192
1193 d1 = Decimal('-11.1')
1194 d2 = Decimal('22.2')
1195
1196 #two Decimals
1197 self.assertEqual(d1-d2, Decimal('-33.3'))
1198 self.assertEqual(d2-d1, Decimal('33.3'))
1199
1200 #with other type, left
1201 c = d1 - 5
1202 self.assertEqual(c, Decimal('-16.1'))
1203 self.assertEqual(type(c), type(d1))
1204
1205 #with other type, right
1206 c = 5 - d1
1207 self.assertEqual(c, Decimal('16.1'))
1208 self.assertEqual(type(c), type(d1))
1209
1210 #inline with decimal
1211 d1 -= d2
1212 self.assertEqual(d1, Decimal('-33.3'))
1213
1214 #inline with other type
1215 d1 -= 5
1216 self.assertEqual(d1, Decimal('-38.3'))
1217
1218 def test_multiplication(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001219 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001220
1221 d1 = Decimal('-5')
1222 d2 = Decimal('3')
1223
1224 #two Decimals
1225 self.assertEqual(d1*d2, Decimal('-15'))
1226 self.assertEqual(d2*d1, Decimal('-15'))
1227
1228 #with other type, left
1229 c = d1 * 5
1230 self.assertEqual(c, Decimal('-25'))
1231 self.assertEqual(type(c), type(d1))
1232
1233 #with other type, right
1234 c = 5 * d1
1235 self.assertEqual(c, Decimal('-25'))
1236 self.assertEqual(type(c), type(d1))
1237
1238 #inline with decimal
1239 d1 *= d2
1240 self.assertEqual(d1, Decimal('-15'))
1241
1242 #inline with other type
1243 d1 *= 5
1244 self.assertEqual(d1, Decimal('-75'))
1245
1246 def test_division(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001247 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001248
1249 d1 = Decimal('-5')
1250 d2 = Decimal('2')
1251
1252 #two Decimals
1253 self.assertEqual(d1/d2, Decimal('-2.5'))
1254 self.assertEqual(d2/d1, Decimal('-0.4'))
1255
1256 #with other type, left
1257 c = d1 / 4
1258 self.assertEqual(c, Decimal('-1.25'))
1259 self.assertEqual(type(c), type(d1))
1260
1261 #with other type, right
1262 c = 4 / d1
1263 self.assertEqual(c, Decimal('-0.8'))
1264 self.assertEqual(type(c), type(d1))
1265
1266 #inline with decimal
1267 d1 /= d2
1268 self.assertEqual(d1, Decimal('-2.5'))
1269
1270 #inline with other type
1271 d1 /= 4
1272 self.assertEqual(d1, Decimal('-0.625'))
1273
1274 def test_floor_division(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001275 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001276
1277 d1 = Decimal('5')
1278 d2 = Decimal('2')
1279
1280 #two Decimals
1281 self.assertEqual(d1//d2, Decimal('2'))
1282 self.assertEqual(d2//d1, Decimal('0'))
1283
1284 #with other type, left
1285 c = d1 // 4
1286 self.assertEqual(c, Decimal('1'))
1287 self.assertEqual(type(c), type(d1))
1288
1289 #with other type, right
1290 c = 7 // d1
1291 self.assertEqual(c, Decimal('1'))
1292 self.assertEqual(type(c), type(d1))
1293
1294 #inline with decimal
1295 d1 //= d2
1296 self.assertEqual(d1, Decimal('2'))
1297
1298 #inline with other type
1299 d1 //= 2
1300 self.assertEqual(d1, Decimal('1'))
1301
1302 def test_powering(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001303 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001304
1305 d1 = Decimal('5')
1306 d2 = Decimal('2')
1307
1308 #two Decimals
1309 self.assertEqual(d1**d2, Decimal('25'))
1310 self.assertEqual(d2**d1, Decimal('32'))
1311
1312 #with other type, left
1313 c = d1 ** 4
1314 self.assertEqual(c, Decimal('625'))
1315 self.assertEqual(type(c), type(d1))
1316
1317 #with other type, right
1318 c = 7 ** d1
1319 self.assertEqual(c, Decimal('16807'))
1320 self.assertEqual(type(c), type(d1))
1321
1322 #inline with decimal
1323 d1 **= d2
1324 self.assertEqual(d1, Decimal('25'))
1325
1326 #inline with other type
1327 d1 **= 4
1328 self.assertEqual(d1, Decimal('390625'))
1329
1330 def test_module(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001331 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001332
1333 d1 = Decimal('5')
1334 d2 = Decimal('2')
1335
1336 #two Decimals
1337 self.assertEqual(d1%d2, Decimal('1'))
1338 self.assertEqual(d2%d1, Decimal('2'))
1339
1340 #with other type, left
1341 c = d1 % 4
1342 self.assertEqual(c, Decimal('1'))
1343 self.assertEqual(type(c), type(d1))
1344
1345 #with other type, right
1346 c = 7 % d1
1347 self.assertEqual(c, Decimal('2'))
1348 self.assertEqual(type(c), type(d1))
1349
1350 #inline with decimal
1351 d1 %= d2
1352 self.assertEqual(d1, Decimal('1'))
1353
1354 #inline with other type
1355 d1 %= 4
1356 self.assertEqual(d1, Decimal('1'))
1357
1358 def test_floor_div_module(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001359 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001360
1361 d1 = Decimal('5')
1362 d2 = Decimal('2')
1363
1364 #two Decimals
1365 (p, q) = divmod(d1, d2)
1366 self.assertEqual(p, Decimal('2'))
1367 self.assertEqual(q, Decimal('1'))
1368 self.assertEqual(type(p), type(d1))
1369 self.assertEqual(type(q), type(d1))
1370
1371 #with other type, left
1372 (p, q) = divmod(d1, 4)
1373 self.assertEqual(p, Decimal('1'))
1374 self.assertEqual(q, Decimal('1'))
1375 self.assertEqual(type(p), type(d1))
1376 self.assertEqual(type(q), type(d1))
1377
1378 #with other type, right
1379 (p, q) = divmod(7, d1)
1380 self.assertEqual(p, Decimal('1'))
1381 self.assertEqual(q, Decimal('2'))
1382 self.assertEqual(type(p), type(d1))
1383 self.assertEqual(type(q), type(d1))
1384
1385 def test_unary_operators(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001386 Decimal = self.decimal.Decimal
1387
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001388 self.assertEqual(+Decimal(45), Decimal(+45)) # +
1389 self.assertEqual(-Decimal(45), Decimal(-45)) # -
1390 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
1391
Christian Heimes77c02eb2008-02-09 02:18:51 +00001392 def test_nan_comparisons(self):
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001393 # comparisons involving signaling nans signal InvalidOperation
1394
1395 # order comparisons (<, <=, >, >=) involving only quiet nans
1396 # also signal InvalidOperation
1397
1398 # equality comparisons (==, !=) involving only quiet nans
1399 # don't signal, but return False or True respectively.
Stefan Krah1919b7e2012-03-21 18:25:23 +01001400 Decimal = self.decimal.Decimal
1401 InvalidOperation = self.decimal.InvalidOperation
1402 localcontext = self.decimal.localcontext
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001403
Christian Heimes77c02eb2008-02-09 02:18:51 +00001404 n = Decimal('NaN')
1405 s = Decimal('sNaN')
1406 i = Decimal('Inf')
1407 f = Decimal('2')
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001408
1409 qnan_pairs = (n, n), (n, i), (i, n), (n, f), (f, n)
1410 snan_pairs = (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)
1411 order_ops = operator.lt, operator.le, operator.gt, operator.ge
1412 equality_ops = operator.eq, operator.ne
1413
1414 # results when InvalidOperation is not trapped
1415 for x, y in qnan_pairs + snan_pairs:
1416 for op in order_ops + equality_ops:
1417 got = op(x, y)
1418 expected = True if op is operator.ne else False
1419 self.assertIs(expected, got,
1420 "expected {0!r} for operator.{1}({2!r}, {3!r}); "
1421 "got {4!r}".format(
1422 expected, op.__name__, x, y, got))
1423
1424 # repeat the above, but this time trap the InvalidOperation
1425 with localcontext() as ctx:
1426 ctx.traps[InvalidOperation] = 1
1427
1428 for x, y in qnan_pairs:
1429 for op in equality_ops:
1430 got = op(x, y)
1431 expected = True if op is operator.ne else False
1432 self.assertIs(expected, got,
1433 "expected {0!r} for "
1434 "operator.{1}({2!r}, {3!r}); "
1435 "got {4!r}".format(
1436 expected, op.__name__, x, y, got))
1437
1438 for x, y in snan_pairs:
1439 for op in equality_ops:
1440 self.assertRaises(InvalidOperation, operator.eq, x, y)
1441 self.assertRaises(InvalidOperation, operator.ne, x, y)
1442
1443 for x, y in qnan_pairs + snan_pairs:
1444 for op in order_ops:
1445 self.assertRaises(InvalidOperation, op, x, y)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001446
Mark Dickinson84230a12010-02-18 14:49:50 +00001447 def test_copy_sign(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001448 Decimal = self.decimal.Decimal
Mark Dickinson84230a12010-02-18 14:49:50 +00001449
Stefan Krah1919b7e2012-03-21 18:25:23 +01001450 d = Decimal(1).copy_sign(Decimal(-2))
Mark Dickinson84230a12010-02-18 14:49:50 +00001451 self.assertEqual(Decimal(1).copy_sign(-2), d)
1452 self.assertRaises(TypeError, Decimal(1).copy_sign, '-2')
1453
Stefan Krah1919b7e2012-03-21 18:25:23 +01001454class CArithmeticOperatorsTest(ArithmeticOperatorsTest):
1455 decimal = C
1456class PyArithmeticOperatorsTest(ArithmeticOperatorsTest):
1457 decimal = P
1458
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001459# The following are two functions used to test threading in the next class
1460
1461def thfunc1(cls):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001462 Decimal = cls.decimal.Decimal
1463 InvalidOperation = cls.decimal.InvalidOperation
1464 DivisionByZero = cls.decimal.DivisionByZero
1465 Overflow = cls.decimal.Overflow
1466 Underflow = cls.decimal.Underflow
1467 Inexact = cls.decimal.Inexact
1468 getcontext = cls.decimal.getcontext
1469 localcontext = cls.decimal.localcontext
1470
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001471 d1 = Decimal(1)
1472 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +00001473 test1 = d1/d3
Christian Heimesfe337bf2008-03-23 21:54:12 +00001474
Stefan Krah1919b7e2012-03-21 18:25:23 +01001475 cls.finish1.set()
1476 cls.synchro.wait()
1477
1478 test2 = d1/d3
1479 with localcontext() as c2:
1480 cls.assertTrue(c2.flags[Inexact])
1481 cls.assertRaises(DivisionByZero, c2.divide, d1, 0)
1482 cls.assertTrue(c2.flags[DivisionByZero])
1483 with localcontext() as c3:
1484 cls.assertTrue(c3.flags[Inexact])
1485 cls.assertTrue(c3.flags[DivisionByZero])
1486 cls.assertRaises(InvalidOperation, c3.compare, d1, Decimal('sNaN'))
1487 cls.assertTrue(c3.flags[InvalidOperation])
1488 del c3
1489 cls.assertFalse(c2.flags[InvalidOperation])
1490 del c2
1491
1492 cls.assertEqual(test1, Decimal('0.333333333333333333333333'))
1493 cls.assertEqual(test2, Decimal('0.333333333333333333333333'))
1494
1495 c1 = getcontext()
1496 cls.assertTrue(c1.flags[Inexact])
1497 for sig in Overflow, Underflow, DivisionByZero, InvalidOperation:
1498 cls.assertFalse(c1.flags[sig])
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001499 return
1500
1501def thfunc2(cls):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001502 Decimal = cls.decimal.Decimal
1503 InvalidOperation = cls.decimal.InvalidOperation
1504 DivisionByZero = cls.decimal.DivisionByZero
1505 Overflow = cls.decimal.Overflow
1506 Underflow = cls.decimal.Underflow
1507 Inexact = cls.decimal.Inexact
1508 getcontext = cls.decimal.getcontext
1509 localcontext = cls.decimal.localcontext
1510
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001511 d1 = Decimal(1)
1512 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +00001513 test1 = d1/d3
Stefan Krah1919b7e2012-03-21 18:25:23 +01001514
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001515 thiscontext = getcontext()
1516 thiscontext.prec = 18
Christian Heimesfe337bf2008-03-23 21:54:12 +00001517 test2 = d1/d3
Stefan Krah1919b7e2012-03-21 18:25:23 +01001518
1519 with localcontext() as c2:
1520 cls.assertTrue(c2.flags[Inexact])
1521 cls.assertRaises(Overflow, c2.multiply, Decimal('1e425000000'), 999)
1522 cls.assertTrue(c2.flags[Overflow])
1523 with localcontext(thiscontext) as c3:
1524 cls.assertTrue(c3.flags[Inexact])
1525 cls.assertFalse(c3.flags[Overflow])
1526 c3.traps[Underflow] = True
1527 cls.assertRaises(Underflow, c3.divide, Decimal('1e-425000000'), 999)
1528 cls.assertTrue(c3.flags[Underflow])
1529 del c3
1530 cls.assertFalse(c2.flags[Underflow])
1531 cls.assertFalse(c2.traps[Underflow])
1532 del c2
1533
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001534 cls.synchro.set()
1535 cls.finish2.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001536
Stefan Krah1919b7e2012-03-21 18:25:23 +01001537 cls.assertEqual(test1, Decimal('0.333333333333333333333333'))
Christian Heimesfe337bf2008-03-23 21:54:12 +00001538 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Stefan Krah1919b7e2012-03-21 18:25:23 +01001539
1540 cls.assertFalse(thiscontext.traps[Underflow])
1541 cls.assertTrue(thiscontext.flags[Inexact])
1542 for sig in Overflow, Underflow, DivisionByZero, InvalidOperation:
1543 cls.assertFalse(thiscontext.flags[sig])
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001544 return
1545
Stefan Krah1919b7e2012-03-21 18:25:23 +01001546class ThreadingTest(unittest.TestCase):
1547 '''Unit tests for thread local contexts in Decimal.'''
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001548
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001549 # Take care executing this test from IDLE, there's an issue in threading
1550 # that hangs IDLE and I couldn't find it
1551
1552 def test_threading(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001553 DefaultContext = self.decimal.DefaultContext
1554
1555 if self.decimal == C and not self.decimal.HAVE_THREADS:
1556 self.skipTest("compiled without threading")
1557 # Test the "threading isolation" of a Context. Also test changing
1558 # the DefaultContext, which acts as a template for the thread-local
1559 # contexts.
1560 save_prec = DefaultContext.prec
1561 save_emax = DefaultContext.Emax
1562 save_emin = DefaultContext.Emin
1563 DefaultContext.prec = 24
1564 DefaultContext.Emax = 425000000
1565 DefaultContext.Emin = -425000000
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001566
1567 self.synchro = threading.Event()
1568 self.finish1 = threading.Event()
1569 self.finish2 = threading.Event()
1570
1571 th1 = threading.Thread(target=thfunc1, args=(self,))
1572 th2 = threading.Thread(target=thfunc2, args=(self,))
1573
1574 th1.start()
1575 th2.start()
1576
1577 self.finish1.wait()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001578 self.finish2.wait()
Stefan Krah1919b7e2012-03-21 18:25:23 +01001579
1580 for sig in Signals[self.decimal]:
1581 self.assertFalse(DefaultContext.flags[sig])
1582
1583 DefaultContext.prec = save_prec
1584 DefaultContext.Emax = save_emax
1585 DefaultContext.Emin = save_emin
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001586 return
1587
Stefan Krah1919b7e2012-03-21 18:25:23 +01001588@unittest.skipUnless(threading, 'threading required')
1589class CThreadingTest(ThreadingTest):
1590 decimal = C
1591@unittest.skipUnless(threading, 'threading required')
1592class PyThreadingTest(ThreadingTest):
1593 decimal = P
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001594
Stefan Krah1919b7e2012-03-21 18:25:23 +01001595class UsabilityTest(unittest.TestCase):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001596 '''Unit tests for Usability cases of Decimal.'''
1597
1598 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001599
Stefan Krah1919b7e2012-03-21 18:25:23 +01001600 Decimal = self.decimal.Decimal
1601
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001602 da = Decimal('23.42')
1603 db = Decimal('23.42')
1604 dc = Decimal('45')
1605
1606 #two Decimals
Ezio Melotti6607d512010-04-03 14:59:49 +00001607 self.assertGreater(dc, da)
1608 self.assertGreaterEqual(dc, da)
1609 self.assertLess(da, dc)
1610 self.assertLessEqual(da, dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001611 self.assertEqual(da, db)
Ezio Melotti6607d512010-04-03 14:59:49 +00001612 self.assertNotEqual(da, dc)
1613 self.assertLessEqual(da, db)
1614 self.assertGreaterEqual(da, db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001615
1616 #a Decimal and an int
Ezio Melotti6607d512010-04-03 14:59:49 +00001617 self.assertGreater(dc, 23)
1618 self.assertLess(23, dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001619 self.assertEqual(dc, 45)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001620
1621 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001622 self.assertNotEqual(da, 'ugly')
1623 self.assertNotEqual(da, 32.7)
1624 self.assertNotEqual(da, object())
1625 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001626
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001627 # sortable
Guido van Rossumc1f779c2007-07-03 08:25:58 +00001628 a = list(map(Decimal, range(100)))
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001629 b = a[:]
1630 random.shuffle(a)
1631 a.sort()
1632 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001633
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001634 def test_decimal_float_comparison(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001635 Decimal = self.decimal.Decimal
1636
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001637 da = Decimal('0.25')
1638 db = Decimal('3.0')
Ezio Melotti6607d512010-04-03 14:59:49 +00001639 self.assertLess(da, 3.0)
1640 self.assertLessEqual(da, 3.0)
1641 self.assertGreater(db, 0.25)
1642 self.assertGreaterEqual(db, 0.25)
1643 self.assertNotEqual(da, 1.5)
1644 self.assertEqual(da, 0.25)
1645 self.assertGreater(3.0, da)
1646 self.assertGreaterEqual(3.0, da)
1647 self.assertLess(0.25, db)
1648 self.assertLessEqual(0.25, db)
1649 self.assertNotEqual(0.25, db)
1650 self.assertEqual(3.0, db)
1651 self.assertNotEqual(0.1, Decimal('0.1'))
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001652
Stefan Krah1919b7e2012-03-21 18:25:23 +01001653 def test_decimal_complex_comparison(self):
1654 Decimal = self.decimal.Decimal
1655
1656 da = Decimal('0.25')
1657 db = Decimal('3.0')
1658 self.assertNotEqual(da, (1.5+0j))
1659 self.assertNotEqual((1.5+0j), da)
1660 self.assertEqual(da, (0.25+0j))
1661 self.assertEqual((0.25+0j), da)
1662 self.assertEqual((3.0+0j), db)
1663 self.assertEqual(db, (3.0+0j))
1664
1665 self.assertNotEqual(db, (3.0+1j))
1666 self.assertNotEqual((3.0+1j), db)
1667
1668 self.assertIs(db.__lt__(3.0+0j), NotImplemented)
1669 self.assertIs(db.__le__(3.0+0j), NotImplemented)
1670 self.assertIs(db.__gt__(3.0+0j), NotImplemented)
1671 self.assertIs(db.__le__(3.0+0j), NotImplemented)
1672
1673 def test_decimal_fraction_comparison(self):
1674 D = self.decimal.Decimal
1675 F = fractions[self.decimal].Fraction
1676 Context = self.decimal.Context
1677 localcontext = self.decimal.localcontext
1678 InvalidOperation = self.decimal.InvalidOperation
1679
1680
1681 emax = C.MAX_EMAX if C else 999999999
1682 emin = C.MIN_EMIN if C else -999999999
1683 etiny = C.MIN_ETINY if C else -1999999997
1684 c = Context(Emax=emax, Emin=emin)
1685
1686 with localcontext(c):
1687 c.prec = emax
1688 self.assertLess(D(0), F(1,9999999999999999999999999999999999999))
1689 self.assertLess(F(-1,9999999999999999999999999999999999999), D(0))
1690 self.assertLess(F(0,1), D("1e" + str(etiny)))
1691 self.assertLess(D("-1e" + str(etiny)), F(0,1))
1692 self.assertLess(F(0,9999999999999999999999999), D("1e" + str(etiny)))
1693 self.assertLess(D("-1e" + str(etiny)), F(0,9999999999999999999999999))
1694
1695 self.assertEqual(D("0.1"), F(1,10))
1696 self.assertEqual(F(1,10), D("0.1"))
1697
1698 c.prec = 300
1699 self.assertNotEqual(D(1)/3, F(1,3))
1700 self.assertNotEqual(F(1,3), D(1)/3)
1701
1702 self.assertLessEqual(F(120984237, 9999999999), D("9e" + str(emax)))
1703 self.assertGreaterEqual(D("9e" + str(emax)), F(120984237, 9999999999))
1704
1705 self.assertGreater(D('inf'), F(99999999999,123))
1706 self.assertGreater(D('inf'), F(-99999999999,123))
1707 self.assertLess(D('-inf'), F(99999999999,123))
1708 self.assertLess(D('-inf'), F(-99999999999,123))
1709
1710 self.assertRaises(InvalidOperation, D('nan').__gt__, F(-9,123))
1711 self.assertIs(NotImplemented, F(-9,123).__lt__(D('nan')))
1712 self.assertNotEqual(D('nan'), F(-9,123))
1713 self.assertNotEqual(F(-9,123), D('nan'))
1714
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001715 def test_copy_and_deepcopy_methods(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001716 Decimal = self.decimal.Decimal
1717
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001718 d = Decimal('43.24')
1719 c = copy.copy(d)
1720 self.assertEqual(id(c), id(d))
1721 dc = copy.deepcopy(d)
1722 self.assertEqual(id(dc), id(d))
1723
1724 def test_hash_method(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001725
1726 Decimal = self.decimal.Decimal
1727 localcontext = self.decimal.localcontext
1728
Stefan Krahdc817b22010-11-17 11:16:34 +00001729 def hashit(d):
1730 a = hash(d)
1731 b = d.__hash__()
1732 self.assertEqual(a, b)
1733 return a
1734
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001735 #just that it's hashable
Stefan Krahdc817b22010-11-17 11:16:34 +00001736 hashit(Decimal(23))
1737 hashit(Decimal('Infinity'))
1738 hashit(Decimal('-Infinity'))
1739 hashit(Decimal('nan123'))
1740 hashit(Decimal('-NaN'))
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001741
1742 test_values = [Decimal(sign*(2**m + n))
1743 for m in [0, 14, 15, 16, 17, 30, 31,
Stefan Krahdc817b22010-11-17 11:16:34 +00001744 32, 33, 61, 62, 63, 64, 65, 66]
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001745 for n in range(-10, 10)
1746 for sign in [-1, 1]]
1747 test_values.extend([
Stefan Krahdc817b22010-11-17 11:16:34 +00001748 Decimal("-1"), # ==> -2
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001749 Decimal("-0"), # zeros
1750 Decimal("0.00"),
1751 Decimal("-0.000"),
1752 Decimal("0E10"),
1753 Decimal("-0E12"),
1754 Decimal("10.0"), # negative exponent
1755 Decimal("-23.00000"),
1756 Decimal("1230E100"), # positive exponent
1757 Decimal("-4.5678E50"),
1758 # a value for which hash(n) != hash(n % (2**64-1))
1759 # in Python pre-2.6
1760 Decimal(2**64 + 2**32 - 1),
1761 # selection of values which fail with the old (before
1762 # version 2.6) long.__hash__
1763 Decimal("1.634E100"),
1764 Decimal("90.697E100"),
1765 Decimal("188.83E100"),
1766 Decimal("1652.9E100"),
1767 Decimal("56531E100"),
1768 ])
1769
1770 # check that hash(d) == hash(int(d)) for integral values
1771 for value in test_values:
Stefan Krahdc817b22010-11-17 11:16:34 +00001772 self.assertEqual(hashit(value), hashit(int(value)))
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001773
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001774 #the same hash that to an int
Stefan Krahdc817b22010-11-17 11:16:34 +00001775 self.assertEqual(hashit(Decimal(23)), hashit(23))
Raymond Hettingerd325c4b2010-11-21 04:08:28 +00001776 self.assertRaises(TypeError, hash, Decimal('sNaN'))
Stefan Krahdc817b22010-11-17 11:16:34 +00001777 self.assertTrue(hashit(Decimal('Inf')))
1778 self.assertTrue(hashit(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001779
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001780 # check that the hashes of a Decimal float match when they
1781 # represent exactly the same values
1782 test_strings = ['inf', '-Inf', '0.0', '-.0e1',
1783 '34.0', '2.5', '112390.625', '-0.515625']
1784 for s in test_strings:
1785 f = float(s)
1786 d = Decimal(s)
Stefan Krahdc817b22010-11-17 11:16:34 +00001787 self.assertEqual(hashit(f), hashit(d))
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001788
Stefan Krah1919b7e2012-03-21 18:25:23 +01001789 with localcontext() as c:
1790 # check that the value of the hash doesn't depend on the
1791 # current context (issue #1757)
1792 x = Decimal("123456789.1")
Christian Heimes2380ac72008-01-09 00:17:24 +00001793
Stefan Krah1919b7e2012-03-21 18:25:23 +01001794 c.prec = 6
1795 h1 = hashit(x)
1796 c.prec = 10
1797 h2 = hashit(x)
1798 c.prec = 16
1799 h3 = hashit(x)
Christian Heimes2380ac72008-01-09 00:17:24 +00001800
Stefan Krah1919b7e2012-03-21 18:25:23 +01001801 self.assertEqual(h1, h2)
1802 self.assertEqual(h1, h3)
1803
1804 c.prec = 10000
1805 x = 1100 ** 1248
1806 self.assertEqual(hashit(Decimal(x)), hashit(x))
Christian Heimes2380ac72008-01-09 00:17:24 +00001807
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001808 def test_min_and_max_methods(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001809 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001810
1811 d1 = Decimal('15.32')
1812 d2 = Decimal('28.5')
1813 l1 = 15
1814 l2 = 28
1815
1816 #between Decimals
Ezio Melotti6607d512010-04-03 14:59:49 +00001817 self.assertIs(min(d1,d2), d1)
1818 self.assertIs(min(d2,d1), d1)
1819 self.assertIs(max(d1,d2), d2)
1820 self.assertIs(max(d2,d1), d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001821
1822 #between Decimal and long
Ezio Melotti6607d512010-04-03 14:59:49 +00001823 self.assertIs(min(d1,l2), d1)
1824 self.assertIs(min(l2,d1), d1)
1825 self.assertIs(max(l1,d2), d2)
1826 self.assertIs(max(d2,l1), d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001827
1828 def test_as_nonzero(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001829 Decimal = self.decimal.Decimal
1830
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001831 #as false
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001832 self.assertFalse(Decimal(0))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001833 #as true
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001834 self.assertTrue(Decimal('0.372'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001835
1836 def test_tostring_methods(self):
1837 #Test str and repr methods.
Stefan Krah1919b7e2012-03-21 18:25:23 +01001838 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001839
1840 d = Decimal('15.32')
1841 self.assertEqual(str(d), '15.32') # str
Christian Heimes68f5fbe2008-02-14 08:27:37 +00001842 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001843
1844 def test_tonum_methods(self):
Mark Dickinson5c2db372009-12-05 20:28:34 +00001845 #Test float and int methods.
Stefan Krah1919b7e2012-03-21 18:25:23 +01001846 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001847
1848 d1 = Decimal('66')
1849 d2 = Decimal('15.32')
1850
1851 #int
1852 self.assertEqual(int(d1), 66)
1853 self.assertEqual(int(d2), 15)
1854
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001855 #float
1856 self.assertEqual(float(d1), 66)
1857 self.assertEqual(float(d2), 15.32)
1858
Mark Dickinsonb27406c2008-05-09 13:42:33 +00001859 #floor
1860 test_pairs = [
1861 ('123.00', 123),
1862 ('3.2', 3),
1863 ('3.54', 3),
1864 ('3.899', 3),
1865 ('-2.3', -3),
1866 ('-11.0', -11),
1867 ('0.0', 0),
1868 ('-0E3', 0),
Stefan Krah1919b7e2012-03-21 18:25:23 +01001869 ('89891211712379812736.1', 89891211712379812736),
Mark Dickinsonb27406c2008-05-09 13:42:33 +00001870 ]
1871 for d, i in test_pairs:
1872 self.assertEqual(math.floor(Decimal(d)), i)
1873 self.assertRaises(ValueError, math.floor, Decimal('-NaN'))
1874 self.assertRaises(ValueError, math.floor, Decimal('sNaN'))
1875 self.assertRaises(ValueError, math.floor, Decimal('NaN123'))
1876 self.assertRaises(OverflowError, math.floor, Decimal('Inf'))
1877 self.assertRaises(OverflowError, math.floor, Decimal('-Inf'))
1878
1879 #ceiling
1880 test_pairs = [
1881 ('123.00', 123),
1882 ('3.2', 4),
1883 ('3.54', 4),
1884 ('3.899', 4),
1885 ('-2.3', -2),
1886 ('-11.0', -11),
1887 ('0.0', 0),
1888 ('-0E3', 0),
Stefan Krah1919b7e2012-03-21 18:25:23 +01001889 ('89891211712379812736.1', 89891211712379812737),
Mark Dickinsonb27406c2008-05-09 13:42:33 +00001890 ]
1891 for d, i in test_pairs:
1892 self.assertEqual(math.ceil(Decimal(d)), i)
1893 self.assertRaises(ValueError, math.ceil, Decimal('-NaN'))
1894 self.assertRaises(ValueError, math.ceil, Decimal('sNaN'))
1895 self.assertRaises(ValueError, math.ceil, Decimal('NaN123'))
1896 self.assertRaises(OverflowError, math.ceil, Decimal('Inf'))
1897 self.assertRaises(OverflowError, math.ceil, Decimal('-Inf'))
1898
1899 #round, single argument
1900 test_pairs = [
1901 ('123.00', 123),
1902 ('3.2', 3),
1903 ('3.54', 4),
1904 ('3.899', 4),
1905 ('-2.3', -2),
1906 ('-11.0', -11),
1907 ('0.0', 0),
1908 ('-0E3', 0),
1909 ('-3.5', -4),
1910 ('-2.5', -2),
1911 ('-1.5', -2),
1912 ('-0.5', 0),
1913 ('0.5', 0),
1914 ('1.5', 2),
1915 ('2.5', 2),
1916 ('3.5', 4),
1917 ]
1918 for d, i in test_pairs:
1919 self.assertEqual(round(Decimal(d)), i)
1920 self.assertRaises(ValueError, round, Decimal('-NaN'))
1921 self.assertRaises(ValueError, round, Decimal('sNaN'))
1922 self.assertRaises(ValueError, round, Decimal('NaN123'))
1923 self.assertRaises(OverflowError, round, Decimal('Inf'))
1924 self.assertRaises(OverflowError, round, Decimal('-Inf'))
1925
1926 #round, two arguments; this is essentially equivalent
1927 #to quantize, which is already extensively tested
1928 test_triples = [
1929 ('123.456', -4, '0E+4'),
1930 ('123.456', -3, '0E+3'),
1931 ('123.456', -2, '1E+2'),
1932 ('123.456', -1, '1.2E+2'),
1933 ('123.456', 0, '123'),
1934 ('123.456', 1, '123.5'),
1935 ('123.456', 2, '123.46'),
1936 ('123.456', 3, '123.456'),
1937 ('123.456', 4, '123.4560'),
1938 ('123.455', 2, '123.46'),
1939 ('123.445', 2, '123.44'),
1940 ('Inf', 4, 'NaN'),
1941 ('-Inf', -23, 'NaN'),
1942 ('sNaN314', 3, 'NaN314'),
1943 ]
1944 for d, n, r in test_triples:
1945 self.assertEqual(str(round(Decimal(d), n)), r)
1946
Mark Dickinsonfc33d4c2012-08-24 18:53:10 +01001947 def test_nan_to_float(self):
1948 # Test conversions of decimal NANs to float.
1949 # See http://bugs.python.org/issue15544
1950 Decimal = self.decimal.Decimal
1951 for s in ('nan', 'nan1234', '-nan', '-nan2468'):
1952 f = float(Decimal(s))
1953 self.assertTrue(math.isnan(f))
1954 sign = math.copysign(1.0, f)
1955 self.assertEqual(sign, -1.0 if s.startswith('-') else 1.0)
1956
1957 def test_snan_to_float(self):
1958 Decimal = self.decimal.Decimal
1959 for s in ('snan', '-snan', 'snan1357', '-snan1234'):
1960 d = Decimal(s)
1961 self.assertRaises(ValueError, float, d)
1962
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001963 def test_eval_round_trip(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001964 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001965
1966 #with zero
1967 d = Decimal( (0, (0,), 0) )
1968 self.assertEqual(d, eval(repr(d)))
1969
1970 #int
1971 d = Decimal( (1, (4, 5), 0) )
1972 self.assertEqual(d, eval(repr(d)))
1973
1974 #float
1975 d = Decimal( (0, (4, 5, 3, 4), -2) )
1976 self.assertEqual(d, eval(repr(d)))
1977
1978 #weird
1979 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1980 self.assertEqual(d, eval(repr(d)))
1981
1982 def test_as_tuple(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001983 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001984
1985 #with zero
1986 d = Decimal(0)
1987 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
1988
1989 #int
1990 d = Decimal(-45)
1991 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
1992
1993 #complicated string
1994 d = Decimal("-4.34913534E-17")
1995 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
1996
Stefan Krah76e12172012-09-10 19:34:58 +02001997 # The '0' coefficient is implementation specific to decimal.py.
1998 # It has no meaning in the C-version and is ignored there.
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001999 d = Decimal("Infinity")
2000 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
2001
Guido van Rossum8ce8a782007-11-01 19:42:39 +00002002 #leading zeros in coefficient should be stripped
2003 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
2004 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
2005 d = Decimal( (1, (0, 0, 0), 37) )
2006 self.assertEqual(d.as_tuple(), (1, (0,), 37))
2007 d = Decimal( (1, (), 37) )
2008 self.assertEqual(d.as_tuple(), (1, (0,), 37))
2009
2010 #leading zeros in NaN diagnostic info should be stripped
2011 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
2012 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
2013 d = Decimal( (1, (0, 0, 0), 'N') )
2014 self.assertEqual(d.as_tuple(), (1, (), 'N') )
2015 d = Decimal( (1, (), 'n') )
2016 self.assertEqual(d.as_tuple(), (1, (), 'n') )
2017
Stefan Krah76e12172012-09-10 19:34:58 +02002018 # For infinities, decimal.py has always silently accepted any
2019 # coefficient tuple.
2020 d = Decimal( (0, (0,), 'F') )
2021 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
2022 d = Decimal( (0, (4, 5, 3, 4), 'F') )
2023 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
2024 d = Decimal( (1, (0, 2, 7, 1), 'F') )
2025 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
Guido van Rossum8ce8a782007-11-01 19:42:39 +00002026
Stefan Krah1919b7e2012-03-21 18:25:23 +01002027 def test_subclassing(self):
2028 # Different behaviours when subclassing Decimal
2029 Decimal = self.decimal.Decimal
2030
2031 class MyDecimal(Decimal):
2032 pass
2033
2034 d1 = MyDecimal(1)
2035 d2 = MyDecimal(2)
2036 d = d1 + d2
2037 self.assertIs(type(d), Decimal)
2038
2039 d = d1.max(d2)
2040 self.assertIs(type(d), Decimal)
2041
2042 d = copy.copy(d1)
2043 self.assertIs(type(d), MyDecimal)
2044 self.assertEqual(d, d1)
2045
2046 d = copy.deepcopy(d1)
2047 self.assertIs(type(d), MyDecimal)
2048 self.assertEqual(d, d1)
2049
2050 def test_implicit_context(self):
2051 Decimal = self.decimal.Decimal
2052 getcontext = self.decimal.getcontext
2053
2054 # Check results when context given implicitly. (Issue 2478)
2055 c = getcontext()
2056 self.assertEqual(str(Decimal(0).sqrt()),
2057 str(c.sqrt(Decimal(0))))
2058
2059 def test_conversions_from_int(self):
2060 # Check that methods taking a second Decimal argument will
2061 # always accept an integer in place of a Decimal.
2062 Decimal = self.decimal.Decimal
2063
2064 self.assertEqual(Decimal(4).compare(3),
2065 Decimal(4).compare(Decimal(3)))
2066 self.assertEqual(Decimal(4).compare_signal(3),
2067 Decimal(4).compare_signal(Decimal(3)))
2068 self.assertEqual(Decimal(4).compare_total(3),
2069 Decimal(4).compare_total(Decimal(3)))
2070 self.assertEqual(Decimal(4).compare_total_mag(3),
2071 Decimal(4).compare_total_mag(Decimal(3)))
2072 self.assertEqual(Decimal(10101).logical_and(1001),
2073 Decimal(10101).logical_and(Decimal(1001)))
2074 self.assertEqual(Decimal(10101).logical_or(1001),
2075 Decimal(10101).logical_or(Decimal(1001)))
2076 self.assertEqual(Decimal(10101).logical_xor(1001),
2077 Decimal(10101).logical_xor(Decimal(1001)))
2078 self.assertEqual(Decimal(567).max(123),
2079 Decimal(567).max(Decimal(123)))
2080 self.assertEqual(Decimal(567).max_mag(123),
2081 Decimal(567).max_mag(Decimal(123)))
2082 self.assertEqual(Decimal(567).min(123),
2083 Decimal(567).min(Decimal(123)))
2084 self.assertEqual(Decimal(567).min_mag(123),
2085 Decimal(567).min_mag(Decimal(123)))
2086 self.assertEqual(Decimal(567).next_toward(123),
2087 Decimal(567).next_toward(Decimal(123)))
2088 self.assertEqual(Decimal(1234).quantize(100),
2089 Decimal(1234).quantize(Decimal(100)))
2090 self.assertEqual(Decimal(768).remainder_near(1234),
2091 Decimal(768).remainder_near(Decimal(1234)))
2092 self.assertEqual(Decimal(123).rotate(1),
2093 Decimal(123).rotate(Decimal(1)))
2094 self.assertEqual(Decimal(1234).same_quantum(1000),
2095 Decimal(1234).same_quantum(Decimal(1000)))
2096 self.assertEqual(Decimal('9.123').scaleb(-100),
2097 Decimal('9.123').scaleb(Decimal(-100)))
2098 self.assertEqual(Decimal(456).shift(-1),
2099 Decimal(456).shift(Decimal(-1)))
2100
2101 self.assertEqual(Decimal(-12).fma(Decimal(45), 67),
2102 Decimal(-12).fma(Decimal(45), Decimal(67)))
2103 self.assertEqual(Decimal(-12).fma(45, 67),
2104 Decimal(-12).fma(Decimal(45), Decimal(67)))
2105 self.assertEqual(Decimal(-12).fma(45, Decimal(67)),
2106 Decimal(-12).fma(Decimal(45), Decimal(67)))
2107
2108class CUsabilityTest(UsabilityTest):
2109 decimal = C
2110class PyUsabilityTest(UsabilityTest):
2111 decimal = P
2112
2113class PythonAPItests(unittest.TestCase):
2114
2115 def test_abc(self):
2116 Decimal = self.decimal.Decimal
2117
2118 self.assertTrue(issubclass(Decimal, numbers.Number))
2119 self.assertFalse(issubclass(Decimal, numbers.Real))
2120 self.assertIsInstance(Decimal(0), numbers.Number)
2121 self.assertNotIsInstance(Decimal(0), numbers.Real)
2122
2123 def test_pickle(self):
2124 Decimal = self.decimal.Decimal
2125
2126 savedecimal = sys.modules['decimal']
2127
2128 # Round trip
2129 sys.modules['decimal'] = self.decimal
2130 d = Decimal('-3.141590000')
2131 p = pickle.dumps(d)
2132 e = pickle.loads(p)
2133 self.assertEqual(d, e)
2134
2135 if C:
2136 # Test interchangeability
2137 x = C.Decimal('-3.123e81723')
2138 y = P.Decimal('-3.123e81723')
2139
2140 sys.modules['decimal'] = C
2141 sx = pickle.dumps(x)
2142 sys.modules['decimal'] = P
2143 r = pickle.loads(sx)
2144 self.assertIsInstance(r, P.Decimal)
2145 self.assertEqual(r, y)
2146
2147 sys.modules['decimal'] = P
2148 sy = pickle.dumps(y)
2149 sys.modules['decimal'] = C
2150 r = pickle.loads(sy)
2151 self.assertIsInstance(r, C.Decimal)
2152 self.assertEqual(r, x)
2153
2154 sys.modules['decimal'] = savedecimal
2155
2156 def test_int(self):
2157 Decimal = self.decimal.Decimal
2158 ROUND_DOWN = self.decimal.ROUND_DOWN
2159
2160 for x in range(-250, 250):
2161 s = '%0.2f' % (x / 100.0)
2162 # should work the same as for floats
2163 self.assertEqual(int(Decimal(s)), int(float(s)))
2164 # should work the same as to_integral in the ROUND_DOWN mode
2165 d = Decimal(s)
2166 r = d.to_integral(ROUND_DOWN)
2167 self.assertEqual(Decimal(int(d)), r)
2168
2169 self.assertRaises(ValueError, int, Decimal('-nan'))
2170 self.assertRaises(ValueError, int, Decimal('snan'))
2171 self.assertRaises(OverflowError, int, Decimal('inf'))
2172 self.assertRaises(OverflowError, int, Decimal('-inf'))
2173
2174 def test_trunc(self):
2175 Decimal = self.decimal.Decimal
2176 ROUND_DOWN = self.decimal.ROUND_DOWN
2177
2178 for x in range(-250, 250):
2179 s = '%0.2f' % (x / 100.0)
2180 # should work the same as for floats
2181 self.assertEqual(int(Decimal(s)), int(float(s)))
2182 # should work the same as to_integral in the ROUND_DOWN mode
2183 d = Decimal(s)
2184 r = d.to_integral(ROUND_DOWN)
2185 self.assertEqual(Decimal(math.trunc(d)), r)
2186
2187 def test_from_float(self):
2188
2189 Decimal = self.decimal.Decimal
2190
2191 class MyDecimal(Decimal):
2192 pass
2193
2194 self.assertTrue(issubclass(MyDecimal, Decimal))
2195
2196 r = MyDecimal.from_float(0.1)
2197 self.assertEqual(type(r), MyDecimal)
2198 self.assertEqual(str(r),
2199 '0.1000000000000000055511151231257827021181583404541015625')
2200 bigint = 12345678901234567890123456789
2201 self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
2202 self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan())
2203 self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite())
2204 self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite())
2205 self.assertEqual(str(MyDecimal.from_float(float('nan'))),
2206 str(Decimal('NaN')))
2207 self.assertEqual(str(MyDecimal.from_float(float('inf'))),
2208 str(Decimal('Infinity')))
2209 self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
2210 str(Decimal('-Infinity')))
2211 self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
2212 for i in range(200):
2213 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
2214 self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
2215
2216 def test_create_decimal_from_float(self):
2217 Decimal = self.decimal.Decimal
2218 Context = self.decimal.Context
2219 ROUND_DOWN = self.decimal.ROUND_DOWN
2220 ROUND_UP = self.decimal.ROUND_UP
2221 Inexact = self.decimal.Inexact
2222
2223 context = Context(prec=5, rounding=ROUND_DOWN)
2224 self.assertEqual(
2225 context.create_decimal_from_float(math.pi),
2226 Decimal('3.1415')
2227 )
2228 context = Context(prec=5, rounding=ROUND_UP)
2229 self.assertEqual(
2230 context.create_decimal_from_float(math.pi),
2231 Decimal('3.1416')
2232 )
2233 context = Context(prec=5, traps=[Inexact])
2234 self.assertRaises(
2235 Inexact,
2236 context.create_decimal_from_float,
2237 math.pi
2238 )
2239 self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
2240 "Decimal('-0')")
2241 self.assertEqual(repr(context.create_decimal_from_float(1.0)),
2242 "Decimal('1')")
2243 self.assertEqual(repr(context.create_decimal_from_float(10)),
2244 "Decimal('10')")
2245
2246 def test_quantize(self):
2247 Decimal = self.decimal.Decimal
2248 Context = self.decimal.Context
2249 InvalidOperation = self.decimal.InvalidOperation
2250 ROUND_DOWN = self.decimal.ROUND_DOWN
2251
2252 c = Context(Emax=99999, Emin=-99999)
2253 self.assertEqual(
2254 Decimal('7.335').quantize(Decimal('.01')),
2255 Decimal('7.34')
2256 )
2257 self.assertEqual(
2258 Decimal('7.335').quantize(Decimal('.01'), rounding=ROUND_DOWN),
2259 Decimal('7.33')
2260 )
2261 self.assertRaises(
2262 InvalidOperation,
2263 Decimal("10e99999").quantize, Decimal('1e100000'), context=c
2264 )
2265
2266 c = Context()
2267 d = Decimal("0.871831e800")
2268 x = d.quantize(context=c, exp=Decimal("1e797"), rounding=ROUND_DOWN)
2269 self.assertEqual(x, Decimal('8.71E+799'))
2270
2271 def test_complex(self):
2272 Decimal = self.decimal.Decimal
2273
2274 x = Decimal("9.8182731e181273")
2275 self.assertEqual(x.real, x)
2276 self.assertEqual(x.imag, 0)
2277 self.assertEqual(x.conjugate(), x)
2278
2279 x = Decimal("1")
2280 self.assertEqual(complex(x), complex(float(1)))
2281
2282 self.assertRaises(AttributeError, setattr, x, 'real', 100)
2283 self.assertRaises(AttributeError, setattr, x, 'imag', 100)
2284 self.assertRaises(AttributeError, setattr, x, 'conjugate', 100)
2285 self.assertRaises(AttributeError, setattr, x, '__complex__', 100)
2286
2287 def test_named_parameters(self):
2288 D = self.decimal.Decimal
2289 Context = self.decimal.Context
2290 localcontext = self.decimal.localcontext
2291 InvalidOperation = self.decimal.InvalidOperation
2292 Overflow = self.decimal.Overflow
2293
2294 xc = Context()
2295 xc.prec = 1
2296 xc.Emax = 1
2297 xc.Emin = -1
2298
2299 with localcontext() as c:
2300 c.clear_flags()
2301
2302 self.assertEqual(D(9, xc), 9)
2303 self.assertEqual(D(9, context=xc), 9)
2304 self.assertEqual(D(context=xc, value=9), 9)
2305 self.assertEqual(D(context=xc), 0)
2306 xc.clear_flags()
2307 self.assertRaises(InvalidOperation, D, "xyz", context=xc)
2308 self.assertTrue(xc.flags[InvalidOperation])
2309 self.assertFalse(c.flags[InvalidOperation])
2310
2311 xc.clear_flags()
2312 self.assertEqual(D(2).exp(context=xc), 7)
2313 self.assertRaises(Overflow, D(8).exp, context=xc)
2314 self.assertTrue(xc.flags[Overflow])
2315 self.assertFalse(c.flags[Overflow])
2316
2317 xc.clear_flags()
2318 self.assertEqual(D(2).ln(context=xc), D('0.7'))
2319 self.assertRaises(InvalidOperation, D(-1).ln, context=xc)
2320 self.assertTrue(xc.flags[InvalidOperation])
2321 self.assertFalse(c.flags[InvalidOperation])
2322
2323 self.assertEqual(D(0).log10(context=xc), D('-inf'))
2324 self.assertEqual(D(-1).next_minus(context=xc), -2)
2325 self.assertEqual(D(-1).next_plus(context=xc), D('-0.9'))
2326 self.assertEqual(D("9.73").normalize(context=xc), D('1E+1'))
2327 self.assertEqual(D("9999").to_integral(context=xc), 9999)
2328 self.assertEqual(D("-2000").to_integral_exact(context=xc), -2000)
2329 self.assertEqual(D("123").to_integral_value(context=xc), 123)
2330 self.assertEqual(D("0.0625").sqrt(context=xc), D('0.2'))
2331
2332 self.assertEqual(D("0.0625").compare(context=xc, other=3), -1)
2333 xc.clear_flags()
2334 self.assertRaises(InvalidOperation,
2335 D("0").compare_signal, D('nan'), context=xc)
2336 self.assertTrue(xc.flags[InvalidOperation])
2337 self.assertFalse(c.flags[InvalidOperation])
2338 self.assertEqual(D("0.01").max(D('0.0101'), context=xc), D('0.0'))
2339 self.assertEqual(D("0.01").max(D('0.0101'), context=xc), D('0.0'))
2340 self.assertEqual(D("0.2").max_mag(D('-0.3'), context=xc),
2341 D('-0.3'))
2342 self.assertEqual(D("0.02").min(D('-0.03'), context=xc), D('-0.0'))
2343 self.assertEqual(D("0.02").min_mag(D('-0.03'), context=xc),
2344 D('0.0'))
2345 self.assertEqual(D("0.2").next_toward(D('-1'), context=xc), D('0.1'))
2346 xc.clear_flags()
2347 self.assertRaises(InvalidOperation,
2348 D("0.2").quantize, D('1e10'), context=xc)
2349 self.assertTrue(xc.flags[InvalidOperation])
2350 self.assertFalse(c.flags[InvalidOperation])
2351 self.assertEqual(D("9.99").remainder_near(D('1.5'), context=xc),
2352 D('-0.5'))
2353
2354 self.assertEqual(D("9.9").fma(third=D('0.9'), context=xc, other=7),
2355 D('7E+1'))
2356
2357 self.assertRaises(TypeError, D(1).is_canonical, context=xc)
2358 self.assertRaises(TypeError, D(1).is_finite, context=xc)
2359 self.assertRaises(TypeError, D(1).is_infinite, context=xc)
2360 self.assertRaises(TypeError, D(1).is_nan, context=xc)
2361 self.assertRaises(TypeError, D(1).is_qnan, context=xc)
2362 self.assertRaises(TypeError, D(1).is_snan, context=xc)
2363 self.assertRaises(TypeError, D(1).is_signed, context=xc)
2364 self.assertRaises(TypeError, D(1).is_zero, context=xc)
2365
2366 self.assertFalse(D("0.01").is_normal(context=xc))
2367 self.assertTrue(D("0.01").is_subnormal(context=xc))
2368
2369 self.assertRaises(TypeError, D(1).adjusted, context=xc)
2370 self.assertRaises(TypeError, D(1).conjugate, context=xc)
2371 self.assertRaises(TypeError, D(1).radix, context=xc)
2372
2373 self.assertEqual(D(-111).logb(context=xc), 2)
2374 self.assertEqual(D(0).logical_invert(context=xc), 1)
2375 self.assertEqual(D('0.01').number_class(context=xc), '+Subnormal')
2376 self.assertEqual(D('0.21').to_eng_string(context=xc), '0.21')
2377
2378 self.assertEqual(D('11').logical_and(D('10'), context=xc), 0)
2379 self.assertEqual(D('11').logical_or(D('10'), context=xc), 1)
2380 self.assertEqual(D('01').logical_xor(D('10'), context=xc), 1)
2381 self.assertEqual(D('23').rotate(1, context=xc), 3)
2382 self.assertEqual(D('23').rotate(1, context=xc), 3)
2383 xc.clear_flags()
2384 self.assertRaises(Overflow,
2385 D('23').scaleb, 1, context=xc)
2386 self.assertTrue(xc.flags[Overflow])
2387 self.assertFalse(c.flags[Overflow])
2388 self.assertEqual(D('23').shift(-1, context=xc), 0)
2389
2390 self.assertRaises(TypeError, D.from_float, 1.1, context=xc)
2391 self.assertRaises(TypeError, D(0).as_tuple, context=xc)
2392
2393 if (self.decimal == C):
2394 self.assertRaises(TypeError, D(1).canonical, context=xc)
2395 self.assertEqual(D("-1").copy_abs(context=xc), 1)
2396 self.assertEqual(D("1").copy_negate(context=xc), -1)
2397 else:
2398 self.assertEqual(D(1).canonical(context=xc), 1)
2399 self.assertRaises(TypeError, D("-1").copy_abs, context=xc)
2400 self.assertRaises(TypeError, D("-1").copy_negate, context=xc)
2401
Stefan Krahb6405ef2012-03-23 14:46:48 +01002402 def test_exception_hierarchy(self):
2403
2404 decimal = self.decimal
2405 DecimalException = decimal.DecimalException
2406 InvalidOperation = decimal.InvalidOperation
2407 FloatOperation = decimal.FloatOperation
2408 DivisionByZero = decimal.DivisionByZero
2409 Overflow = decimal.Overflow
2410 Underflow = decimal.Underflow
2411 Subnormal = decimal.Subnormal
2412 Inexact = decimal.Inexact
2413 Rounded = decimal.Rounded
2414 Clamped = decimal.Clamped
2415
2416 self.assertTrue(issubclass(DecimalException, ArithmeticError))
2417
2418 self.assertTrue(issubclass(InvalidOperation, DecimalException))
2419 self.assertTrue(issubclass(FloatOperation, DecimalException))
2420 self.assertTrue(issubclass(FloatOperation, TypeError))
2421 self.assertTrue(issubclass(DivisionByZero, DecimalException))
2422 self.assertTrue(issubclass(DivisionByZero, ZeroDivisionError))
2423 self.assertTrue(issubclass(Overflow, Rounded))
2424 self.assertTrue(issubclass(Overflow, Inexact))
2425 self.assertTrue(issubclass(Overflow, DecimalException))
2426 self.assertTrue(issubclass(Underflow, Inexact))
2427 self.assertTrue(issubclass(Underflow, Rounded))
2428 self.assertTrue(issubclass(Underflow, Subnormal))
2429 self.assertTrue(issubclass(Underflow, DecimalException))
2430
2431 self.assertTrue(issubclass(Subnormal, DecimalException))
2432 self.assertTrue(issubclass(Inexact, DecimalException))
2433 self.assertTrue(issubclass(Rounded, DecimalException))
2434 self.assertTrue(issubclass(Clamped, DecimalException))
2435
2436 self.assertTrue(issubclass(decimal.ConversionSyntax, InvalidOperation))
2437 self.assertTrue(issubclass(decimal.DivisionImpossible, InvalidOperation))
2438 self.assertTrue(issubclass(decimal.DivisionUndefined, InvalidOperation))
2439 self.assertTrue(issubclass(decimal.DivisionUndefined, ZeroDivisionError))
2440 self.assertTrue(issubclass(decimal.InvalidContext, InvalidOperation))
2441
Stefan Krah1919b7e2012-03-21 18:25:23 +01002442class CPythonAPItests(PythonAPItests):
2443 decimal = C
2444class PyPythonAPItests(PythonAPItests):
2445 decimal = P
2446
2447class ContextAPItests(unittest.TestCase):
2448
2449 def test_pickle(self):
2450
2451 Context = self.decimal.Context
2452
2453 savedecimal = sys.modules['decimal']
2454
2455 # Round trip
2456 sys.modules['decimal'] = self.decimal
2457 c = Context()
2458 e = pickle.loads(pickle.dumps(c))
2459
2460 self.assertEqual(c.prec, e.prec)
2461 self.assertEqual(c.Emin, e.Emin)
2462 self.assertEqual(c.Emax, e.Emax)
2463 self.assertEqual(c.rounding, e.rounding)
2464 self.assertEqual(c.capitals, e.capitals)
2465 self.assertEqual(c.clamp, e.clamp)
2466 self.assertEqual(c.flags, e.flags)
2467 self.assertEqual(c.traps, e.traps)
2468
2469 # Test interchangeability
2470 combinations = [(C, P), (P, C)] if C else [(P, P)]
2471 for dumper, loader in combinations:
2472 for ri, _ in enumerate(RoundingModes[dumper]):
2473 for fi, _ in enumerate(OrderedSignals[dumper]):
2474 for ti, _ in enumerate(OrderedSignals[dumper]):
2475
2476 prec = random.randrange(1, 100)
2477 emin = random.randrange(-100, 0)
2478 emax = random.randrange(1, 100)
2479 caps = random.randrange(2)
2480 clamp = random.randrange(2)
2481
2482 # One module dumps
2483 sys.modules['decimal'] = dumper
2484 c = dumper.Context(
2485 prec=prec, Emin=emin, Emax=emax,
2486 rounding=RoundingModes[dumper][ri],
2487 capitals=caps, clamp=clamp,
2488 flags=OrderedSignals[dumper][:fi],
2489 traps=OrderedSignals[dumper][:ti]
2490 )
2491 s = pickle.dumps(c)
2492
2493 # The other module loads
2494 sys.modules['decimal'] = loader
2495 d = pickle.loads(s)
2496 self.assertIsInstance(d, loader.Context)
2497
2498 self.assertEqual(d.prec, prec)
2499 self.assertEqual(d.Emin, emin)
2500 self.assertEqual(d.Emax, emax)
2501 self.assertEqual(d.rounding, RoundingModes[loader][ri])
2502 self.assertEqual(d.capitals, caps)
2503 self.assertEqual(d.clamp, clamp)
2504 assert_signals(self, d, 'flags', OrderedSignals[loader][:fi])
2505 assert_signals(self, d, 'traps', OrderedSignals[loader][:ti])
2506
2507 sys.modules['decimal'] = savedecimal
2508
2509 def test_equality_with_other_types(self):
2510 Decimal = self.decimal.Decimal
2511
2512 self.assertIn(Decimal(10), ['a', 1.0, Decimal(10), (1,2), {}])
2513 self.assertNotIn(Decimal(10), ['a', 1.0, (1,2), {}])
2514
2515 def test_copy(self):
2516 # All copies should be deep
2517 Decimal = self.decimal.Decimal
2518 Context = self.decimal.Context
2519
2520 c = Context()
2521 d = c.copy()
2522 self.assertNotEqual(id(c), id(d))
2523 self.assertNotEqual(id(c.flags), id(d.flags))
2524 self.assertNotEqual(id(c.traps), id(d.traps))
2525 k1 = set(c.flags.keys())
2526 k2 = set(d.flags.keys())
2527 self.assertEqual(k1, k2)
2528 self.assertEqual(c.flags, d.flags)
2529
2530 def test__clamp(self):
2531 # In Python 3.2, the private attribute `_clamp` was made
2532 # public (issue 8540), with the old `_clamp` becoming a
2533 # property wrapping `clamp`. For the duration of Python 3.2
2534 # only, the attribute should be gettable/settable via both
2535 # `clamp` and `_clamp`; in Python 3.3, `_clamp` should be
2536 # removed.
2537 Context = self.decimal.Context
2538 c = Context()
2539 self.assertRaises(AttributeError, getattr, c, '_clamp')
2540
2541 def test_abs(self):
2542 Decimal = self.decimal.Decimal
2543 Context = self.decimal.Context
2544
2545 c = Context()
2546 d = c.abs(Decimal(-1))
2547 self.assertEqual(c.abs(-1), d)
2548 self.assertRaises(TypeError, c.abs, '-1')
2549
2550 def test_add(self):
2551 Decimal = self.decimal.Decimal
2552 Context = self.decimal.Context
2553
2554 c = Context()
2555 d = c.add(Decimal(1), Decimal(1))
2556 self.assertEqual(c.add(1, 1), d)
2557 self.assertEqual(c.add(Decimal(1), 1), d)
2558 self.assertEqual(c.add(1, Decimal(1)), d)
2559 self.assertRaises(TypeError, c.add, '1', 1)
2560 self.assertRaises(TypeError, c.add, 1, '1')
2561
2562 def test_compare(self):
2563 Decimal = self.decimal.Decimal
2564 Context = self.decimal.Context
2565
2566 c = Context()
2567 d = c.compare(Decimal(1), Decimal(1))
2568 self.assertEqual(c.compare(1, 1), d)
2569 self.assertEqual(c.compare(Decimal(1), 1), d)
2570 self.assertEqual(c.compare(1, Decimal(1)), d)
2571 self.assertRaises(TypeError, c.compare, '1', 1)
2572 self.assertRaises(TypeError, c.compare, 1, '1')
2573
2574 def test_compare_signal(self):
2575 Decimal = self.decimal.Decimal
2576 Context = self.decimal.Context
2577
2578 c = Context()
2579 d = c.compare_signal(Decimal(1), Decimal(1))
2580 self.assertEqual(c.compare_signal(1, 1), d)
2581 self.assertEqual(c.compare_signal(Decimal(1), 1), d)
2582 self.assertEqual(c.compare_signal(1, Decimal(1)), d)
2583 self.assertRaises(TypeError, c.compare_signal, '1', 1)
2584 self.assertRaises(TypeError, c.compare_signal, 1, '1')
2585
2586 def test_compare_total(self):
2587 Decimal = self.decimal.Decimal
2588 Context = self.decimal.Context
2589
2590 c = Context()
2591 d = c.compare_total(Decimal(1), Decimal(1))
2592 self.assertEqual(c.compare_total(1, 1), d)
2593 self.assertEqual(c.compare_total(Decimal(1), 1), d)
2594 self.assertEqual(c.compare_total(1, Decimal(1)), d)
2595 self.assertRaises(TypeError, c.compare_total, '1', 1)
2596 self.assertRaises(TypeError, c.compare_total, 1, '1')
2597
2598 def test_compare_total_mag(self):
2599 Decimal = self.decimal.Decimal
2600 Context = self.decimal.Context
2601
2602 c = Context()
2603 d = c.compare_total_mag(Decimal(1), Decimal(1))
2604 self.assertEqual(c.compare_total_mag(1, 1), d)
2605 self.assertEqual(c.compare_total_mag(Decimal(1), 1), d)
2606 self.assertEqual(c.compare_total_mag(1, Decimal(1)), d)
2607 self.assertRaises(TypeError, c.compare_total_mag, '1', 1)
2608 self.assertRaises(TypeError, c.compare_total_mag, 1, '1')
2609
2610 def test_copy_abs(self):
2611 Decimal = self.decimal.Decimal
2612 Context = self.decimal.Context
2613
2614 c = Context()
2615 d = c.copy_abs(Decimal(-1))
2616 self.assertEqual(c.copy_abs(-1), d)
2617 self.assertRaises(TypeError, c.copy_abs, '-1')
2618
2619 def test_copy_decimal(self):
2620 Decimal = self.decimal.Decimal
2621 Context = self.decimal.Context
2622
2623 c = Context()
2624 d = c.copy_decimal(Decimal(-1))
2625 self.assertEqual(c.copy_decimal(-1), d)
2626 self.assertRaises(TypeError, c.copy_decimal, '-1')
2627
2628 def test_copy_negate(self):
2629 Decimal = self.decimal.Decimal
2630 Context = self.decimal.Context
2631
2632 c = Context()
2633 d = c.copy_negate(Decimal(-1))
2634 self.assertEqual(c.copy_negate(-1), d)
2635 self.assertRaises(TypeError, c.copy_negate, '-1')
2636
2637 def test_copy_sign(self):
2638 Decimal = self.decimal.Decimal
2639 Context = self.decimal.Context
2640
2641 c = Context()
2642 d = c.copy_sign(Decimal(1), Decimal(-2))
2643 self.assertEqual(c.copy_sign(1, -2), d)
2644 self.assertEqual(c.copy_sign(Decimal(1), -2), d)
2645 self.assertEqual(c.copy_sign(1, Decimal(-2)), d)
2646 self.assertRaises(TypeError, c.copy_sign, '1', -2)
2647 self.assertRaises(TypeError, c.copy_sign, 1, '-2')
2648
2649 def test_divide(self):
2650 Decimal = self.decimal.Decimal
2651 Context = self.decimal.Context
2652
2653 c = Context()
2654 d = c.divide(Decimal(1), Decimal(2))
2655 self.assertEqual(c.divide(1, 2), d)
2656 self.assertEqual(c.divide(Decimal(1), 2), d)
2657 self.assertEqual(c.divide(1, Decimal(2)), d)
2658 self.assertRaises(TypeError, c.divide, '1', 2)
2659 self.assertRaises(TypeError, c.divide, 1, '2')
2660
2661 def test_divide_int(self):
2662 Decimal = self.decimal.Decimal
2663 Context = self.decimal.Context
2664
2665 c = Context()
2666 d = c.divide_int(Decimal(1), Decimal(2))
2667 self.assertEqual(c.divide_int(1, 2), d)
2668 self.assertEqual(c.divide_int(Decimal(1), 2), d)
2669 self.assertEqual(c.divide_int(1, Decimal(2)), d)
2670 self.assertRaises(TypeError, c.divide_int, '1', 2)
2671 self.assertRaises(TypeError, c.divide_int, 1, '2')
2672
2673 def test_divmod(self):
2674 Decimal = self.decimal.Decimal
2675 Context = self.decimal.Context
2676
2677 c = Context()
2678 d = c.divmod(Decimal(1), Decimal(2))
2679 self.assertEqual(c.divmod(1, 2), d)
2680 self.assertEqual(c.divmod(Decimal(1), 2), d)
2681 self.assertEqual(c.divmod(1, Decimal(2)), d)
2682 self.assertRaises(TypeError, c.divmod, '1', 2)
2683 self.assertRaises(TypeError, c.divmod, 1, '2')
2684
2685 def test_exp(self):
2686 Decimal = self.decimal.Decimal
2687 Context = self.decimal.Context
2688
2689 c = Context()
2690 d = c.exp(Decimal(10))
2691 self.assertEqual(c.exp(10), d)
2692 self.assertRaises(TypeError, c.exp, '10')
2693
2694 def test_fma(self):
2695 Decimal = self.decimal.Decimal
2696 Context = self.decimal.Context
2697
2698 c = Context()
2699 d = c.fma(Decimal(2), Decimal(3), Decimal(4))
2700 self.assertEqual(c.fma(2, 3, 4), d)
2701 self.assertEqual(c.fma(Decimal(2), 3, 4), d)
2702 self.assertEqual(c.fma(2, Decimal(3), 4), d)
2703 self.assertEqual(c.fma(2, 3, Decimal(4)), d)
2704 self.assertEqual(c.fma(Decimal(2), Decimal(3), 4), d)
2705 self.assertRaises(TypeError, c.fma, '2', 3, 4)
2706 self.assertRaises(TypeError, c.fma, 2, '3', 4)
2707 self.assertRaises(TypeError, c.fma, 2, 3, '4')
2708
2709 # Issue 12079 for Context.fma ...
2710 self.assertRaises(TypeError, c.fma,
2711 Decimal('Infinity'), Decimal(0), "not a decimal")
2712 self.assertRaises(TypeError, c.fma,
2713 Decimal(1), Decimal('snan'), 1.222)
2714 # ... and for Decimal.fma.
2715 self.assertRaises(TypeError, Decimal('Infinity').fma,
2716 Decimal(0), "not a decimal")
2717 self.assertRaises(TypeError, Decimal(1).fma,
2718 Decimal('snan'), 1.222)
2719
2720 def test_is_finite(self):
2721 Decimal = self.decimal.Decimal
2722 Context = self.decimal.Context
2723
2724 c = Context()
2725 d = c.is_finite(Decimal(10))
2726 self.assertEqual(c.is_finite(10), d)
2727 self.assertRaises(TypeError, c.is_finite, '10')
2728
2729 def test_is_infinite(self):
2730 Decimal = self.decimal.Decimal
2731 Context = self.decimal.Context
2732
2733 c = Context()
2734 d = c.is_infinite(Decimal(10))
2735 self.assertEqual(c.is_infinite(10), d)
2736 self.assertRaises(TypeError, c.is_infinite, '10')
2737
2738 def test_is_nan(self):
2739 Decimal = self.decimal.Decimal
2740 Context = self.decimal.Context
2741
2742 c = Context()
2743 d = c.is_nan(Decimal(10))
2744 self.assertEqual(c.is_nan(10), d)
2745 self.assertRaises(TypeError, c.is_nan, '10')
2746
2747 def test_is_normal(self):
2748 Decimal = self.decimal.Decimal
2749 Context = self.decimal.Context
2750
2751 c = Context()
2752 d = c.is_normal(Decimal(10))
2753 self.assertEqual(c.is_normal(10), d)
2754 self.assertRaises(TypeError, c.is_normal, '10')
2755
2756 def test_is_qnan(self):
2757 Decimal = self.decimal.Decimal
2758 Context = self.decimal.Context
2759
2760 c = Context()
2761 d = c.is_qnan(Decimal(10))
2762 self.assertEqual(c.is_qnan(10), d)
2763 self.assertRaises(TypeError, c.is_qnan, '10')
2764
2765 def test_is_signed(self):
2766 Decimal = self.decimal.Decimal
2767 Context = self.decimal.Context
2768
2769 c = Context()
2770 d = c.is_signed(Decimal(10))
2771 self.assertEqual(c.is_signed(10), d)
2772 self.assertRaises(TypeError, c.is_signed, '10')
2773
2774 def test_is_snan(self):
2775 Decimal = self.decimal.Decimal
2776 Context = self.decimal.Context
2777
2778 c = Context()
2779 d = c.is_snan(Decimal(10))
2780 self.assertEqual(c.is_snan(10), d)
2781 self.assertRaises(TypeError, c.is_snan, '10')
2782
2783 def test_is_subnormal(self):
2784 Decimal = self.decimal.Decimal
2785 Context = self.decimal.Context
2786
2787 c = Context()
2788 d = c.is_subnormal(Decimal(10))
2789 self.assertEqual(c.is_subnormal(10), d)
2790 self.assertRaises(TypeError, c.is_subnormal, '10')
2791
2792 def test_is_zero(self):
2793 Decimal = self.decimal.Decimal
2794 Context = self.decimal.Context
2795
2796 c = Context()
2797 d = c.is_zero(Decimal(10))
2798 self.assertEqual(c.is_zero(10), d)
2799 self.assertRaises(TypeError, c.is_zero, '10')
2800
2801 def test_ln(self):
2802 Decimal = self.decimal.Decimal
2803 Context = self.decimal.Context
2804
2805 c = Context()
2806 d = c.ln(Decimal(10))
2807 self.assertEqual(c.ln(10), d)
2808 self.assertRaises(TypeError, c.ln, '10')
2809
2810 def test_log10(self):
2811 Decimal = self.decimal.Decimal
2812 Context = self.decimal.Context
2813
2814 c = Context()
2815 d = c.log10(Decimal(10))
2816 self.assertEqual(c.log10(10), d)
2817 self.assertRaises(TypeError, c.log10, '10')
2818
2819 def test_logb(self):
2820 Decimal = self.decimal.Decimal
2821 Context = self.decimal.Context
2822
2823 c = Context()
2824 d = c.logb(Decimal(10))
2825 self.assertEqual(c.logb(10), d)
2826 self.assertRaises(TypeError, c.logb, '10')
2827
2828 def test_logical_and(self):
2829 Decimal = self.decimal.Decimal
2830 Context = self.decimal.Context
2831
2832 c = Context()
2833 d = c.logical_and(Decimal(1), Decimal(1))
2834 self.assertEqual(c.logical_and(1, 1), d)
2835 self.assertEqual(c.logical_and(Decimal(1), 1), d)
2836 self.assertEqual(c.logical_and(1, Decimal(1)), d)
2837 self.assertRaises(TypeError, c.logical_and, '1', 1)
2838 self.assertRaises(TypeError, c.logical_and, 1, '1')
2839
2840 def test_logical_invert(self):
2841 Decimal = self.decimal.Decimal
2842 Context = self.decimal.Context
2843
2844 c = Context()
2845 d = c.logical_invert(Decimal(1000))
2846 self.assertEqual(c.logical_invert(1000), d)
2847 self.assertRaises(TypeError, c.logical_invert, '1000')
2848
2849 def test_logical_or(self):
2850 Decimal = self.decimal.Decimal
2851 Context = self.decimal.Context
2852
2853 c = Context()
2854 d = c.logical_or(Decimal(1), Decimal(1))
2855 self.assertEqual(c.logical_or(1, 1), d)
2856 self.assertEqual(c.logical_or(Decimal(1), 1), d)
2857 self.assertEqual(c.logical_or(1, Decimal(1)), d)
2858 self.assertRaises(TypeError, c.logical_or, '1', 1)
2859 self.assertRaises(TypeError, c.logical_or, 1, '1')
2860
2861 def test_logical_xor(self):
2862 Decimal = self.decimal.Decimal
2863 Context = self.decimal.Context
2864
2865 c = Context()
2866 d = c.logical_xor(Decimal(1), Decimal(1))
2867 self.assertEqual(c.logical_xor(1, 1), d)
2868 self.assertEqual(c.logical_xor(Decimal(1), 1), d)
2869 self.assertEqual(c.logical_xor(1, Decimal(1)), d)
2870 self.assertRaises(TypeError, c.logical_xor, '1', 1)
2871 self.assertRaises(TypeError, c.logical_xor, 1, '1')
2872
2873 def test_max(self):
2874 Decimal = self.decimal.Decimal
2875 Context = self.decimal.Context
2876
2877 c = Context()
2878 d = c.max(Decimal(1), Decimal(2))
2879 self.assertEqual(c.max(1, 2), d)
2880 self.assertEqual(c.max(Decimal(1), 2), d)
2881 self.assertEqual(c.max(1, Decimal(2)), d)
2882 self.assertRaises(TypeError, c.max, '1', 2)
2883 self.assertRaises(TypeError, c.max, 1, '2')
2884
2885 def test_max_mag(self):
2886 Decimal = self.decimal.Decimal
2887 Context = self.decimal.Context
2888
2889 c = Context()
2890 d = c.max_mag(Decimal(1), Decimal(2))
2891 self.assertEqual(c.max_mag(1, 2), d)
2892 self.assertEqual(c.max_mag(Decimal(1), 2), d)
2893 self.assertEqual(c.max_mag(1, Decimal(2)), d)
2894 self.assertRaises(TypeError, c.max_mag, '1', 2)
2895 self.assertRaises(TypeError, c.max_mag, 1, '2')
2896
2897 def test_min(self):
2898 Decimal = self.decimal.Decimal
2899 Context = self.decimal.Context
2900
2901 c = Context()
2902 d = c.min(Decimal(1), Decimal(2))
2903 self.assertEqual(c.min(1, 2), d)
2904 self.assertEqual(c.min(Decimal(1), 2), d)
2905 self.assertEqual(c.min(1, Decimal(2)), d)
2906 self.assertRaises(TypeError, c.min, '1', 2)
2907 self.assertRaises(TypeError, c.min, 1, '2')
2908
2909 def test_min_mag(self):
2910 Decimal = self.decimal.Decimal
2911 Context = self.decimal.Context
2912
2913 c = Context()
2914 d = c.min_mag(Decimal(1), Decimal(2))
2915 self.assertEqual(c.min_mag(1, 2), d)
2916 self.assertEqual(c.min_mag(Decimal(1), 2), d)
2917 self.assertEqual(c.min_mag(1, Decimal(2)), d)
2918 self.assertRaises(TypeError, c.min_mag, '1', 2)
2919 self.assertRaises(TypeError, c.min_mag, 1, '2')
2920
2921 def test_minus(self):
2922 Decimal = self.decimal.Decimal
2923 Context = self.decimal.Context
2924
2925 c = Context()
2926 d = c.minus(Decimal(10))
2927 self.assertEqual(c.minus(10), d)
2928 self.assertRaises(TypeError, c.minus, '10')
2929
2930 def test_multiply(self):
2931 Decimal = self.decimal.Decimal
2932 Context = self.decimal.Context
2933
2934 c = Context()
2935 d = c.multiply(Decimal(1), Decimal(2))
2936 self.assertEqual(c.multiply(1, 2), d)
2937 self.assertEqual(c.multiply(Decimal(1), 2), d)
2938 self.assertEqual(c.multiply(1, Decimal(2)), d)
2939 self.assertRaises(TypeError, c.multiply, '1', 2)
2940 self.assertRaises(TypeError, c.multiply, 1, '2')
2941
2942 def test_next_minus(self):
2943 Decimal = self.decimal.Decimal
2944 Context = self.decimal.Context
2945
2946 c = Context()
2947 d = c.next_minus(Decimal(10))
2948 self.assertEqual(c.next_minus(10), d)
2949 self.assertRaises(TypeError, c.next_minus, '10')
2950
2951 def test_next_plus(self):
2952 Decimal = self.decimal.Decimal
2953 Context = self.decimal.Context
2954
2955 c = Context()
2956 d = c.next_plus(Decimal(10))
2957 self.assertEqual(c.next_plus(10), d)
2958 self.assertRaises(TypeError, c.next_plus, '10')
2959
2960 def test_next_toward(self):
2961 Decimal = self.decimal.Decimal
2962 Context = self.decimal.Context
2963
2964 c = Context()
2965 d = c.next_toward(Decimal(1), Decimal(2))
2966 self.assertEqual(c.next_toward(1, 2), d)
2967 self.assertEqual(c.next_toward(Decimal(1), 2), d)
2968 self.assertEqual(c.next_toward(1, Decimal(2)), d)
2969 self.assertRaises(TypeError, c.next_toward, '1', 2)
2970 self.assertRaises(TypeError, c.next_toward, 1, '2')
2971
2972 def test_normalize(self):
2973 Decimal = self.decimal.Decimal
2974 Context = self.decimal.Context
2975
2976 c = Context()
2977 d = c.normalize(Decimal(10))
2978 self.assertEqual(c.normalize(10), d)
2979 self.assertRaises(TypeError, c.normalize, '10')
2980
2981 def test_number_class(self):
2982 Decimal = self.decimal.Decimal
2983 Context = self.decimal.Context
2984
2985 c = Context()
2986 self.assertEqual(c.number_class(123), c.number_class(Decimal(123)))
2987 self.assertEqual(c.number_class(0), c.number_class(Decimal(0)))
2988 self.assertEqual(c.number_class(-45), c.number_class(Decimal(-45)))
2989
2990 def test_plus(self):
2991 Decimal = self.decimal.Decimal
2992 Context = self.decimal.Context
2993
2994 c = Context()
2995 d = c.plus(Decimal(10))
2996 self.assertEqual(c.plus(10), d)
2997 self.assertRaises(TypeError, c.plus, '10')
2998
2999 def test_power(self):
3000 Decimal = self.decimal.Decimal
3001 Context = self.decimal.Context
3002
3003 c = Context()
3004 d = c.power(Decimal(1), Decimal(4))
3005 self.assertEqual(c.power(1, 4), d)
3006 self.assertEqual(c.power(Decimal(1), 4), d)
3007 self.assertEqual(c.power(1, Decimal(4)), d)
3008 self.assertEqual(c.power(Decimal(1), Decimal(4)), d)
3009 self.assertRaises(TypeError, c.power, '1', 4)
3010 self.assertRaises(TypeError, c.power, 1, '4')
3011 self.assertEqual(c.power(modulo=5, b=8, a=2), 1)
3012
3013 def test_quantize(self):
3014 Decimal = self.decimal.Decimal
3015 Context = self.decimal.Context
3016
3017 c = Context()
3018 d = c.quantize(Decimal(1), Decimal(2))
3019 self.assertEqual(c.quantize(1, 2), d)
3020 self.assertEqual(c.quantize(Decimal(1), 2), d)
3021 self.assertEqual(c.quantize(1, Decimal(2)), d)
3022 self.assertRaises(TypeError, c.quantize, '1', 2)
3023 self.assertRaises(TypeError, c.quantize, 1, '2')
3024
3025 def test_remainder(self):
3026 Decimal = self.decimal.Decimal
3027 Context = self.decimal.Context
3028
3029 c = Context()
3030 d = c.remainder(Decimal(1), Decimal(2))
3031 self.assertEqual(c.remainder(1, 2), d)
3032 self.assertEqual(c.remainder(Decimal(1), 2), d)
3033 self.assertEqual(c.remainder(1, Decimal(2)), d)
3034 self.assertRaises(TypeError, c.remainder, '1', 2)
3035 self.assertRaises(TypeError, c.remainder, 1, '2')
3036
3037 def test_remainder_near(self):
3038 Decimal = self.decimal.Decimal
3039 Context = self.decimal.Context
3040
3041 c = Context()
3042 d = c.remainder_near(Decimal(1), Decimal(2))
3043 self.assertEqual(c.remainder_near(1, 2), d)
3044 self.assertEqual(c.remainder_near(Decimal(1), 2), d)
3045 self.assertEqual(c.remainder_near(1, Decimal(2)), d)
3046 self.assertRaises(TypeError, c.remainder_near, '1', 2)
3047 self.assertRaises(TypeError, c.remainder_near, 1, '2')
3048
3049 def test_rotate(self):
3050 Decimal = self.decimal.Decimal
3051 Context = self.decimal.Context
3052
3053 c = Context()
3054 d = c.rotate(Decimal(1), Decimal(2))
3055 self.assertEqual(c.rotate(1, 2), d)
3056 self.assertEqual(c.rotate(Decimal(1), 2), d)
3057 self.assertEqual(c.rotate(1, Decimal(2)), d)
3058 self.assertRaises(TypeError, c.rotate, '1', 2)
3059 self.assertRaises(TypeError, c.rotate, 1, '2')
3060
3061 def test_sqrt(self):
3062 Decimal = self.decimal.Decimal
3063 Context = self.decimal.Context
3064
3065 c = Context()
3066 d = c.sqrt(Decimal(10))
3067 self.assertEqual(c.sqrt(10), d)
3068 self.assertRaises(TypeError, c.sqrt, '10')
3069
3070 def test_same_quantum(self):
3071 Decimal = self.decimal.Decimal
3072 Context = self.decimal.Context
3073
3074 c = Context()
3075 d = c.same_quantum(Decimal(1), Decimal(2))
3076 self.assertEqual(c.same_quantum(1, 2), d)
3077 self.assertEqual(c.same_quantum(Decimal(1), 2), d)
3078 self.assertEqual(c.same_quantum(1, Decimal(2)), d)
3079 self.assertRaises(TypeError, c.same_quantum, '1', 2)
3080 self.assertRaises(TypeError, c.same_quantum, 1, '2')
3081
3082 def test_scaleb(self):
3083 Decimal = self.decimal.Decimal
3084 Context = self.decimal.Context
3085
3086 c = Context()
3087 d = c.scaleb(Decimal(1), Decimal(2))
3088 self.assertEqual(c.scaleb(1, 2), d)
3089 self.assertEqual(c.scaleb(Decimal(1), 2), d)
3090 self.assertEqual(c.scaleb(1, Decimal(2)), d)
3091 self.assertRaises(TypeError, c.scaleb, '1', 2)
3092 self.assertRaises(TypeError, c.scaleb, 1, '2')
3093
3094 def test_shift(self):
3095 Decimal = self.decimal.Decimal
3096 Context = self.decimal.Context
3097
3098 c = Context()
3099 d = c.shift(Decimal(1), Decimal(2))
3100 self.assertEqual(c.shift(1, 2), d)
3101 self.assertEqual(c.shift(Decimal(1), 2), d)
3102 self.assertEqual(c.shift(1, Decimal(2)), d)
3103 self.assertRaises(TypeError, c.shift, '1', 2)
3104 self.assertRaises(TypeError, c.shift, 1, '2')
3105
3106 def test_subtract(self):
3107 Decimal = self.decimal.Decimal
3108 Context = self.decimal.Context
3109
3110 c = Context()
3111 d = c.subtract(Decimal(1), Decimal(2))
3112 self.assertEqual(c.subtract(1, 2), d)
3113 self.assertEqual(c.subtract(Decimal(1), 2), d)
3114 self.assertEqual(c.subtract(1, Decimal(2)), d)
3115 self.assertRaises(TypeError, c.subtract, '1', 2)
3116 self.assertRaises(TypeError, c.subtract, 1, '2')
3117
3118 def test_to_eng_string(self):
3119 Decimal = self.decimal.Decimal
3120 Context = self.decimal.Context
3121
3122 c = Context()
3123 d = c.to_eng_string(Decimal(10))
3124 self.assertEqual(c.to_eng_string(10), d)
3125 self.assertRaises(TypeError, c.to_eng_string, '10')
3126
3127 def test_to_sci_string(self):
3128 Decimal = self.decimal.Decimal
3129 Context = self.decimal.Context
3130
3131 c = Context()
3132 d = c.to_sci_string(Decimal(10))
3133 self.assertEqual(c.to_sci_string(10), d)
3134 self.assertRaises(TypeError, c.to_sci_string, '10')
3135
3136 def test_to_integral_exact(self):
3137 Decimal = self.decimal.Decimal
3138 Context = self.decimal.Context
3139
3140 c = Context()
3141 d = c.to_integral_exact(Decimal(10))
3142 self.assertEqual(c.to_integral_exact(10), d)
3143 self.assertRaises(TypeError, c.to_integral_exact, '10')
3144
3145 def test_to_integral_value(self):
3146 Decimal = self.decimal.Decimal
3147 Context = self.decimal.Context
3148
3149 c = Context()
3150 d = c.to_integral_value(Decimal(10))
3151 self.assertEqual(c.to_integral_value(10), d)
3152 self.assertRaises(TypeError, c.to_integral_value, '10')
3153 self.assertRaises(TypeError, c.to_integral_value, 10, 'x')
3154
3155class CContextAPItests(ContextAPItests):
3156 decimal = C
3157class PyContextAPItests(ContextAPItests):
3158 decimal = P
3159
3160class ContextWithStatement(unittest.TestCase):
3161 # Can't do these as docstrings until Python 2.6
3162 # as doctest can't handle __future__ statements
3163
3164 def test_localcontext(self):
3165 # Use a copy of the current context in the block
3166 getcontext = self.decimal.getcontext
3167 localcontext = self.decimal.localcontext
3168
3169 orig_ctx = getcontext()
3170 with localcontext() as enter_ctx:
3171 set_ctx = getcontext()
3172 final_ctx = getcontext()
3173 self.assertIs(orig_ctx, final_ctx, 'did not restore context correctly')
3174 self.assertIsNot(orig_ctx, set_ctx, 'did not copy the context')
3175 self.assertIs(set_ctx, enter_ctx, '__enter__ returned wrong context')
3176
3177 def test_localcontextarg(self):
3178 # Use a copy of the supplied context in the block
3179 Context = self.decimal.Context
3180 getcontext = self.decimal.getcontext
3181 localcontext = self.decimal.localcontext
3182
3183 localcontext = self.decimal.localcontext
3184 orig_ctx = getcontext()
3185 new_ctx = Context(prec=42)
3186 with localcontext(new_ctx) as enter_ctx:
3187 set_ctx = getcontext()
3188 final_ctx = getcontext()
3189 self.assertIs(orig_ctx, final_ctx, 'did not restore context correctly')
3190 self.assertEqual(set_ctx.prec, new_ctx.prec, 'did not set correct context')
3191 self.assertIsNot(new_ctx, set_ctx, 'did not copy the context')
3192 self.assertIs(set_ctx, enter_ctx, '__enter__ returned wrong context')
3193
3194 def test_nested_with_statements(self):
3195 # Use a copy of the supplied context in the block
3196 Decimal = self.decimal.Decimal
3197 Context = self.decimal.Context
3198 getcontext = self.decimal.getcontext
3199 localcontext = self.decimal.localcontext
3200 Clamped = self.decimal.Clamped
3201 Overflow = self.decimal.Overflow
3202
3203 orig_ctx = getcontext()
3204 orig_ctx.clear_flags()
3205 new_ctx = Context(Emax=384)
3206 with localcontext() as c1:
3207 self.assertEqual(c1.flags, orig_ctx.flags)
3208 self.assertEqual(c1.traps, orig_ctx.traps)
3209 c1.traps[Clamped] = True
3210 c1.Emin = -383
3211 self.assertNotEqual(orig_ctx.Emin, -383)
3212 self.assertRaises(Clamped, c1.create_decimal, '0e-999')
3213 self.assertTrue(c1.flags[Clamped])
3214 with localcontext(new_ctx) as c2:
3215 self.assertEqual(c2.flags, new_ctx.flags)
3216 self.assertEqual(c2.traps, new_ctx.traps)
3217 self.assertRaises(Overflow, c2.power, Decimal('3.4e200'), 2)
3218 self.assertFalse(c2.flags[Clamped])
3219 self.assertTrue(c2.flags[Overflow])
3220 del c2
3221 self.assertFalse(c1.flags[Overflow])
3222 del c1
3223 self.assertNotEqual(orig_ctx.Emin, -383)
3224 self.assertFalse(orig_ctx.flags[Clamped])
3225 self.assertFalse(orig_ctx.flags[Overflow])
3226 self.assertFalse(new_ctx.flags[Clamped])
3227 self.assertFalse(new_ctx.flags[Overflow])
3228
3229 def test_with_statements_gc1(self):
3230 localcontext = self.decimal.localcontext
3231
3232 with localcontext() as c1:
3233 del c1
3234 with localcontext() as c2:
3235 del c2
3236 with localcontext() as c3:
3237 del c3
3238 with localcontext() as c4:
3239 del c4
3240
3241 def test_with_statements_gc2(self):
3242 localcontext = self.decimal.localcontext
3243
3244 with localcontext() as c1:
3245 with localcontext(c1) as c2:
3246 del c1
3247 with localcontext(c2) as c3:
3248 del c2
3249 with localcontext(c3) as c4:
3250 del c3
3251 del c4
3252
3253 def test_with_statements_gc3(self):
3254 Context = self.decimal.Context
3255 localcontext = self.decimal.localcontext
3256 getcontext = self.decimal.getcontext
3257 setcontext = self.decimal.setcontext
3258
3259 with localcontext() as c1:
3260 del c1
3261 n1 = Context(prec=1)
3262 setcontext(n1)
3263 with localcontext(n1) as c2:
3264 del n1
3265 self.assertEqual(c2.prec, 1)
3266 del c2
3267 n2 = Context(prec=2)
3268 setcontext(n2)
3269 del n2
3270 self.assertEqual(getcontext().prec, 2)
3271 n3 = Context(prec=3)
3272 setcontext(n3)
3273 self.assertEqual(getcontext().prec, 3)
3274 with localcontext(n3) as c3:
3275 del n3
3276 self.assertEqual(c3.prec, 3)
3277 del c3
3278 n4 = Context(prec=4)
3279 setcontext(n4)
3280 del n4
3281 self.assertEqual(getcontext().prec, 4)
3282 with localcontext() as c4:
3283 self.assertEqual(c4.prec, 4)
3284 del c4
3285
3286class CContextWithStatement(ContextWithStatement):
3287 decimal = C
3288class PyContextWithStatement(ContextWithStatement):
3289 decimal = P
3290
3291class ContextFlags(unittest.TestCase):
3292
3293 def test_flags_irrelevant(self):
3294 # check that the result (numeric result + flags raised) of an
3295 # arithmetic operation doesn't depend on the current flags
3296 Decimal = self.decimal.Decimal
3297 Context = self.decimal.Context
3298 Inexact = self.decimal.Inexact
3299 Rounded = self.decimal.Rounded
3300 Underflow = self.decimal.Underflow
3301 Clamped = self.decimal.Clamped
3302 Subnormal = self.decimal.Subnormal
3303 ROUND_HALF_EVEN = self.decimal.ROUND_HALF_EVEN
3304
3305 def raise_error(context, flag):
3306 if self.decimal == C:
3307 context.flags[flag] = True
3308 if context.traps[flag]:
3309 raise flag
3310 else:
3311 context._raise_error(flag)
3312
3313 context = Context(prec=9, Emin = -425000000, Emax = 425000000,
3314 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
3315
3316 # operations that raise various flags, in the form (function, arglist)
3317 operations = [
3318 (context._apply, [Decimal("100E-425000010")]),
3319 (context.sqrt, [Decimal(2)]),
3320 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
3321 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
3322 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
3323 ]
3324
3325 # try various flags individually, then a whole lot at once
3326 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
3327 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
3328
3329 for fn, args in operations:
3330 # find answer and flags raised using a clean context
3331 context.clear_flags()
3332 ans = fn(*args)
3333 flags = [k for k, v in context.flags.items() if v]
3334
3335 for extra_flags in flagsets:
3336 # set flags, before calling operation
3337 context.clear_flags()
3338 for flag in extra_flags:
3339 raise_error(context, flag)
3340 new_ans = fn(*args)
3341
3342 # flags that we expect to be set after the operation
3343 expected_flags = list(flags)
3344 for flag in extra_flags:
3345 if flag not in expected_flags:
3346 expected_flags.append(flag)
3347 expected_flags.sort(key=id)
3348
3349 # flags we actually got
3350 new_flags = [k for k,v in context.flags.items() if v]
3351 new_flags.sort(key=id)
3352
3353 self.assertEqual(ans, new_ans,
3354 "operation produces different answers depending on flags set: " +
3355 "expected %s, got %s." % (ans, new_ans))
3356 self.assertEqual(new_flags, expected_flags,
3357 "operation raises different flags depending on flags set: " +
3358 "expected %s, got %s" % (expected_flags, new_flags))
3359
3360 def test_flag_comparisons(self):
3361 Context = self.decimal.Context
3362 Inexact = self.decimal.Inexact
3363 Rounded = self.decimal.Rounded
3364
3365 c = Context()
3366
3367 # Valid SignalDict
3368 self.assertNotEqual(c.flags, c.traps)
3369 self.assertNotEqual(c.traps, c.flags)
3370
3371 c.flags = c.traps
3372 self.assertEqual(c.flags, c.traps)
3373 self.assertEqual(c.traps, c.flags)
3374
3375 c.flags[Rounded] = True
3376 c.traps = c.flags
3377 self.assertEqual(c.flags, c.traps)
3378 self.assertEqual(c.traps, c.flags)
3379
3380 d = {}
3381 d.update(c.flags)
3382 self.assertEqual(d, c.flags)
3383 self.assertEqual(c.flags, d)
3384
3385 d[Inexact] = True
3386 self.assertNotEqual(d, c.flags)
3387 self.assertNotEqual(c.flags, d)
3388
3389 # Invalid SignalDict
3390 d = {Inexact:False}
3391 self.assertNotEqual(d, c.flags)
3392 self.assertNotEqual(c.flags, d)
3393
3394 d = ["xyz"]
3395 self.assertNotEqual(d, c.flags)
3396 self.assertNotEqual(c.flags, d)
3397
3398 @requires_IEEE_754
3399 def test_float_operation(self):
3400 Decimal = self.decimal.Decimal
3401 FloatOperation = self.decimal.FloatOperation
3402 localcontext = self.decimal.localcontext
3403
3404 with localcontext() as c:
3405 ##### trap is off by default
3406 self.assertFalse(c.traps[FloatOperation])
3407
3408 # implicit conversion sets the flag
3409 c.clear_flags()
3410 self.assertEqual(Decimal(7.5), 7.5)
3411 self.assertTrue(c.flags[FloatOperation])
3412
3413 c.clear_flags()
3414 self.assertEqual(c.create_decimal(7.5), 7.5)
3415 self.assertTrue(c.flags[FloatOperation])
3416
3417 # explicit conversion does not set the flag
3418 c.clear_flags()
3419 x = Decimal.from_float(7.5)
3420 self.assertFalse(c.flags[FloatOperation])
3421 # comparison sets the flag
3422 self.assertEqual(x, 7.5)
3423 self.assertTrue(c.flags[FloatOperation])
3424
3425 c.clear_flags()
3426 x = c.create_decimal_from_float(7.5)
3427 self.assertFalse(c.flags[FloatOperation])
3428 self.assertEqual(x, 7.5)
3429 self.assertTrue(c.flags[FloatOperation])
3430
3431 ##### set the trap
3432 c.traps[FloatOperation] = True
3433
3434 # implicit conversion raises
3435 c.clear_flags()
3436 self.assertRaises(FloatOperation, Decimal, 7.5)
3437 self.assertTrue(c.flags[FloatOperation])
3438
3439 c.clear_flags()
3440 self.assertRaises(FloatOperation, c.create_decimal, 7.5)
3441 self.assertTrue(c.flags[FloatOperation])
3442
3443 # explicit conversion is silent
3444 c.clear_flags()
3445 x = Decimal.from_float(7.5)
3446 self.assertFalse(c.flags[FloatOperation])
3447
3448 c.clear_flags()
3449 x = c.create_decimal_from_float(7.5)
3450 self.assertFalse(c.flags[FloatOperation])
3451
3452 def test_float_comparison(self):
3453 Decimal = self.decimal.Decimal
3454 Context = self.decimal.Context
3455 FloatOperation = self.decimal.FloatOperation
3456 localcontext = self.decimal.localcontext
3457
3458 def assert_attr(a, b, attr, context, signal=None):
3459 context.clear_flags()
3460 f = getattr(a, attr)
3461 if signal == FloatOperation:
3462 self.assertRaises(signal, f, b)
3463 else:
3464 self.assertIs(f(b), True)
3465 self.assertTrue(context.flags[FloatOperation])
3466
3467 small_d = Decimal('0.25')
3468 big_d = Decimal('3.0')
3469 small_f = 0.25
3470 big_f = 3.0
3471
3472 zero_d = Decimal('0.0')
3473 neg_zero_d = Decimal('-0.0')
3474 zero_f = 0.0
3475 neg_zero_f = -0.0
3476
3477 inf_d = Decimal('Infinity')
3478 neg_inf_d = Decimal('-Infinity')
3479 inf_f = float('inf')
3480 neg_inf_f = float('-inf')
3481
3482 def doit(c, signal=None):
3483 # Order
3484 for attr in '__lt__', '__le__':
3485 assert_attr(small_d, big_f, attr, c, signal)
3486
3487 for attr in '__gt__', '__ge__':
3488 assert_attr(big_d, small_f, attr, c, signal)
3489
3490 # Equality
3491 assert_attr(small_d, small_f, '__eq__', c, None)
3492
3493 assert_attr(neg_zero_d, neg_zero_f, '__eq__', c, None)
3494 assert_attr(neg_zero_d, zero_f, '__eq__', c, None)
3495
3496 assert_attr(zero_d, neg_zero_f, '__eq__', c, None)
3497 assert_attr(zero_d, zero_f, '__eq__', c, None)
3498
3499 assert_attr(neg_inf_d, neg_inf_f, '__eq__', c, None)
3500 assert_attr(inf_d, inf_f, '__eq__', c, None)
3501
3502 # Inequality
3503 assert_attr(small_d, big_f, '__ne__', c, None)
3504
3505 assert_attr(Decimal('0.1'), 0.1, '__ne__', c, None)
3506
3507 assert_attr(neg_inf_d, inf_f, '__ne__', c, None)
3508 assert_attr(inf_d, neg_inf_f, '__ne__', c, None)
3509
3510 assert_attr(Decimal('NaN'), float('nan'), '__ne__', c, None)
3511
3512 def test_containers(c, signal=None):
3513 c.clear_flags()
3514 s = set([100.0, Decimal('100.0')])
3515 self.assertEqual(len(s), 1)
3516 self.assertTrue(c.flags[FloatOperation])
3517
3518 c.clear_flags()
3519 if signal:
3520 self.assertRaises(signal, sorted, [1.0, Decimal('10.0')])
3521 else:
3522 s = sorted([10.0, Decimal('10.0')])
3523 self.assertTrue(c.flags[FloatOperation])
3524
3525 c.clear_flags()
3526 b = 10.0 in [Decimal('10.0'), 1.0]
3527 self.assertTrue(c.flags[FloatOperation])
3528
3529 c.clear_flags()
3530 b = 10.0 in {Decimal('10.0'):'a', 1.0:'b'}
3531 self.assertTrue(c.flags[FloatOperation])
3532
3533 nc = Context()
3534 with localcontext(nc) as c:
3535 self.assertFalse(c.traps[FloatOperation])
3536 doit(c, signal=None)
3537 test_containers(c, signal=None)
3538
3539 c.traps[FloatOperation] = True
3540 doit(c, signal=FloatOperation)
3541 test_containers(c, signal=FloatOperation)
3542
3543 def test_float_operation_default(self):
3544 Decimal = self.decimal.Decimal
3545 Context = self.decimal.Context
3546 Inexact = self.decimal.Inexact
3547 FloatOperation= self.decimal.FloatOperation
3548
3549 context = Context()
3550 self.assertFalse(context.flags[FloatOperation])
3551 self.assertFalse(context.traps[FloatOperation])
3552
3553 context.clear_traps()
3554 context.traps[Inexact] = True
3555 context.traps[FloatOperation] = True
3556 self.assertTrue(context.traps[FloatOperation])
3557 self.assertTrue(context.traps[Inexact])
3558
3559class CContextFlags(ContextFlags):
3560 decimal = C
3561class PyContextFlags(ContextFlags):
3562 decimal = P
3563
3564class SpecialContexts(unittest.TestCase):
3565 """Test the context templates."""
3566
3567 def test_context_templates(self):
3568 BasicContext = self.decimal.BasicContext
3569 ExtendedContext = self.decimal.ExtendedContext
3570 getcontext = self.decimal.getcontext
3571 setcontext = self.decimal.setcontext
3572 InvalidOperation = self.decimal.InvalidOperation
3573 DivisionByZero = self.decimal.DivisionByZero
3574 Overflow = self.decimal.Overflow
3575 Underflow = self.decimal.Underflow
3576 Clamped = self.decimal.Clamped
3577
3578 assert_signals(self, BasicContext, 'traps',
3579 [InvalidOperation, DivisionByZero, Overflow, Underflow, Clamped]
3580 )
3581
3582 savecontext = getcontext().copy()
3583 basic_context_prec = BasicContext.prec
3584 extended_context_prec = ExtendedContext.prec
3585
3586 ex = None
3587 try:
3588 BasicContext.prec = ExtendedContext.prec = 441
3589 for template in BasicContext, ExtendedContext:
3590 setcontext(template)
3591 c = getcontext()
3592 self.assertIsNot(c, template)
3593 self.assertEqual(c.prec, 441)
3594 except Exception as e:
3595 ex = e.__class__
3596 finally:
3597 BasicContext.prec = basic_context_prec
3598 ExtendedContext.prec = extended_context_prec
3599 setcontext(savecontext)
3600 if ex:
3601 raise ex
3602
3603 def test_default_context(self):
3604 DefaultContext = self.decimal.DefaultContext
3605 BasicContext = self.decimal.BasicContext
3606 ExtendedContext = self.decimal.ExtendedContext
3607 getcontext = self.decimal.getcontext
3608 setcontext = self.decimal.setcontext
3609 InvalidOperation = self.decimal.InvalidOperation
3610 DivisionByZero = self.decimal.DivisionByZero
3611 Overflow = self.decimal.Overflow
3612
3613 self.assertEqual(BasicContext.prec, 9)
3614 self.assertEqual(ExtendedContext.prec, 9)
3615
3616 assert_signals(self, DefaultContext, 'traps',
3617 [InvalidOperation, DivisionByZero, Overflow]
3618 )
3619
3620 savecontext = getcontext().copy()
3621 default_context_prec = DefaultContext.prec
3622
3623 ex = None
3624 try:
3625 c = getcontext()
3626 saveprec = c.prec
3627
3628 DefaultContext.prec = 961
3629 c = getcontext()
3630 self.assertEqual(c.prec, saveprec)
3631
3632 setcontext(DefaultContext)
3633 c = getcontext()
3634 self.assertIsNot(c, DefaultContext)
3635 self.assertEqual(c.prec, 961)
3636 except Exception as e:
3637 ex = e.__class__
3638 finally:
3639 DefaultContext.prec = default_context_prec
3640 setcontext(savecontext)
3641 if ex:
3642 raise ex
3643
3644class CSpecialContexts(SpecialContexts):
3645 decimal = C
3646class PySpecialContexts(SpecialContexts):
3647 decimal = P
3648
3649class ContextInputValidation(unittest.TestCase):
3650
3651 def test_invalid_context(self):
3652 Context = self.decimal.Context
3653 DefaultContext = self.decimal.DefaultContext
3654
3655 c = DefaultContext.copy()
3656
3657 # prec, Emax
3658 for attr in ['prec', 'Emax']:
3659 setattr(c, attr, 999999)
3660 self.assertEqual(getattr(c, attr), 999999)
3661 self.assertRaises(ValueError, setattr, c, attr, -1)
3662 self.assertRaises(TypeError, setattr, c, attr, 'xyz')
3663
3664 # Emin
3665 setattr(c, 'Emin', -999999)
3666 self.assertEqual(getattr(c, 'Emin'), -999999)
3667 self.assertRaises(ValueError, setattr, c, 'Emin', 1)
3668 self.assertRaises(TypeError, setattr, c, 'Emin', (1,2,3))
3669
3670 # rounding: always raise TypeError in order to get consistent
3671 # exceptions across implementations. In decimal, rounding
3672 # modes are strings, in _decimal they are integers. The idea
3673 # is to view rounding as an abstract type and not mind the
3674 # implementation details.
3675 # Hence, a user should view the rounding modes as if they
3676 # had been defined in a language that supports abstract
3677 # data types, e.g. ocaml:
3678 #
3679 # type rounding = ROUND_DOWN | ROUND_HALF_UP | ... ;;
3680 #
3681 self.assertRaises(TypeError, setattr, c, 'rounding', -1)
3682 self.assertRaises(TypeError, setattr, c, 'rounding', 9)
3683 self.assertRaises(TypeError, setattr, c, 'rounding', 1.0)
3684 self.assertRaises(TypeError, setattr, c, 'rounding', 'xyz')
3685
3686 # capitals, clamp
3687 for attr in ['capitals', 'clamp']:
3688 self.assertRaises(ValueError, setattr, c, attr, -1)
3689 self.assertRaises(ValueError, setattr, c, attr, 2)
3690 self.assertRaises(TypeError, setattr, c, attr, [1,2,3])
3691
3692 # Invalid attribute
3693 self.assertRaises(AttributeError, setattr, c, 'emax', 100)
3694
3695 # Invalid signal dict
3696 self.assertRaises(TypeError, setattr, c, 'flags', [])
3697 self.assertRaises(KeyError, setattr, c, 'flags', {})
3698 self.assertRaises(KeyError, setattr, c, 'traps',
3699 {'InvalidOperation':0})
3700
3701 # Attributes cannot be deleted
3702 for attr in ['prec', 'Emax', 'Emin', 'rounding', 'capitals', 'clamp',
3703 'flags', 'traps']:
3704 self.assertRaises(AttributeError, c.__delattr__, attr)
3705
3706 # Invalid attributes
3707 self.assertRaises(TypeError, getattr, c, 9)
3708 self.assertRaises(TypeError, setattr, c, 9)
3709
3710 # Invalid values in constructor
3711 self.assertRaises(TypeError, Context, rounding=999999)
3712 self.assertRaises(TypeError, Context, rounding='xyz')
3713 self.assertRaises(ValueError, Context, clamp=2)
3714 self.assertRaises(ValueError, Context, capitals=-1)
3715 self.assertRaises(KeyError, Context, flags=["P"])
3716 self.assertRaises(KeyError, Context, traps=["Q"])
3717
3718 # Type error in conversion
3719 self.assertRaises(TypeError, Context, flags=(0,1))
3720 self.assertRaises(TypeError, Context, traps=(1,0))
3721
3722class CContextInputValidation(ContextInputValidation):
3723 decimal = C
3724class PyContextInputValidation(ContextInputValidation):
3725 decimal = P
3726
3727class ContextSubclassing(unittest.TestCase):
3728
3729 def test_context_subclassing(self):
3730 decimal = self.decimal
3731 Decimal = decimal.Decimal
3732 Context = decimal.Context
3733 ROUND_HALF_EVEN = decimal.ROUND_HALF_EVEN
3734 ROUND_DOWN = decimal.ROUND_DOWN
3735 Clamped = decimal.Clamped
3736 DivisionByZero = decimal.DivisionByZero
3737 Inexact = decimal.Inexact
3738 Overflow = decimal.Overflow
3739 Rounded = decimal.Rounded
3740 Subnormal = decimal.Subnormal
3741 Underflow = decimal.Underflow
3742 InvalidOperation = decimal.InvalidOperation
3743
3744 class MyContext(Context):
3745 def __init__(self, prec=None, rounding=None, Emin=None, Emax=None,
3746 capitals=None, clamp=None, flags=None,
3747 traps=None):
3748 Context.__init__(self)
3749 if prec is not None:
3750 self.prec = prec
3751 if rounding is not None:
3752 self.rounding = rounding
3753 if Emin is not None:
3754 self.Emin = Emin
3755 if Emax is not None:
3756 self.Emax = Emax
3757 if capitals is not None:
3758 self.capitals = capitals
3759 if clamp is not None:
3760 self.clamp = clamp
3761 if flags is not None:
3762 if isinstance(flags, list):
3763 flags = {v:(v in flags) for v in OrderedSignals[decimal] + flags}
3764 self.flags = flags
3765 if traps is not None:
3766 if isinstance(traps, list):
3767 traps = {v:(v in traps) for v in OrderedSignals[decimal] + traps}
3768 self.traps = traps
3769
3770 c = Context()
3771 d = MyContext()
3772 for attr in ('prec', 'rounding', 'Emin', 'Emax', 'capitals', 'clamp',
3773 'flags', 'traps'):
3774 self.assertEqual(getattr(c, attr), getattr(d, attr))
3775
3776 # prec
3777 self.assertRaises(ValueError, MyContext, **{'prec':-1})
3778 c = MyContext(prec=1)
3779 self.assertEqual(c.prec, 1)
3780 self.assertRaises(InvalidOperation, c.quantize, Decimal('9e2'), 0)
3781
3782 # rounding
3783 self.assertRaises(TypeError, MyContext, **{'rounding':'XYZ'})
3784 c = MyContext(rounding=ROUND_DOWN, prec=1)
3785 self.assertEqual(c.rounding, ROUND_DOWN)
3786 self.assertEqual(c.plus(Decimal('9.9')), 9)
3787
3788 # Emin
3789 self.assertRaises(ValueError, MyContext, **{'Emin':5})
3790 c = MyContext(Emin=-1, prec=1)
3791 self.assertEqual(c.Emin, -1)
3792 x = c.add(Decimal('1e-99'), Decimal('2.234e-2000'))
3793 self.assertEqual(x, Decimal('0.0'))
3794 for signal in (Inexact, Underflow, Subnormal, Rounded, Clamped):
3795 self.assertTrue(c.flags[signal])
3796
3797 # Emax
3798 self.assertRaises(ValueError, MyContext, **{'Emax':-1})
3799 c = MyContext(Emax=1, prec=1)
3800 self.assertEqual(c.Emax, 1)
3801 self.assertRaises(Overflow, c.add, Decimal('1e99'), Decimal('2.234e2000'))
3802 if self.decimal == C:
3803 for signal in (Inexact, Overflow, Rounded):
3804 self.assertTrue(c.flags[signal])
3805
3806 # capitals
3807 self.assertRaises(ValueError, MyContext, **{'capitals':-1})
3808 c = MyContext(capitals=0)
3809 self.assertEqual(c.capitals, 0)
3810 x = c.create_decimal('1E222')
3811 self.assertEqual(c.to_sci_string(x), '1e+222')
3812
3813 # clamp
3814 self.assertRaises(ValueError, MyContext, **{'clamp':2})
3815 c = MyContext(clamp=1, Emax=99)
3816 self.assertEqual(c.clamp, 1)
3817 x = c.plus(Decimal('1e99'))
3818 self.assertEqual(str(x), '1.000000000000000000000000000E+99')
3819
3820 # flags
3821 self.assertRaises(TypeError, MyContext, **{'flags':'XYZ'})
3822 c = MyContext(flags=[Rounded, DivisionByZero])
3823 for signal in (Rounded, DivisionByZero):
3824 self.assertTrue(c.flags[signal])
3825 c.clear_flags()
3826 for signal in OrderedSignals[decimal]:
3827 self.assertFalse(c.flags[signal])
3828
3829 # traps
3830 self.assertRaises(TypeError, MyContext, **{'traps':'XYZ'})
3831 c = MyContext(traps=[Rounded, DivisionByZero])
3832 for signal in (Rounded, DivisionByZero):
3833 self.assertTrue(c.traps[signal])
3834 c.clear_traps()
3835 for signal in OrderedSignals[decimal]:
3836 self.assertFalse(c.traps[signal])
3837
3838class CContextSubclassing(ContextSubclassing):
3839 decimal = C
3840class PyContextSubclassing(ContextSubclassing):
3841 decimal = P
3842
3843@skip_if_extra_functionality
3844class CheckAttributes(unittest.TestCase):
3845
3846 def test_module_attributes(self):
3847
3848 # Architecture dependent context limits
3849 self.assertEqual(C.MAX_PREC, P.MAX_PREC)
3850 self.assertEqual(C.MAX_EMAX, P.MAX_EMAX)
3851 self.assertEqual(C.MIN_EMIN, P.MIN_EMIN)
3852 self.assertEqual(C.MIN_ETINY, P.MIN_ETINY)
3853
3854 self.assertTrue(C.HAVE_THREADS is True or C.HAVE_THREADS is False)
3855 self.assertTrue(P.HAVE_THREADS is True or P.HAVE_THREADS is False)
3856
3857 self.assertEqual(C.__version__, P.__version__)
3858
3859 x = dir(C)
3860 y = [s for s in dir(P) if '__' in s or not s.startswith('_')]
Stefan Krahfe17b2b2012-03-25 18:59:21 +02003861 self.assertEqual(set(x) - set(y), set())
Stefan Krah1919b7e2012-03-21 18:25:23 +01003862
3863 def test_context_attributes(self):
3864
3865 x = [s for s in dir(C.Context()) if '__' in s or not s.startswith('_')]
3866 y = [s for s in dir(P.Context()) if '__' in s or not s.startswith('_')]
3867 self.assertEqual(set(x) - set(y), set())
3868
3869 def test_decimal_attributes(self):
3870
3871 x = [s for s in dir(C.Decimal(9)) if '__' in s or not s.startswith('_')]
3872 y = [s for s in dir(C.Decimal(9)) if '__' in s or not s.startswith('_')]
3873 self.assertEqual(set(x) - set(y), set())
3874
3875class Coverage(unittest.TestCase):
3876
3877 def test_adjusted(self):
3878 Decimal = self.decimal.Decimal
3879
3880 self.assertEqual(Decimal('1234e9999').adjusted(), 10002)
3881 # XXX raise?
3882 self.assertEqual(Decimal('nan').adjusted(), 0)
3883 self.assertEqual(Decimal('inf').adjusted(), 0)
3884
3885 def test_canonical(self):
3886 Decimal = self.decimal.Decimal
3887 getcontext = self.decimal.getcontext
3888
3889 x = Decimal(9).canonical()
3890 self.assertEqual(x, 9)
3891
3892 c = getcontext()
3893 x = c.canonical(Decimal(9))
3894 self.assertEqual(x, 9)
3895
3896 def test_context_repr(self):
3897 c = self.decimal.DefaultContext.copy()
3898
3899 c.prec = 425000000
3900 c.Emax = 425000000
3901 c.Emin = -425000000
3902 c.rounding = self.decimal.ROUND_HALF_DOWN
3903 c.capitals = 0
3904 c.clamp = 1
3905 for sig in OrderedSignals[self.decimal]:
3906 c.flags[sig] = False
3907 c.traps[sig] = False
3908
3909 s = c.__repr__()
3910 t = "Context(prec=425000000, rounding=ROUND_HALF_DOWN, " \
3911 "Emin=-425000000, Emax=425000000, capitals=0, clamp=1, " \
3912 "flags=[], traps=[])"
3913 self.assertEqual(s, t)
3914
3915 def test_implicit_context(self):
3916 Decimal = self.decimal.Decimal
3917 localcontext = self.decimal.localcontext
3918
3919 with localcontext() as c:
3920 c.prec = 1
3921 c.Emax = 1
3922 c.Emin = -1
3923
3924 # abs
3925 self.assertEqual(abs(Decimal("-10")), 10)
3926 # add
3927 self.assertEqual(Decimal("7") + 1, 8)
3928 # divide
3929 self.assertEqual(Decimal("10") / 5, 2)
3930 # divide_int
3931 self.assertEqual(Decimal("10") // 7, 1)
3932 # fma
3933 self.assertEqual(Decimal("1.2").fma(Decimal("0.01"), 1), 1)
3934 self.assertIs(Decimal("NaN").fma(7, 1).is_nan(), True)
3935 # three arg power
3936 self.assertEqual(pow(Decimal(10), 2, 7), 2)
3937 # exp
3938 self.assertEqual(Decimal("1.01").exp(), 3)
3939 # is_normal
3940 self.assertIs(Decimal("0.01").is_normal(), False)
3941 # is_subnormal
3942 self.assertIs(Decimal("0.01").is_subnormal(), True)
3943 # ln
3944 self.assertEqual(Decimal("20").ln(), 3)
3945 # log10
3946 self.assertEqual(Decimal("20").log10(), 1)
3947 # logb
3948 self.assertEqual(Decimal("580").logb(), 2)
3949 # logical_invert
3950 self.assertEqual(Decimal("10").logical_invert(), 1)
3951 # minus
3952 self.assertEqual(-Decimal("-10"), 10)
3953 # multiply
3954 self.assertEqual(Decimal("2") * 4, 8)
3955 # next_minus
3956 self.assertEqual(Decimal("10").next_minus(), 9)
3957 # next_plus
3958 self.assertEqual(Decimal("10").next_plus(), Decimal('2E+1'))
3959 # normalize
3960 self.assertEqual(Decimal("-10").normalize(), Decimal('-1E+1'))
3961 # number_class
3962 self.assertEqual(Decimal("10").number_class(), '+Normal')
3963 # plus
3964 self.assertEqual(+Decimal("-1"), -1)
3965 # remainder
3966 self.assertEqual(Decimal("10") % 7, 3)
3967 # subtract
3968 self.assertEqual(Decimal("10") - 7, 3)
3969 # to_integral_exact
3970 self.assertEqual(Decimal("1.12345").to_integral_exact(), 1)
3971
3972 # Boolean functions
3973 self.assertTrue(Decimal("1").is_canonical())
3974 self.assertTrue(Decimal("1").is_finite())
3975 self.assertTrue(Decimal("1").is_finite())
3976 self.assertTrue(Decimal("snan").is_snan())
3977 self.assertTrue(Decimal("-1").is_signed())
3978 self.assertTrue(Decimal("0").is_zero())
3979 self.assertTrue(Decimal("0").is_zero())
3980
3981 # Copy
3982 with localcontext() as c:
3983 c.prec = 10000
3984 x = 1228 ** 1523
3985 y = -Decimal(x)
3986
3987 z = y.copy_abs()
3988 self.assertEqual(z, x)
3989
3990 z = y.copy_negate()
3991 self.assertEqual(z, x)
3992
3993 z = y.copy_sign(Decimal(1))
3994 self.assertEqual(z, x)
3995
3996 def test_divmod(self):
3997 Decimal = self.decimal.Decimal
3998 localcontext = self.decimal.localcontext
3999 InvalidOperation = self.decimal.InvalidOperation
4000 DivisionByZero = self.decimal.DivisionByZero
4001
4002 with localcontext() as c:
4003 q, r = divmod(Decimal("10912837129"), 1001)
4004 self.assertEqual(q, Decimal('10901935'))
4005 self.assertEqual(r, Decimal('194'))
4006
4007 q, r = divmod(Decimal("NaN"), 7)
4008 self.assertTrue(q.is_nan() and r.is_nan())
4009
4010 c.traps[InvalidOperation] = False
4011 q, r = divmod(Decimal("NaN"), 7)
4012 self.assertTrue(q.is_nan() and r.is_nan())
4013
4014 c.traps[InvalidOperation] = False
4015 c.clear_flags()
4016 q, r = divmod(Decimal("inf"), Decimal("inf"))
4017 self.assertTrue(q.is_nan() and r.is_nan())
4018 self.assertTrue(c.flags[InvalidOperation])
4019
4020 c.clear_flags()
4021 q, r = divmod(Decimal("inf"), 101)
4022 self.assertTrue(q.is_infinite() and r.is_nan())
4023 self.assertTrue(c.flags[InvalidOperation])
4024
4025 c.clear_flags()
4026 q, r = divmod(Decimal(0), 0)
4027 self.assertTrue(q.is_nan() and r.is_nan())
4028 self.assertTrue(c.flags[InvalidOperation])
4029
4030 c.traps[DivisionByZero] = False
4031 c.clear_flags()
4032 q, r = divmod(Decimal(11), 0)
4033 self.assertTrue(q.is_infinite() and r.is_nan())
4034 self.assertTrue(c.flags[InvalidOperation] and
4035 c.flags[DivisionByZero])
4036
4037 def test_power(self):
4038 Decimal = self.decimal.Decimal
4039 localcontext = self.decimal.localcontext
4040 Overflow = self.decimal.Overflow
4041 Rounded = self.decimal.Rounded
4042
4043 with localcontext() as c:
4044 c.prec = 3
4045 c.clear_flags()
4046 self.assertEqual(Decimal("1.0") ** 100, Decimal('1.00'))
4047 self.assertTrue(c.flags[Rounded])
4048
4049 c.prec = 1
4050 c.Emax = 1
4051 c.Emin = -1
4052 c.clear_flags()
4053 c.traps[Overflow] = False
4054 self.assertEqual(Decimal(10000) ** Decimal("0.5"), Decimal('inf'))
4055 self.assertTrue(c.flags[Overflow])
4056
4057 def test_quantize(self):
4058 Decimal = self.decimal.Decimal
4059 localcontext = self.decimal.localcontext
4060 InvalidOperation = self.decimal.InvalidOperation
4061
4062 with localcontext() as c:
4063 c.prec = 1
4064 c.Emax = 1
4065 c.Emin = -1
4066 c.traps[InvalidOperation] = False
4067 x = Decimal(99).quantize(Decimal("1e1"))
4068 self.assertTrue(x.is_nan())
4069
4070 def test_radix(self):
4071 Decimal = self.decimal.Decimal
4072 getcontext = self.decimal.getcontext
4073
4074 c = getcontext()
4075 self.assertEqual(Decimal("1").radix(), 10)
4076 self.assertEqual(c.radix(), 10)
4077
4078 def test_rop(self):
4079 Decimal = self.decimal.Decimal
4080
4081 for attr in ('__radd__', '__rsub__', '__rmul__', '__rtruediv__',
4082 '__rdivmod__', '__rmod__', '__rfloordiv__', '__rpow__'):
4083 self.assertIs(getattr(Decimal("1"), attr)("xyz"), NotImplemented)
4084
4085 def test_round(self):
4086 # Python3 behavior: round() returns Decimal
4087 Decimal = self.decimal.Decimal
4088 getcontext = self.decimal.getcontext
4089
4090 c = getcontext()
4091 c.prec = 28
4092
4093 self.assertEqual(str(Decimal("9.99").__round__()), "10")
4094 self.assertEqual(str(Decimal("9.99e-5").__round__()), "0")
4095 self.assertEqual(str(Decimal("1.23456789").__round__(5)), "1.23457")
4096 self.assertEqual(str(Decimal("1.2345").__round__(10)), "1.2345000000")
4097 self.assertEqual(str(Decimal("1.2345").__round__(-10)), "0E+10")
4098
4099 self.assertRaises(TypeError, Decimal("1.23").__round__, "5")
4100 self.assertRaises(TypeError, Decimal("1.23").__round__, 5, 8)
4101
4102 def test_create_decimal(self):
4103 c = self.decimal.Context()
4104 self.assertRaises(ValueError, c.create_decimal, ["%"])
4105
4106 def test_int(self):
4107 Decimal = self.decimal.Decimal
4108 localcontext = self.decimal.localcontext
4109
4110 with localcontext() as c:
4111 c.prec = 9999
4112 x = Decimal(1221**1271) / 10**3923
4113 self.assertEqual(int(x), 1)
4114 self.assertEqual(x.to_integral(), 2)
4115
4116 def test_copy(self):
4117 Context = self.decimal.Context
4118
4119 c = Context()
4120 c.prec = 10000
4121 x = -(1172 ** 1712)
4122
4123 y = c.copy_abs(x)
4124 self.assertEqual(y, -x)
4125
4126 y = c.copy_negate(x)
4127 self.assertEqual(y, -x)
4128
4129 y = c.copy_sign(x, 1)
4130 self.assertEqual(y, -x)
4131
4132class CCoverage(Coverage):
4133 decimal = C
4134class PyCoverage(Coverage):
4135 decimal = P
4136
4137class PyFunctionality(unittest.TestCase):
4138 """Extra functionality in decimal.py"""
4139
4140 def test_py_quantize_watchexp(self):
4141 # watchexp functionality
4142 Decimal = P.Decimal
4143 localcontext = P.localcontext
4144
4145 with localcontext() as c:
4146 c.prec = 1
4147 c.Emax = 1
4148 c.Emin = -1
4149 x = Decimal(99999).quantize(Decimal("1e3"), watchexp=False)
4150 self.assertEqual(x, Decimal('1.00E+5'))
4151
4152 def test_py_alternate_formatting(self):
4153 # triples giving a format, a Decimal, and the expected result
4154 Decimal = P.Decimal
4155 localcontext = P.localcontext
4156
4157 test_values = [
4158 # Issue 7094: Alternate formatting (specified by #)
4159 ('.0e', '1.0', '1e+0'),
4160 ('#.0e', '1.0', '1.e+0'),
4161 ('.0f', '1.0', '1'),
4162 ('#.0f', '1.0', '1.'),
4163 ('g', '1.1', '1.1'),
4164 ('#g', '1.1', '1.1'),
4165 ('.0g', '1', '1'),
4166 ('#.0g', '1', '1.'),
4167 ('.0%', '1.0', '100%'),
4168 ('#.0%', '1.0', '100.%'),
4169 ]
4170 for fmt, d, result in test_values:
4171 self.assertEqual(format(Decimal(d), fmt), result)
4172
4173class PyWhitebox(unittest.TestCase):
4174 """White box testing for decimal.py"""
4175
4176 def test_py_exact_power(self):
4177 # Rarely exercised lines in _power_exact.
4178 Decimal = P.Decimal
4179 localcontext = P.localcontext
4180
4181 with localcontext() as c:
4182 c.prec = 8
4183 x = Decimal(2**16) ** Decimal("-0.5")
4184 self.assertEqual(x, Decimal('0.00390625'))
4185
4186 x = Decimal(2**16) ** Decimal("-0.6")
4187 self.assertEqual(x, Decimal('0.0012885819'))
4188
4189 x = Decimal("256e7") ** Decimal("-0.5")
4190
4191 x = Decimal(152587890625) ** Decimal('-0.0625')
4192 self.assertEqual(x, Decimal("0.2"))
4193
4194 x = Decimal("152587890625e7") ** Decimal('-0.0625')
4195
4196 x = Decimal(5**2659) ** Decimal('-0.0625')
4197
4198 c.prec = 1
4199 x = Decimal("152587890625") ** Decimal('-0.5')
4200 c.prec = 201
4201 x = Decimal(2**578) ** Decimal("-0.5")
4202
4203 def test_py_immutability_operations(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004204 # Do operations and check that it didn't change change internal objects.
Stefan Krah1919b7e2012-03-21 18:25:23 +01004205 Decimal = P.Decimal
4206 DefaultContext = P.DefaultContext
4207 setcontext = P.setcontext
4208
4209 c = DefaultContext.copy()
4210 c.traps = dict((s, 0) for s in OrderedSignals[P])
4211 setcontext(c)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004212
4213 d1 = Decimal('-25e55')
4214 b1 = Decimal('-25e55')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004215 d2 = Decimal('33e+33')
4216 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004217
4218 def checkSameDec(operation, useOther=False):
4219 if useOther:
4220 eval("d1." + operation + "(d2)")
4221 self.assertEqual(d1._sign, b1._sign)
4222 self.assertEqual(d1._int, b1._int)
4223 self.assertEqual(d1._exp, b1._exp)
4224 self.assertEqual(d2._sign, b2._sign)
4225 self.assertEqual(d2._int, b2._int)
4226 self.assertEqual(d2._exp, b2._exp)
4227 else:
4228 eval("d1." + operation + "()")
4229 self.assertEqual(d1._sign, b1._sign)
4230 self.assertEqual(d1._int, b1._int)
4231 self.assertEqual(d1._exp, b1._exp)
4232 return
4233
4234 Decimal(d1)
4235 self.assertEqual(d1._sign, b1._sign)
4236 self.assertEqual(d1._int, b1._int)
4237 self.assertEqual(d1._exp, b1._exp)
4238
4239 checkSameDec("__abs__")
4240 checkSameDec("__add__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004241 checkSameDec("__divmod__", True)
Christian Heimes77c02eb2008-02-09 02:18:51 +00004242 checkSameDec("__eq__", True)
4243 checkSameDec("__ne__", True)
4244 checkSameDec("__le__", True)
4245 checkSameDec("__lt__", True)
4246 checkSameDec("__ge__", True)
4247 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004248 checkSameDec("__float__")
4249 checkSameDec("__floordiv__", True)
4250 checkSameDec("__hash__")
4251 checkSameDec("__int__")
Christian Heimes969fe572008-01-25 11:23:10 +00004252 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004253 checkSameDec("__mod__", True)
4254 checkSameDec("__mul__", True)
4255 checkSameDec("__neg__")
Jack Diederich4dafcc42006-11-28 19:15:13 +00004256 checkSameDec("__bool__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004257 checkSameDec("__pos__")
4258 checkSameDec("__pow__", True)
4259 checkSameDec("__radd__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004260 checkSameDec("__rdivmod__", True)
4261 checkSameDec("__repr__")
4262 checkSameDec("__rfloordiv__", True)
4263 checkSameDec("__rmod__", True)
4264 checkSameDec("__rmul__", True)
4265 checkSameDec("__rpow__", True)
4266 checkSameDec("__rsub__", True)
4267 checkSameDec("__str__")
4268 checkSameDec("__sub__", True)
4269 checkSameDec("__truediv__", True)
4270 checkSameDec("adjusted")
4271 checkSameDec("as_tuple")
4272 checkSameDec("compare", True)
4273 checkSameDec("max", True)
4274 checkSameDec("min", True)
4275 checkSameDec("normalize")
4276 checkSameDec("quantize", True)
4277 checkSameDec("remainder_near", True)
4278 checkSameDec("same_quantum", True)
4279 checkSameDec("sqrt")
4280 checkSameDec("to_eng_string")
4281 checkSameDec("to_integral")
4282
Stefan Krah1919b7e2012-03-21 18:25:23 +01004283 def test_py_decimal_id(self):
4284 Decimal = P.Decimal
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004285
Stefan Krah1919b7e2012-03-21 18:25:23 +01004286 d = Decimal(45)
4287 e = Decimal(d)
4288 self.assertEqual(str(e), '45')
4289 self.assertNotEqual(id(d), id(e))
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004290
Stefan Krah1919b7e2012-03-21 18:25:23 +01004291 def test_py_rescale(self):
4292 # Coverage
4293 Decimal = P.Decimal
4294 ROUND_UP = P.ROUND_UP
4295 localcontext = P.localcontext
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004296
Stefan Krah1919b7e2012-03-21 18:25:23 +01004297 with localcontext() as c:
4298 x = Decimal("NaN")._rescale(3, ROUND_UP)
4299 self.assertTrue(x.is_nan())
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004300
Stefan Krah1919b7e2012-03-21 18:25:23 +01004301 def test_py__round(self):
4302 # Coverage
4303 Decimal = P.Decimal
4304 ROUND_UP = P.ROUND_UP
Christian Heimes0348fb62008-03-26 12:55:56 +00004305
Stefan Krah1919b7e2012-03-21 18:25:23 +01004306 self.assertRaises(ValueError, Decimal("3.1234")._round, 0, ROUND_UP)
Mark Dickinsona2d1fe02009-10-29 12:23:02 +00004307
Stefan Krah1919b7e2012-03-21 18:25:23 +01004308class CFunctionality(unittest.TestCase):
4309 """Extra functionality in _decimal"""
Mark Dickinsona2d1fe02009-10-29 12:23:02 +00004310
Stefan Krah1919b7e2012-03-21 18:25:23 +01004311 @requires_extra_functionality
4312 def test_c_ieee_context(self):
4313 # issue 8786: Add support for IEEE 754 contexts to decimal module.
4314 IEEEContext = C.IEEEContext
4315 DECIMAL32 = C.DECIMAL32
4316 DECIMAL64 = C.DECIMAL64
4317 DECIMAL128 = C.DECIMAL128
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004318
Stefan Krah1919b7e2012-03-21 18:25:23 +01004319 def assert_rest(self, context):
4320 self.assertEqual(context.clamp, 1)
4321 assert_signals(self, context, 'traps', [])
4322 assert_signals(self, context, 'flags', [])
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004323
Stefan Krah1919b7e2012-03-21 18:25:23 +01004324 c = IEEEContext(DECIMAL32)
4325 self.assertEqual(c.prec, 7)
4326 self.assertEqual(c.Emax, 96)
4327 self.assertEqual(c.Emin, -95)
4328 assert_rest(self, c)
Raymond Hettinger82417ca2009-02-03 03:54:28 +00004329
Stefan Krah1919b7e2012-03-21 18:25:23 +01004330 c = IEEEContext(DECIMAL64)
4331 self.assertEqual(c.prec, 16)
4332 self.assertEqual(c.Emax, 384)
4333 self.assertEqual(c.Emin, -383)
4334 assert_rest(self, c)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004335
Stefan Krah1919b7e2012-03-21 18:25:23 +01004336 c = IEEEContext(DECIMAL128)
4337 self.assertEqual(c.prec, 34)
4338 self.assertEqual(c.Emax, 6144)
4339 self.assertEqual(c.Emin, -6143)
4340 assert_rest(self, c)
Raymond Hettinger5548be22004-07-05 18:49:38 +00004341
Stefan Krah1919b7e2012-03-21 18:25:23 +01004342 # Invalid values
4343 self.assertRaises(OverflowError, IEEEContext, 2**63)
4344 self.assertRaises(ValueError, IEEEContext, -1)
4345 self.assertRaises(ValueError, IEEEContext, 1024)
Mark Dickinson825fce32009-09-07 18:08:12 +00004346
Stefan Krah1919b7e2012-03-21 18:25:23 +01004347 @requires_extra_functionality
4348 def test_c_context(self):
4349 Context = C.Context
Christian Heimes969fe572008-01-25 11:23:10 +00004350
Stefan Krah1919b7e2012-03-21 18:25:23 +01004351 c = Context(flags=C.DecClamped, traps=C.DecRounded)
4352 self.assertEqual(c._flags, C.DecClamped)
4353 self.assertEqual(c._traps, C.DecRounded)
Raymond Hettinger771ed762009-01-03 19:20:32 +00004354
Stefan Krah1919b7e2012-03-21 18:25:23 +01004355 @requires_extra_functionality
4356 def test_constants(self):
4357 # Condition flags
4358 cond = (
4359 C.DecClamped, C.DecConversionSyntax, C.DecDivisionByZero,
4360 C.DecDivisionImpossible, C.DecDivisionUndefined,
4361 C.DecFpuError, C.DecInexact, C.DecInvalidContext,
4362 C.DecInvalidOperation, C.DecMallocError,
4363 C.DecFloatOperation, C.DecOverflow, C.DecRounded,
4364 C.DecSubnormal, C.DecUnderflow
Raymond Hettinger771ed762009-01-03 19:20:32 +00004365 )
Stefan Krah1919b7e2012-03-21 18:25:23 +01004366
4367 # IEEEContext
4368 self.assertEqual(C.DECIMAL32, 32)
4369 self.assertEqual(C.DECIMAL64, 64)
4370 self.assertEqual(C.DECIMAL128, 128)
4371 self.assertEqual(C.IEEE_CONTEXT_MAX_BITS, 512)
4372
4373 # Rounding modes
4374 for i, v in enumerate(RoundingModes[C]):
4375 self.assertEqual(v, i)
4376 self.assertEqual(C.ROUND_TRUNC, 8)
4377
4378 # Conditions
4379 for i, v in enumerate(cond):
4380 self.assertEqual(v, 1<<i)
4381
4382 self.assertEqual(C.DecIEEEInvalidOperation,
4383 C.DecConversionSyntax|
4384 C.DecDivisionImpossible|
4385 C.DecDivisionUndefined|
4386 C.DecFpuError|
4387 C.DecInvalidContext|
4388 C.DecInvalidOperation|
4389 C.DecMallocError)
4390
4391 self.assertEqual(C.DecErrors,
4392 C.DecIEEEInvalidOperation|
4393 C.DecDivisionByZero)
4394
4395 self.assertEqual(C.DecTraps,
4396 C.DecErrors|C.DecOverflow|C.DecUnderflow)
4397
4398class CWhitebox(unittest.TestCase):
4399 """Whitebox testing for _decimal"""
4400
4401 def test_bignum(self):
4402 # Not exactly whitebox, but too slow with pydecimal.
4403
4404 Decimal = C.Decimal
4405 localcontext = C.localcontext
4406
4407 b1 = 10**35
4408 b2 = 10**36
4409 with localcontext() as c:
4410 c.prec = 1000000
4411 for i in range(5):
4412 a = random.randrange(b1, b2)
4413 b = random.randrange(1000, 1200)
4414 x = a ** b
4415 y = Decimal(a) ** Decimal(b)
4416 self.assertEqual(x, y)
4417
4418 def test_invalid_construction(self):
4419 self.assertRaises(TypeError, C.Decimal, 9, "xyz")
4420
4421 def test_c_input_restriction(self):
4422 # Too large for _decimal to be converted exactly
4423 Decimal = C.Decimal
4424 InvalidOperation = C.InvalidOperation
4425 Context = C.Context
4426 localcontext = C.localcontext
4427
4428 with localcontext(Context()):
4429 self.assertRaises(InvalidOperation, Decimal,
4430 "1e9999999999999999999")
4431
4432 def test_c_context_repr(self):
4433 # This test is _decimal-only because flags are not printed
4434 # in the same order.
4435 DefaultContext = C.DefaultContext
4436 FloatOperation = C.FloatOperation
4437 ROUND_HALF_DOWN = C.ROUND_HALF_DOWN
4438
4439 c = DefaultContext.copy()
4440
4441 c.prec = 425000000
4442 c.Emax = 425000000
4443 c.Emin = -425000000
4444 c.rounding = ROUND_HALF_DOWN
4445 c.capitals = 0
4446 c.clamp = 1
4447 for sig in OrderedSignals[C]:
4448 c.flags[sig] = True
4449 c.traps[sig] = True
4450 c.flags[FloatOperation] = True
4451 c.traps[FloatOperation] = True
4452
4453 s = c.__repr__()
4454 t = "Context(prec=425000000, rounding=ROUND_HALF_DOWN, " \
4455 "Emin=-425000000, Emax=425000000, capitals=0, clamp=1, " \
4456 "flags=[Clamped, InvalidOperation, DivisionByZero, Inexact, " \
4457 "FloatOperation, Overflow, Rounded, Subnormal, Underflow], " \
4458 "traps=[Clamped, InvalidOperation, DivisionByZero, Inexact, " \
4459 "FloatOperation, Overflow, Rounded, Subnormal, Underflow])"
4460 self.assertEqual(s, t)
4461
4462 def test_c_context_errors(self):
4463 Context = C.Context
4464 InvalidOperation = C.InvalidOperation
4465 Overflow = C.Overflow
4466 FloatOperation = C.FloatOperation
4467 localcontext = C.localcontext
4468 getcontext = C.getcontext
4469 setcontext = C.setcontext
4470 HAVE_CONFIG_64 = (C.MAX_PREC > 425000000)
4471
4472 c = Context()
4473
4474 # SignalDict: input validation
4475 self.assertRaises(KeyError, c.flags.__setitem__, 801, 0)
4476 self.assertRaises(KeyError, c.traps.__setitem__, 801, 0)
4477 self.assertRaises(ValueError, c.flags.__delitem__, Overflow)
4478 self.assertRaises(ValueError, c.traps.__delitem__, InvalidOperation)
4479 self.assertRaises(TypeError, setattr, c, 'flags', ['x'])
4480 self.assertRaises(TypeError, setattr, c,'traps', ['y'])
4481 self.assertRaises(KeyError, setattr, c, 'flags', {0:1})
4482 self.assertRaises(KeyError, setattr, c, 'traps', {0:1})
4483
4484 # Test assignment from a signal dict with the correct length but
4485 # one invalid key.
4486 d = c.flags.copy()
4487 del d[FloatOperation]
4488 d["XYZ"] = 91283719
4489 self.assertRaises(KeyError, setattr, c, 'flags', d)
4490 self.assertRaises(KeyError, setattr, c, 'traps', d)
4491
4492 # Input corner cases
4493 int_max = 2**63-1 if HAVE_CONFIG_64 else 2**31-1
4494 gt_max_emax = 10**18 if HAVE_CONFIG_64 else 10**9
4495
4496 # prec, Emax, Emin
4497 for attr in ['prec', 'Emax']:
4498 self.assertRaises(ValueError, setattr, c, attr, gt_max_emax)
4499 self.assertRaises(ValueError, setattr, c, 'Emin', -gt_max_emax)
4500
4501 # prec, Emax, Emin in context constructor
4502 self.assertRaises(ValueError, Context, prec=gt_max_emax)
4503 self.assertRaises(ValueError, Context, Emax=gt_max_emax)
4504 self.assertRaises(ValueError, Context, Emin=-gt_max_emax)
4505
4506 # Overflow in conversion
4507 self.assertRaises(OverflowError, Context, prec=int_max+1)
4508 self.assertRaises(OverflowError, Context, Emax=int_max+1)
4509 self.assertRaises(OverflowError, Context, Emin=-int_max-2)
4510 self.assertRaises(OverflowError, Context, rounding=int_max+1)
4511 self.assertRaises(OverflowError, Context, clamp=int_max+1)
4512 self.assertRaises(OverflowError, Context, capitals=int_max+1)
4513
4514 # OverflowError, general ValueError
4515 for attr in ('prec', 'Emin', 'Emax', 'capitals', 'clamp'):
4516 self.assertRaises(OverflowError, setattr, c, attr, int_max+1)
4517 self.assertRaises(OverflowError, setattr, c, attr, -int_max-2)
4518 if sys.platform != 'win32':
4519 self.assertRaises(ValueError, setattr, c, attr, int_max)
4520 self.assertRaises(ValueError, setattr, c, attr, -int_max-1)
4521
4522 # OverflowError, general TypeError
4523 for attr in ('rounding',):
4524 self.assertRaises(OverflowError, setattr, c, attr, int_max+1)
4525 self.assertRaises(OverflowError, setattr, c, attr, -int_max-2)
4526 if sys.platform != 'win32':
4527 self.assertRaises(TypeError, setattr, c, attr, int_max)
4528 self.assertRaises(TypeError, setattr, c, attr, -int_max-1)
4529
4530 # OverflowError: _unsafe_setprec, _unsafe_setemin, _unsafe_setemax
4531 if C.MAX_PREC == 425000000:
4532 self.assertRaises(OverflowError, getattr(c, '_unsafe_setprec'),
4533 int_max+1)
4534 self.assertRaises(OverflowError, getattr(c, '_unsafe_setemax'),
4535 int_max+1)
4536 self.assertRaises(OverflowError, getattr(c, '_unsafe_setemin'),
4537 -int_max-2)
4538
4539 # ValueError: _unsafe_setprec, _unsafe_setemin, _unsafe_setemax
4540 if C.MAX_PREC == 425000000:
4541 self.assertRaises(ValueError, getattr(c, '_unsafe_setprec'), 0)
4542 self.assertRaises(ValueError, getattr(c, '_unsafe_setprec'),
4543 1070000001)
4544 self.assertRaises(ValueError, getattr(c, '_unsafe_setemax'), -1)
4545 self.assertRaises(ValueError, getattr(c, '_unsafe_setemax'),
4546 1070000001)
4547 self.assertRaises(ValueError, getattr(c, '_unsafe_setemin'),
4548 -1070000001)
4549 self.assertRaises(ValueError, getattr(c, '_unsafe_setemin'), 1)
4550
4551 # capitals, clamp
4552 for attr in ['capitals', 'clamp']:
4553 self.assertRaises(ValueError, setattr, c, attr, -1)
4554 self.assertRaises(ValueError, setattr, c, attr, 2)
4555 self.assertRaises(TypeError, setattr, c, attr, [1,2,3])
4556 if HAVE_CONFIG_64:
4557 self.assertRaises(ValueError, setattr, c, attr, 2**32)
4558 self.assertRaises(ValueError, setattr, c, attr, 2**32+1)
4559
4560 # Invalid local context
4561 self.assertRaises(TypeError, exec, 'with localcontext("xyz"): pass',
4562 locals())
4563
4564 # setcontext
4565 saved_context = getcontext()
4566 self.assertRaises(TypeError, setcontext, "xyz")
4567 setcontext(saved_context)
4568
4569 @requires_extra_functionality
4570 def test_c_context_errors_extra(self):
4571 Context = C.Context
4572 InvalidOperation = C.InvalidOperation
4573 Overflow = C.Overflow
4574 localcontext = C.localcontext
4575 getcontext = C.getcontext
4576 setcontext = C.setcontext
4577 HAVE_CONFIG_64 = (C.MAX_PREC > 425000000)
4578
4579 c = Context()
4580
4581 # Input corner cases
4582 int_max = 2**63-1 if HAVE_CONFIG_64 else 2**31-1
4583
4584 # OverflowError, general ValueError
4585 self.assertRaises(OverflowError, setattr, c, '_allcr', int_max+1)
4586 self.assertRaises(OverflowError, setattr, c, '_allcr', -int_max-2)
4587 if sys.platform != 'win32':
4588 self.assertRaises(ValueError, setattr, c, '_allcr', int_max)
4589 self.assertRaises(ValueError, setattr, c, '_allcr', -int_max-1)
4590
4591 # OverflowError, general TypeError
4592 for attr in ('_flags', '_traps'):
4593 self.assertRaises(OverflowError, setattr, c, attr, int_max+1)
4594 self.assertRaises(OverflowError, setattr, c, attr, -int_max-2)
4595 if sys.platform != 'win32':
4596 self.assertRaises(TypeError, setattr, c, attr, int_max)
4597 self.assertRaises(TypeError, setattr, c, attr, -int_max-1)
4598
4599 # _allcr
4600 self.assertRaises(ValueError, setattr, c, '_allcr', -1)
4601 self.assertRaises(ValueError, setattr, c, '_allcr', 2)
4602 self.assertRaises(TypeError, setattr, c, '_allcr', [1,2,3])
4603 if HAVE_CONFIG_64:
4604 self.assertRaises(ValueError, setattr, c, '_allcr', 2**32)
4605 self.assertRaises(ValueError, setattr, c, '_allcr', 2**32+1)
4606
4607 # _flags, _traps
4608 for attr in ['_flags', '_traps']:
4609 self.assertRaises(TypeError, setattr, c, attr, 999999)
4610 self.assertRaises(TypeError, setattr, c, attr, 'x')
4611
4612 def test_c_valid_context(self):
4613 # These tests are for code coverage in _decimal.
4614 DefaultContext = C.DefaultContext
4615 ROUND_HALF_UP = C.ROUND_HALF_UP
4616 Clamped = C.Clamped
4617 Underflow = C.Underflow
4618 Inexact = C.Inexact
4619 Rounded = C.Rounded
4620 Subnormal = C.Subnormal
4621
4622 c = DefaultContext.copy()
4623
4624 # Exercise all getters and setters
4625 c.prec = 34
4626 c.rounding = ROUND_HALF_UP
4627 c.Emax = 3000
4628 c.Emin = -3000
4629 c.capitals = 1
4630 c.clamp = 0
4631
4632 self.assertEqual(c.prec, 34)
4633 self.assertEqual(c.rounding, ROUND_HALF_UP)
4634 self.assertEqual(c.Emin, -3000)
4635 self.assertEqual(c.Emax, 3000)
4636 self.assertEqual(c.capitals, 1)
4637 self.assertEqual(c.clamp, 0)
4638
4639 self.assertEqual(c.Etiny(), -3033)
4640 self.assertEqual(c.Etop(), 2967)
4641
4642 # Exercise all unsafe setters
4643 if C.MAX_PREC == 425000000:
4644 c._unsafe_setprec(999999999)
4645 c._unsafe_setemax(999999999)
4646 c._unsafe_setemin(-999999999)
4647 self.assertEqual(c.prec, 999999999)
4648 self.assertEqual(c.Emax, 999999999)
4649 self.assertEqual(c.Emin, -999999999)
4650
4651 @requires_extra_functionality
4652 def test_c_valid_context_extra(self):
4653 DefaultContext = C.DefaultContext
4654
4655 c = DefaultContext.copy()
4656 self.assertEqual(c._allcr, 1)
4657 c._allcr = 0
4658 self.assertEqual(c._allcr, 0)
4659
4660 def test_c_round(self):
4661 # Restricted input.
4662 Decimal = C.Decimal
4663 InvalidOperation = C.InvalidOperation
4664 localcontext = C.localcontext
4665 MAX_EMAX = C.MAX_EMAX
4666 MIN_ETINY = C.MIN_ETINY
4667 int_max = 2**63-1 if C.MAX_PREC > 425000000 else 2**31-1
4668
4669 with localcontext() as c:
4670 c.traps[InvalidOperation] = True
4671 self.assertRaises(InvalidOperation, Decimal("1.23").__round__,
4672 -int_max-1)
4673 self.assertRaises(InvalidOperation, Decimal("1.23").__round__,
4674 int_max)
4675 self.assertRaises(InvalidOperation, Decimal("1").__round__,
4676 int(MAX_EMAX+1))
4677 self.assertRaises(C.InvalidOperation, Decimal("1").__round__,
4678 -int(MIN_ETINY-1))
4679 self.assertRaises(OverflowError, Decimal("1.23").__round__,
4680 -int_max-2)
4681 self.assertRaises(OverflowError, Decimal("1.23").__round__,
4682 int_max+1)
4683
4684 def test_c_format(self):
4685 # Restricted input
4686 Decimal = C.Decimal
4687 InvalidOperation = C.InvalidOperation
4688 Rounded = C.Rounded
4689 localcontext = C.localcontext
4690 HAVE_CONFIG_64 = (C.MAX_PREC > 425000000)
4691
4692 self.assertRaises(TypeError, Decimal(1).__format__, "=10.10", [], 9)
4693 self.assertRaises(TypeError, Decimal(1).__format__, "=10.10", 9)
4694 self.assertRaises(TypeError, Decimal(1).__format__, [])
4695
4696 with localcontext() as c:
4697 c.traps[InvalidOperation] = True
4698 c.traps[Rounded] = True
4699 self.assertRaises(ValueError, Decimal(1).__format__, "<>=10.10")
4700 maxsize = 2**63-1 if HAVE_CONFIG_64 else 2**31-1
4701 self.assertRaises(InvalidOperation, Decimal("1.23456789").__format__,
4702 "=%d.1" % maxsize)
4703
4704 def test_c_integral(self):
4705 Decimal = C.Decimal
4706 Inexact = C.Inexact
4707 ROUND_UP = C.ROUND_UP
4708 localcontext = C.localcontext
4709
4710 x = Decimal(10)
4711 self.assertEqual(x.to_integral(), 10)
4712 self.assertRaises(TypeError, x.to_integral, '10')
4713 self.assertRaises(TypeError, x.to_integral, 10, 'x')
4714 self.assertRaises(TypeError, x.to_integral, 10)
4715
4716 self.assertEqual(x.to_integral_value(), 10)
4717 self.assertRaises(TypeError, x.to_integral_value, '10')
4718 self.assertRaises(TypeError, x.to_integral_value, 10, 'x')
4719 self.assertRaises(TypeError, x.to_integral_value, 10)
4720
4721 self.assertEqual(x.to_integral_exact(), 10)
4722 self.assertRaises(TypeError, x.to_integral_exact, '10')
4723 self.assertRaises(TypeError, x.to_integral_exact, 10, 'x')
4724 self.assertRaises(TypeError, x.to_integral_exact, 10)
4725
4726 with localcontext() as c:
4727 x = Decimal("99999999999999999999999999.9").to_integral_value(ROUND_UP)
4728 self.assertEqual(x, Decimal('100000000000000000000000000'))
4729
4730 x = Decimal("99999999999999999999999999.9").to_integral_exact(ROUND_UP)
4731 self.assertEqual(x, Decimal('100000000000000000000000000'))
4732
4733 c.traps[Inexact] = True
4734 self.assertRaises(Inexact, Decimal("999.9").to_integral_exact, ROUND_UP)
4735
4736 def test_c_funcs(self):
4737 # Invalid arguments
4738 Decimal = C.Decimal
4739 InvalidOperation = C.InvalidOperation
4740 DivisionByZero = C.DivisionByZero
4741 ROUND_UP = C.ROUND_UP
4742 getcontext = C.getcontext
4743 localcontext = C.localcontext
4744
4745 self.assertEqual(Decimal('9.99e10').to_eng_string(), '99.9E+9')
4746
4747 self.assertRaises(TypeError, pow, Decimal(1), 2, "3")
4748 self.assertRaises(TypeError, Decimal(9).number_class, "x", "y")
4749 self.assertRaises(TypeError, Decimal(9).same_quantum, 3, "x", "y")
4750
Raymond Hettinger771ed762009-01-03 19:20:32 +00004751 self.assertRaises(
Stefan Krah1919b7e2012-03-21 18:25:23 +01004752 TypeError,
4753 Decimal("1.23456789").quantize, Decimal('1e-100000'), []
Raymond Hettinger771ed762009-01-03 19:20:32 +00004754 )
Stefan Krah1919b7e2012-03-21 18:25:23 +01004755 self.assertRaises(
4756 TypeError,
4757 Decimal("1.23456789").quantize, Decimal('1e-100000'), getcontext()
4758 )
4759 self.assertRaises(
4760 TypeError,
4761 Decimal("1.23456789").quantize, Decimal('1e-100000'), 10
4762 )
4763 self.assertRaises(
4764 TypeError,
4765 Decimal("1.23456789").quantize, Decimal('1e-100000'), ROUND_UP, 1000
4766 )
Raymond Hettinger771ed762009-01-03 19:20:32 +00004767
Stefan Krah1919b7e2012-03-21 18:25:23 +01004768 with localcontext() as c:
4769 c.clear_traps()
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00004770
Stefan Krah1919b7e2012-03-21 18:25:23 +01004771 # Invalid arguments
4772 self.assertRaises(TypeError, c.copy_sign, Decimal(1), "x", "y")
4773 self.assertRaises(TypeError, c.canonical, 200)
4774 self.assertRaises(TypeError, c.is_canonical, 200)
4775 self.assertRaises(TypeError, c.divmod, 9, 8, "x", "y")
4776 self.assertRaises(TypeError, c.same_quantum, 9, 3, "x", "y")
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00004777
Stefan Krah1919b7e2012-03-21 18:25:23 +01004778 self.assertEqual(str(c.canonical(Decimal(200))), '200')
4779 self.assertEqual(c.radix(), 10)
Raymond Hettinger0aeac102004-07-05 22:53:03 +00004780
Stefan Krah1919b7e2012-03-21 18:25:23 +01004781 c.traps[DivisionByZero] = True
4782 self.assertRaises(DivisionByZero, Decimal(9).__divmod__, 0)
4783 self.assertRaises(DivisionByZero, c.divmod, 9, 0)
4784 self.assertTrue(c.flags[InvalidOperation])
Raymond Hettinger955d2b22004-08-08 20:17:45 +00004785
Stefan Krah1919b7e2012-03-21 18:25:23 +01004786 c.clear_flags()
4787 c.traps[InvalidOperation] = True
4788 self.assertRaises(InvalidOperation, Decimal(9).__divmod__, 0)
4789 self.assertRaises(InvalidOperation, c.divmod, 9, 0)
4790 self.assertTrue(c.flags[DivisionByZero])
Mark Dickinsonb1d8e322010-05-22 18:35:36 +00004791
Stefan Krah1919b7e2012-03-21 18:25:23 +01004792 c.traps[InvalidOperation] = True
4793 c.prec = 2
4794 self.assertRaises(InvalidOperation, pow, Decimal(1000), 1, 501)
Mark Dickinson84230a12010-02-18 14:49:50 +00004795
Stefan Krah1919b7e2012-03-21 18:25:23 +01004796 @requires_extra_functionality
4797 def test_c_context_templates(self):
4798 self.assertEqual(
4799 C.BasicContext._traps,
4800 C.DecIEEEInvalidOperation|C.DecDivisionByZero|C.DecOverflow|
4801 C.DecUnderflow|C.DecClamped
4802 )
4803 self.assertEqual(
4804 C.DefaultContext._traps,
4805 C.DecIEEEInvalidOperation|C.DecDivisionByZero|C.DecOverflow
4806 )
Mark Dickinson84230a12010-02-18 14:49:50 +00004807
Stefan Krah1919b7e2012-03-21 18:25:23 +01004808 @requires_extra_functionality
4809 def test_c_signal_dict(self):
Mark Dickinson84230a12010-02-18 14:49:50 +00004810
Stefan Krah1919b7e2012-03-21 18:25:23 +01004811 # SignalDict coverage
4812 Context = C.Context
4813 DefaultContext = C.DefaultContext
Mark Dickinson84230a12010-02-18 14:49:50 +00004814
Stefan Krah1919b7e2012-03-21 18:25:23 +01004815 InvalidOperation = C.InvalidOperation
4816 DivisionByZero = C.DivisionByZero
4817 Overflow = C.Overflow
4818 Subnormal = C.Subnormal
4819 Underflow = C.Underflow
4820 Rounded = C.Rounded
4821 Inexact = C.Inexact
4822 Clamped = C.Clamped
Mark Dickinson84230a12010-02-18 14:49:50 +00004823
Stefan Krah1919b7e2012-03-21 18:25:23 +01004824 DecClamped = C.DecClamped
4825 DecInvalidOperation = C.DecInvalidOperation
4826 DecIEEEInvalidOperation = C.DecIEEEInvalidOperation
Mark Dickinson84230a12010-02-18 14:49:50 +00004827
Stefan Krah1919b7e2012-03-21 18:25:23 +01004828 def assertIsExclusivelySet(signal, signal_dict):
4829 for sig in signal_dict:
4830 if sig == signal:
4831 self.assertTrue(signal_dict[sig])
4832 else:
4833 self.assertFalse(signal_dict[sig])
Mark Dickinson84230a12010-02-18 14:49:50 +00004834
Stefan Krah1919b7e2012-03-21 18:25:23 +01004835 c = DefaultContext.copy()
Mark Dickinson84230a12010-02-18 14:49:50 +00004836
Stefan Krah1919b7e2012-03-21 18:25:23 +01004837 # Signal dict methods
4838 self.assertTrue(Overflow in c.traps)
4839 c.clear_traps()
4840 for k in c.traps.keys():
4841 c.traps[k] = True
4842 for v in c.traps.values():
4843 self.assertTrue(v)
4844 c.clear_traps()
4845 for k, v in c.traps.items():
4846 self.assertFalse(v)
Mark Dickinson84230a12010-02-18 14:49:50 +00004847
Stefan Krah1919b7e2012-03-21 18:25:23 +01004848 self.assertFalse(c.flags.get(Overflow))
4849 self.assertIs(c.flags.get("x"), None)
4850 self.assertEqual(c.flags.get("x", "y"), "y")
4851 self.assertRaises(TypeError, c.flags.get, "x", "y", "z")
Mark Dickinson84230a12010-02-18 14:49:50 +00004852
Stefan Krah1919b7e2012-03-21 18:25:23 +01004853 self.assertEqual(len(c.flags), len(c.traps))
4854 s = sys.getsizeof(c.flags)
4855 s = sys.getsizeof(c.traps)
4856 s = c.flags.__repr__()
Mark Dickinson84230a12010-02-18 14:49:50 +00004857
Stefan Krah1919b7e2012-03-21 18:25:23 +01004858 # Set flags/traps.
4859 c.clear_flags()
4860 c._flags = DecClamped
4861 self.assertTrue(c.flags[Clamped])
Mark Dickinson84230a12010-02-18 14:49:50 +00004862
Stefan Krah1919b7e2012-03-21 18:25:23 +01004863 c.clear_traps()
4864 c._traps = DecInvalidOperation
4865 self.assertTrue(c.traps[InvalidOperation])
Mark Dickinson84230a12010-02-18 14:49:50 +00004866
Stefan Krah1919b7e2012-03-21 18:25:23 +01004867 # Set flags/traps from dictionary.
4868 c.clear_flags()
4869 d = c.flags.copy()
4870 d[DivisionByZero] = True
4871 c.flags = d
4872 assertIsExclusivelySet(DivisionByZero, c.flags)
Mark Dickinson84230a12010-02-18 14:49:50 +00004873
Stefan Krah1919b7e2012-03-21 18:25:23 +01004874 c.clear_traps()
4875 d = c.traps.copy()
4876 d[Underflow] = True
4877 c.traps = d
4878 assertIsExclusivelySet(Underflow, c.traps)
Mark Dickinson84230a12010-02-18 14:49:50 +00004879
Stefan Krah1919b7e2012-03-21 18:25:23 +01004880 # Random constructors
4881 IntSignals = {
4882 Clamped: C.DecClamped,
4883 Rounded: C.DecRounded,
4884 Inexact: C.DecInexact,
4885 Subnormal: C.DecSubnormal,
4886 Underflow: C.DecUnderflow,
4887 Overflow: C.DecOverflow,
4888 DivisionByZero: C.DecDivisionByZero,
4889 InvalidOperation: C.DecIEEEInvalidOperation
4890 }
4891 IntCond = [
4892 C.DecDivisionImpossible, C.DecDivisionUndefined, C.DecFpuError,
4893 C.DecInvalidContext, C.DecInvalidOperation, C.DecMallocError,
4894 C.DecConversionSyntax,
4895 ]
Mark Dickinsonb455e582011-05-22 12:53:18 +01004896
Stefan Krah1919b7e2012-03-21 18:25:23 +01004897 lim = len(OrderedSignals[C])
4898 for r in range(lim):
4899 for t in range(lim):
4900 for round in RoundingModes[C]:
4901 flags = random.sample(OrderedSignals[C], r)
4902 traps = random.sample(OrderedSignals[C], t)
4903 prec = random.randrange(1, 10000)
4904 emin = random.randrange(-10000, 0)
4905 emax = random.randrange(0, 10000)
4906 clamp = random.randrange(0, 2)
4907 caps = random.randrange(0, 2)
4908 cr = random.randrange(0, 2)
4909 c = Context(prec=prec, rounding=round, Emin=emin, Emax=emax,
4910 capitals=caps, clamp=clamp, flags=list(flags),
4911 traps=list(traps))
Mark Dickinson84230a12010-02-18 14:49:50 +00004912
Stefan Krah1919b7e2012-03-21 18:25:23 +01004913 self.assertEqual(c.prec, prec)
4914 self.assertEqual(c.rounding, round)
4915 self.assertEqual(c.Emin, emin)
4916 self.assertEqual(c.Emax, emax)
4917 self.assertEqual(c.capitals, caps)
4918 self.assertEqual(c.clamp, clamp)
Mark Dickinson84230a12010-02-18 14:49:50 +00004919
Stefan Krah1919b7e2012-03-21 18:25:23 +01004920 f = 0
4921 for x in flags:
4922 f |= IntSignals[x]
4923 self.assertEqual(c._flags, f)
Mark Dickinson84230a12010-02-18 14:49:50 +00004924
Stefan Krah1919b7e2012-03-21 18:25:23 +01004925 f = 0
4926 for x in traps:
4927 f |= IntSignals[x]
4928 self.assertEqual(c._traps, f)
Mark Dickinson84230a12010-02-18 14:49:50 +00004929
Stefan Krah1919b7e2012-03-21 18:25:23 +01004930 for cond in IntCond:
4931 c._flags = cond
4932 self.assertTrue(c._flags&DecIEEEInvalidOperation)
4933 assertIsExclusivelySet(InvalidOperation, c.flags)
Mark Dickinson84230a12010-02-18 14:49:50 +00004934
Stefan Krah1919b7e2012-03-21 18:25:23 +01004935 for cond in IntCond:
4936 c._traps = cond
4937 self.assertTrue(c._traps&DecIEEEInvalidOperation)
4938 assertIsExclusivelySet(InvalidOperation, c.traps)
Mark Dickinson84230a12010-02-18 14:49:50 +00004939
Stefan Krah1919b7e2012-03-21 18:25:23 +01004940 def test_invalid_override(self):
4941 Decimal = C.Decimal
Mark Dickinson84230a12010-02-18 14:49:50 +00004942
Stefan Krah1919b7e2012-03-21 18:25:23 +01004943 try:
4944 from locale import CHAR_MAX
4945 except ImportError:
4946 return
Mark Dickinson84230a12010-02-18 14:49:50 +00004947
Stefan Krah1919b7e2012-03-21 18:25:23 +01004948 def make_grouping(lst):
4949 return ''.join([chr(x) for x in lst])
Mark Dickinson84230a12010-02-18 14:49:50 +00004950
Stefan Krah1919b7e2012-03-21 18:25:23 +01004951 def get_fmt(x, override=None, fmt='n'):
4952 return Decimal(x).__format__(fmt, override)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004953
Stefan Krah1919b7e2012-03-21 18:25:23 +01004954 invalid_grouping = {
4955 'decimal_point' : ',',
4956 'grouping' : make_grouping([255, 255, 0]),
4957 'thousands_sep' : ','
4958 }
4959 invalid_dot = {
4960 'decimal_point' : 'xxxxx',
4961 'grouping' : make_grouping([3, 3, 0]),
4962 'thousands_sep' : ','
4963 }
4964 invalid_sep = {
4965 'decimal_point' : '.',
4966 'grouping' : make_grouping([3, 3, 0]),
4967 'thousands_sep' : 'yyyyy'
4968 }
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004969
Stefan Krah1919b7e2012-03-21 18:25:23 +01004970 if CHAR_MAX == 127: # negative grouping in override
4971 self.assertRaises(ValueError, get_fmt, 12345,
4972 invalid_grouping, 'g')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004973
Stefan Krah1919b7e2012-03-21 18:25:23 +01004974 self.assertRaises(ValueError, get_fmt, 12345, invalid_dot, 'g')
4975 self.assertRaises(ValueError, get_fmt, 12345, invalid_sep, 'g')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004976
Stefan Krah0774e9b2012-04-05 15:21:58 +02004977 def test_exact_conversion(self):
4978 Decimal = C.Decimal
4979 localcontext = C.localcontext
4980 InvalidOperation = C.InvalidOperation
4981
4982 with localcontext() as c:
4983
4984 c.traps[InvalidOperation] = True
4985
4986 # Clamped
4987 x = "0e%d" % sys.maxsize
4988 self.assertRaises(InvalidOperation, Decimal, x)
4989
4990 x = "0e%d" % (-sys.maxsize-1)
4991 self.assertRaises(InvalidOperation, Decimal, x)
4992
4993 # Overflow
4994 x = "1e%d" % sys.maxsize
4995 self.assertRaises(InvalidOperation, Decimal, x)
4996
4997 # Underflow
4998 x = "1e%d" % (-sys.maxsize-1)
4999 self.assertRaises(InvalidOperation, Decimal, x)
5000
Stefan Krahff3eca02012-04-05 15:46:19 +02005001 def test_from_tuple(self):
5002 Decimal = C.Decimal
5003 localcontext = C.localcontext
5004 InvalidOperation = C.InvalidOperation
5005 Overflow = C.Overflow
5006 Underflow = C.Underflow
5007
5008 with localcontext() as c:
5009
5010 c.traps[InvalidOperation] = True
5011 c.traps[Overflow] = True
5012 c.traps[Underflow] = True
5013
5014 # SSIZE_MAX
5015 x = (1, (), sys.maxsize)
5016 self.assertEqual(str(c.create_decimal(x)), '-0E+999999')
5017 self.assertRaises(InvalidOperation, Decimal, x)
5018
5019 x = (1, (0, 1, 2), sys.maxsize)
5020 self.assertRaises(Overflow, c.create_decimal, x)
5021 self.assertRaises(InvalidOperation, Decimal, x)
5022
5023 # SSIZE_MIN
5024 x = (1, (), -sys.maxsize-1)
5025 self.assertEqual(str(c.create_decimal(x)), '-0E-1000026')
5026 self.assertRaises(InvalidOperation, Decimal, x)
5027
5028 x = (1, (0, 1, 2), -sys.maxsize-1)
5029 self.assertRaises(Underflow, c.create_decimal, x)
5030 self.assertRaises(InvalidOperation, Decimal, x)
5031
5032 # OverflowError
5033 x = (1, (), sys.maxsize+1)
5034 self.assertRaises(OverflowError, c.create_decimal, x)
5035 self.assertRaises(OverflowError, Decimal, x)
5036
5037 x = (1, (), -sys.maxsize-2)
5038 self.assertRaises(OverflowError, c.create_decimal, x)
5039 self.assertRaises(OverflowError, Decimal, x)
5040
5041 # Specials
5042 x = (1, (), "N")
5043 self.assertEqual(str(Decimal(x)), '-sNaN')
5044 x = (1, (0,), "N")
5045 self.assertEqual(str(Decimal(x)), '-sNaN')
5046 x = (1, (0, 1), "N")
5047 self.assertEqual(str(Decimal(x)), '-sNaN1')
5048
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005049
Stefan Krah1919b7e2012-03-21 18:25:23 +01005050all_tests = [
5051 CExplicitConstructionTest, PyExplicitConstructionTest,
5052 CImplicitConstructionTest, PyImplicitConstructionTest,
5053 CFormatTest, PyFormatTest,
5054 CArithmeticOperatorsTest, PyArithmeticOperatorsTest,
5055 CThreadingTest, PyThreadingTest,
5056 CUsabilityTest, PyUsabilityTest,
5057 CPythonAPItests, PyPythonAPItests,
5058 CContextAPItests, PyContextAPItests,
5059 CContextWithStatement, PyContextWithStatement,
5060 CContextFlags, PyContextFlags,
5061 CSpecialContexts, PySpecialContexts,
5062 CContextInputValidation, PyContextInputValidation,
5063 CContextSubclassing, PyContextSubclassing,
5064 CCoverage, PyCoverage,
5065 CFunctionality, PyFunctionality,
5066 CWhitebox, PyWhitebox,
5067 CIBMTestCases, PyIBMTestCases,
5068]
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005069
Stefan Krah1919b7e2012-03-21 18:25:23 +01005070# Delete C tests if _decimal.so is not present.
5071if not C:
5072 all_tests = all_tests[1::2]
5073else:
5074 all_tests.insert(0, CheckAttributes)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005075
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005076
5077def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00005078 """ Execute the tests.
5079
Raymond Hettingered20ad82004-09-04 20:09:13 +00005080 Runs all arithmetic tests if arith is True or if the "decimal" resource
5081 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00005082 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00005083
Stefan Krah1919b7e2012-03-21 18:25:23 +01005084 init(C)
5085 init(P)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005086 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00005087 TEST_ALL = arith or is_resource_enabled('decimal')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005088 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00005089
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005090 if todo_tests is None:
Stefan Krah1919b7e2012-03-21 18:25:23 +01005091 test_classes = all_tests
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005092 else:
Stefan Krah1919b7e2012-03-21 18:25:23 +01005093 test_classes = [CIBMTestCases, PyIBMTestCases]
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005094
5095 # Dynamically build custom test definition for each file in the test
5096 # directory and add the definitions to the DecimalTest class. This
5097 # procedure insures that new files do not get skipped.
5098 for filename in os.listdir(directory):
5099 if '.decTest' not in filename or filename.startswith("."):
5100 continue
5101 head, tail = filename.split('.')
5102 if todo_tests is not None and head not in todo_tests:
5103 continue
5104 tester = lambda self, f=filename: self.eval_file(directory + f)
Stefan Krah1919b7e2012-03-21 18:25:23 +01005105 setattr(CIBMTestCases, 'test_' + head, tester)
5106 setattr(PyIBMTestCases, 'test_' + head, tester)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005107 del filename, head, tail, tester
5108
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00005109
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00005110 try:
5111 run_unittest(*test_classes)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005112 if todo_tests is None:
Stefan Krah1919b7e2012-03-21 18:25:23 +01005113 from doctest import IGNORE_EXCEPTION_DETAIL
5114 savedecimal = sys.modules['decimal']
5115 if C:
5116 sys.modules['decimal'] = C
5117 run_doctest(C, verbose, optionflags=IGNORE_EXCEPTION_DETAIL)
5118 sys.modules['decimal'] = P
5119 run_doctest(P, verbose)
5120 sys.modules['decimal'] = savedecimal
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00005121 finally:
Stefan Krah1919b7e2012-03-21 18:25:23 +01005122 if C: C.setcontext(ORIGINAL_CONTEXT[C])
5123 P.setcontext(ORIGINAL_CONTEXT[P])
5124 if not C:
5125 warnings.warn('C tests skipped: no module named _decimal.',
5126 UserWarning)
5127 if not orig_sys_decimal is sys.modules['decimal']:
5128 raise TestFailed("Internal error: unbalanced number of changes to "
5129 "sys.modules['decimal'].")
5130
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00005131
5132if __name__ == '__main__':
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005133 import optparse
5134 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
5135 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
5136 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
5137 (opt, args) = p.parse_args()
5138
5139 if opt.skip:
5140 test_main(arith=False, verbose=True)
5141 elif args:
5142 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00005143 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005144 test_main(arith=True, verbose=True)