blob: dd4c73cdf14bbb4da44f7578be7b99abd97fea96 [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):
Stefan Krah0f82b762012-11-08 11:17:29 +01002032 y = None
Stefan Krah1919b7e2012-03-21 18:25:23 +01002033
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
Stefan Krah0f82b762012-11-08 11:17:29 +01002050 # Decimal(Decimal)
2051 d = Decimal('1.0')
2052 x = Decimal(d)
2053 self.assertIs(type(x), Decimal)
2054 self.assertEqual(x, d)
Stefan Krahf4abc7b2012-11-07 23:12:25 +01002055
Stefan Krah0f82b762012-11-08 11:17:29 +01002056 # MyDecimal(Decimal)
2057 m = MyDecimal(d)
2058 self.assertIs(type(m), MyDecimal)
2059 self.assertEqual(m, d)
2060 self.assertIs(m.y, None)
2061
2062 # Decimal(MyDecimal)
2063 x = Decimal(m)
2064 self.assertIs(type(x), Decimal)
2065 self.assertEqual(x, d)
2066
2067 # MyDecimal(MyDecimal)
2068 m.y = 9
2069 x = MyDecimal(m)
2070 self.assertIs(type(x), MyDecimal)
2071 self.assertEqual(x, d)
2072 self.assertIs(x.y, None)
Stefan Krahed16eff2012-11-07 23:47:19 +01002073
Stefan Krah1919b7e2012-03-21 18:25:23 +01002074 def test_implicit_context(self):
2075 Decimal = self.decimal.Decimal
2076 getcontext = self.decimal.getcontext
2077
2078 # Check results when context given implicitly. (Issue 2478)
2079 c = getcontext()
2080 self.assertEqual(str(Decimal(0).sqrt()),
2081 str(c.sqrt(Decimal(0))))
2082
2083 def test_conversions_from_int(self):
2084 # Check that methods taking a second Decimal argument will
2085 # always accept an integer in place of a Decimal.
2086 Decimal = self.decimal.Decimal
2087
2088 self.assertEqual(Decimal(4).compare(3),
2089 Decimal(4).compare(Decimal(3)))
2090 self.assertEqual(Decimal(4).compare_signal(3),
2091 Decimal(4).compare_signal(Decimal(3)))
2092 self.assertEqual(Decimal(4).compare_total(3),
2093 Decimal(4).compare_total(Decimal(3)))
2094 self.assertEqual(Decimal(4).compare_total_mag(3),
2095 Decimal(4).compare_total_mag(Decimal(3)))
2096 self.assertEqual(Decimal(10101).logical_and(1001),
2097 Decimal(10101).logical_and(Decimal(1001)))
2098 self.assertEqual(Decimal(10101).logical_or(1001),
2099 Decimal(10101).logical_or(Decimal(1001)))
2100 self.assertEqual(Decimal(10101).logical_xor(1001),
2101 Decimal(10101).logical_xor(Decimal(1001)))
2102 self.assertEqual(Decimal(567).max(123),
2103 Decimal(567).max(Decimal(123)))
2104 self.assertEqual(Decimal(567).max_mag(123),
2105 Decimal(567).max_mag(Decimal(123)))
2106 self.assertEqual(Decimal(567).min(123),
2107 Decimal(567).min(Decimal(123)))
2108 self.assertEqual(Decimal(567).min_mag(123),
2109 Decimal(567).min_mag(Decimal(123)))
2110 self.assertEqual(Decimal(567).next_toward(123),
2111 Decimal(567).next_toward(Decimal(123)))
2112 self.assertEqual(Decimal(1234).quantize(100),
2113 Decimal(1234).quantize(Decimal(100)))
2114 self.assertEqual(Decimal(768).remainder_near(1234),
2115 Decimal(768).remainder_near(Decimal(1234)))
2116 self.assertEqual(Decimal(123).rotate(1),
2117 Decimal(123).rotate(Decimal(1)))
2118 self.assertEqual(Decimal(1234).same_quantum(1000),
2119 Decimal(1234).same_quantum(Decimal(1000)))
2120 self.assertEqual(Decimal('9.123').scaleb(-100),
2121 Decimal('9.123').scaleb(Decimal(-100)))
2122 self.assertEqual(Decimal(456).shift(-1),
2123 Decimal(456).shift(Decimal(-1)))
2124
2125 self.assertEqual(Decimal(-12).fma(Decimal(45), 67),
2126 Decimal(-12).fma(Decimal(45), Decimal(67)))
2127 self.assertEqual(Decimal(-12).fma(45, 67),
2128 Decimal(-12).fma(Decimal(45), Decimal(67)))
2129 self.assertEqual(Decimal(-12).fma(45, Decimal(67)),
2130 Decimal(-12).fma(Decimal(45), Decimal(67)))
2131
2132class CUsabilityTest(UsabilityTest):
2133 decimal = C
2134class PyUsabilityTest(UsabilityTest):
2135 decimal = P
2136
2137class PythonAPItests(unittest.TestCase):
2138
2139 def test_abc(self):
2140 Decimal = self.decimal.Decimal
2141
2142 self.assertTrue(issubclass(Decimal, numbers.Number))
2143 self.assertFalse(issubclass(Decimal, numbers.Real))
2144 self.assertIsInstance(Decimal(0), numbers.Number)
2145 self.assertNotIsInstance(Decimal(0), numbers.Real)
2146
2147 def test_pickle(self):
2148 Decimal = self.decimal.Decimal
2149
2150 savedecimal = sys.modules['decimal']
2151
2152 # Round trip
2153 sys.modules['decimal'] = self.decimal
2154 d = Decimal('-3.141590000')
2155 p = pickle.dumps(d)
2156 e = pickle.loads(p)
2157 self.assertEqual(d, e)
2158
2159 if C:
2160 # Test interchangeability
2161 x = C.Decimal('-3.123e81723')
2162 y = P.Decimal('-3.123e81723')
2163
2164 sys.modules['decimal'] = C
2165 sx = pickle.dumps(x)
2166 sys.modules['decimal'] = P
2167 r = pickle.loads(sx)
2168 self.assertIsInstance(r, P.Decimal)
2169 self.assertEqual(r, y)
2170
2171 sys.modules['decimal'] = P
2172 sy = pickle.dumps(y)
2173 sys.modules['decimal'] = C
2174 r = pickle.loads(sy)
2175 self.assertIsInstance(r, C.Decimal)
2176 self.assertEqual(r, x)
2177
2178 sys.modules['decimal'] = savedecimal
2179
2180 def test_int(self):
2181 Decimal = self.decimal.Decimal
2182 ROUND_DOWN = self.decimal.ROUND_DOWN
2183
2184 for x in range(-250, 250):
2185 s = '%0.2f' % (x / 100.0)
2186 # should work the same as for floats
2187 self.assertEqual(int(Decimal(s)), int(float(s)))
2188 # should work the same as to_integral in the ROUND_DOWN mode
2189 d = Decimal(s)
2190 r = d.to_integral(ROUND_DOWN)
2191 self.assertEqual(Decimal(int(d)), r)
2192
2193 self.assertRaises(ValueError, int, Decimal('-nan'))
2194 self.assertRaises(ValueError, int, Decimal('snan'))
2195 self.assertRaises(OverflowError, int, Decimal('inf'))
2196 self.assertRaises(OverflowError, int, Decimal('-inf'))
2197
2198 def test_trunc(self):
2199 Decimal = self.decimal.Decimal
2200 ROUND_DOWN = self.decimal.ROUND_DOWN
2201
2202 for x in range(-250, 250):
2203 s = '%0.2f' % (x / 100.0)
2204 # should work the same as for floats
2205 self.assertEqual(int(Decimal(s)), int(float(s)))
2206 # should work the same as to_integral in the ROUND_DOWN mode
2207 d = Decimal(s)
2208 r = d.to_integral(ROUND_DOWN)
2209 self.assertEqual(Decimal(math.trunc(d)), r)
2210
2211 def test_from_float(self):
2212
2213 Decimal = self.decimal.Decimal
2214
2215 class MyDecimal(Decimal):
2216 pass
2217
2218 self.assertTrue(issubclass(MyDecimal, Decimal))
2219
2220 r = MyDecimal.from_float(0.1)
2221 self.assertEqual(type(r), MyDecimal)
2222 self.assertEqual(str(r),
2223 '0.1000000000000000055511151231257827021181583404541015625')
2224 bigint = 12345678901234567890123456789
2225 self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
2226 self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan())
2227 self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite())
2228 self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite())
2229 self.assertEqual(str(MyDecimal.from_float(float('nan'))),
2230 str(Decimal('NaN')))
2231 self.assertEqual(str(MyDecimal.from_float(float('inf'))),
2232 str(Decimal('Infinity')))
2233 self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
2234 str(Decimal('-Infinity')))
2235 self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
2236 for i in range(200):
2237 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
2238 self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
2239
2240 def test_create_decimal_from_float(self):
2241 Decimal = self.decimal.Decimal
2242 Context = self.decimal.Context
2243 ROUND_DOWN = self.decimal.ROUND_DOWN
2244 ROUND_UP = self.decimal.ROUND_UP
2245 Inexact = self.decimal.Inexact
2246
2247 context = Context(prec=5, rounding=ROUND_DOWN)
2248 self.assertEqual(
2249 context.create_decimal_from_float(math.pi),
2250 Decimal('3.1415')
2251 )
2252 context = Context(prec=5, rounding=ROUND_UP)
2253 self.assertEqual(
2254 context.create_decimal_from_float(math.pi),
2255 Decimal('3.1416')
2256 )
2257 context = Context(prec=5, traps=[Inexact])
2258 self.assertRaises(
2259 Inexact,
2260 context.create_decimal_from_float,
2261 math.pi
2262 )
2263 self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
2264 "Decimal('-0')")
2265 self.assertEqual(repr(context.create_decimal_from_float(1.0)),
2266 "Decimal('1')")
2267 self.assertEqual(repr(context.create_decimal_from_float(10)),
2268 "Decimal('10')")
2269
2270 def test_quantize(self):
2271 Decimal = self.decimal.Decimal
2272 Context = self.decimal.Context
2273 InvalidOperation = self.decimal.InvalidOperation
2274 ROUND_DOWN = self.decimal.ROUND_DOWN
2275
2276 c = Context(Emax=99999, Emin=-99999)
2277 self.assertEqual(
2278 Decimal('7.335').quantize(Decimal('.01')),
2279 Decimal('7.34')
2280 )
2281 self.assertEqual(
2282 Decimal('7.335').quantize(Decimal('.01'), rounding=ROUND_DOWN),
2283 Decimal('7.33')
2284 )
2285 self.assertRaises(
2286 InvalidOperation,
2287 Decimal("10e99999").quantize, Decimal('1e100000'), context=c
2288 )
2289
2290 c = Context()
2291 d = Decimal("0.871831e800")
2292 x = d.quantize(context=c, exp=Decimal("1e797"), rounding=ROUND_DOWN)
2293 self.assertEqual(x, Decimal('8.71E+799'))
2294
2295 def test_complex(self):
2296 Decimal = self.decimal.Decimal
2297
2298 x = Decimal("9.8182731e181273")
2299 self.assertEqual(x.real, x)
2300 self.assertEqual(x.imag, 0)
2301 self.assertEqual(x.conjugate(), x)
2302
2303 x = Decimal("1")
2304 self.assertEqual(complex(x), complex(float(1)))
2305
2306 self.assertRaises(AttributeError, setattr, x, 'real', 100)
2307 self.assertRaises(AttributeError, setattr, x, 'imag', 100)
2308 self.assertRaises(AttributeError, setattr, x, 'conjugate', 100)
2309 self.assertRaises(AttributeError, setattr, x, '__complex__', 100)
2310
2311 def test_named_parameters(self):
2312 D = self.decimal.Decimal
2313 Context = self.decimal.Context
2314 localcontext = self.decimal.localcontext
2315 InvalidOperation = self.decimal.InvalidOperation
2316 Overflow = self.decimal.Overflow
2317
2318 xc = Context()
2319 xc.prec = 1
2320 xc.Emax = 1
2321 xc.Emin = -1
2322
2323 with localcontext() as c:
2324 c.clear_flags()
2325
2326 self.assertEqual(D(9, xc), 9)
2327 self.assertEqual(D(9, context=xc), 9)
2328 self.assertEqual(D(context=xc, value=9), 9)
2329 self.assertEqual(D(context=xc), 0)
2330 xc.clear_flags()
2331 self.assertRaises(InvalidOperation, D, "xyz", context=xc)
2332 self.assertTrue(xc.flags[InvalidOperation])
2333 self.assertFalse(c.flags[InvalidOperation])
2334
2335 xc.clear_flags()
2336 self.assertEqual(D(2).exp(context=xc), 7)
2337 self.assertRaises(Overflow, D(8).exp, context=xc)
2338 self.assertTrue(xc.flags[Overflow])
2339 self.assertFalse(c.flags[Overflow])
2340
2341 xc.clear_flags()
2342 self.assertEqual(D(2).ln(context=xc), D('0.7'))
2343 self.assertRaises(InvalidOperation, D(-1).ln, context=xc)
2344 self.assertTrue(xc.flags[InvalidOperation])
2345 self.assertFalse(c.flags[InvalidOperation])
2346
2347 self.assertEqual(D(0).log10(context=xc), D('-inf'))
2348 self.assertEqual(D(-1).next_minus(context=xc), -2)
2349 self.assertEqual(D(-1).next_plus(context=xc), D('-0.9'))
2350 self.assertEqual(D("9.73").normalize(context=xc), D('1E+1'))
2351 self.assertEqual(D("9999").to_integral(context=xc), 9999)
2352 self.assertEqual(D("-2000").to_integral_exact(context=xc), -2000)
2353 self.assertEqual(D("123").to_integral_value(context=xc), 123)
2354 self.assertEqual(D("0.0625").sqrt(context=xc), D('0.2'))
2355
2356 self.assertEqual(D("0.0625").compare(context=xc, other=3), -1)
2357 xc.clear_flags()
2358 self.assertRaises(InvalidOperation,
2359 D("0").compare_signal, D('nan'), context=xc)
2360 self.assertTrue(xc.flags[InvalidOperation])
2361 self.assertFalse(c.flags[InvalidOperation])
2362 self.assertEqual(D("0.01").max(D('0.0101'), context=xc), D('0.0'))
2363 self.assertEqual(D("0.01").max(D('0.0101'), context=xc), D('0.0'))
2364 self.assertEqual(D("0.2").max_mag(D('-0.3'), context=xc),
2365 D('-0.3'))
2366 self.assertEqual(D("0.02").min(D('-0.03'), context=xc), D('-0.0'))
2367 self.assertEqual(D("0.02").min_mag(D('-0.03'), context=xc),
2368 D('0.0'))
2369 self.assertEqual(D("0.2").next_toward(D('-1'), context=xc), D('0.1'))
2370 xc.clear_flags()
2371 self.assertRaises(InvalidOperation,
2372 D("0.2").quantize, D('1e10'), context=xc)
2373 self.assertTrue(xc.flags[InvalidOperation])
2374 self.assertFalse(c.flags[InvalidOperation])
2375 self.assertEqual(D("9.99").remainder_near(D('1.5'), context=xc),
2376 D('-0.5'))
2377
2378 self.assertEqual(D("9.9").fma(third=D('0.9'), context=xc, other=7),
2379 D('7E+1'))
2380
2381 self.assertRaises(TypeError, D(1).is_canonical, context=xc)
2382 self.assertRaises(TypeError, D(1).is_finite, context=xc)
2383 self.assertRaises(TypeError, D(1).is_infinite, context=xc)
2384 self.assertRaises(TypeError, D(1).is_nan, context=xc)
2385 self.assertRaises(TypeError, D(1).is_qnan, context=xc)
2386 self.assertRaises(TypeError, D(1).is_snan, context=xc)
2387 self.assertRaises(TypeError, D(1).is_signed, context=xc)
2388 self.assertRaises(TypeError, D(1).is_zero, context=xc)
2389
2390 self.assertFalse(D("0.01").is_normal(context=xc))
2391 self.assertTrue(D("0.01").is_subnormal(context=xc))
2392
2393 self.assertRaises(TypeError, D(1).adjusted, context=xc)
2394 self.assertRaises(TypeError, D(1).conjugate, context=xc)
2395 self.assertRaises(TypeError, D(1).radix, context=xc)
2396
2397 self.assertEqual(D(-111).logb(context=xc), 2)
2398 self.assertEqual(D(0).logical_invert(context=xc), 1)
2399 self.assertEqual(D('0.01').number_class(context=xc), '+Subnormal')
2400 self.assertEqual(D('0.21').to_eng_string(context=xc), '0.21')
2401
2402 self.assertEqual(D('11').logical_and(D('10'), context=xc), 0)
2403 self.assertEqual(D('11').logical_or(D('10'), context=xc), 1)
2404 self.assertEqual(D('01').logical_xor(D('10'), context=xc), 1)
2405 self.assertEqual(D('23').rotate(1, context=xc), 3)
2406 self.assertEqual(D('23').rotate(1, context=xc), 3)
2407 xc.clear_flags()
2408 self.assertRaises(Overflow,
2409 D('23').scaleb, 1, context=xc)
2410 self.assertTrue(xc.flags[Overflow])
2411 self.assertFalse(c.flags[Overflow])
2412 self.assertEqual(D('23').shift(-1, context=xc), 0)
2413
2414 self.assertRaises(TypeError, D.from_float, 1.1, context=xc)
2415 self.assertRaises(TypeError, D(0).as_tuple, context=xc)
2416
2417 if (self.decimal == C):
2418 self.assertRaises(TypeError, D(1).canonical, context=xc)
2419 self.assertEqual(D("-1").copy_abs(context=xc), 1)
2420 self.assertEqual(D("1").copy_negate(context=xc), -1)
2421 else:
2422 self.assertEqual(D(1).canonical(context=xc), 1)
2423 self.assertRaises(TypeError, D("-1").copy_abs, context=xc)
2424 self.assertRaises(TypeError, D("-1").copy_negate, context=xc)
2425
Stefan Krahb6405ef2012-03-23 14:46:48 +01002426 def test_exception_hierarchy(self):
2427
2428 decimal = self.decimal
2429 DecimalException = decimal.DecimalException
2430 InvalidOperation = decimal.InvalidOperation
2431 FloatOperation = decimal.FloatOperation
2432 DivisionByZero = decimal.DivisionByZero
2433 Overflow = decimal.Overflow
2434 Underflow = decimal.Underflow
2435 Subnormal = decimal.Subnormal
2436 Inexact = decimal.Inexact
2437 Rounded = decimal.Rounded
2438 Clamped = decimal.Clamped
2439
2440 self.assertTrue(issubclass(DecimalException, ArithmeticError))
2441
2442 self.assertTrue(issubclass(InvalidOperation, DecimalException))
2443 self.assertTrue(issubclass(FloatOperation, DecimalException))
2444 self.assertTrue(issubclass(FloatOperation, TypeError))
2445 self.assertTrue(issubclass(DivisionByZero, DecimalException))
2446 self.assertTrue(issubclass(DivisionByZero, ZeroDivisionError))
2447 self.assertTrue(issubclass(Overflow, Rounded))
2448 self.assertTrue(issubclass(Overflow, Inexact))
2449 self.assertTrue(issubclass(Overflow, DecimalException))
2450 self.assertTrue(issubclass(Underflow, Inexact))
2451 self.assertTrue(issubclass(Underflow, Rounded))
2452 self.assertTrue(issubclass(Underflow, Subnormal))
2453 self.assertTrue(issubclass(Underflow, DecimalException))
2454
2455 self.assertTrue(issubclass(Subnormal, DecimalException))
2456 self.assertTrue(issubclass(Inexact, DecimalException))
2457 self.assertTrue(issubclass(Rounded, DecimalException))
2458 self.assertTrue(issubclass(Clamped, DecimalException))
2459
2460 self.assertTrue(issubclass(decimal.ConversionSyntax, InvalidOperation))
2461 self.assertTrue(issubclass(decimal.DivisionImpossible, InvalidOperation))
2462 self.assertTrue(issubclass(decimal.DivisionUndefined, InvalidOperation))
2463 self.assertTrue(issubclass(decimal.DivisionUndefined, ZeroDivisionError))
2464 self.assertTrue(issubclass(decimal.InvalidContext, InvalidOperation))
2465
Stefan Krah1919b7e2012-03-21 18:25:23 +01002466class CPythonAPItests(PythonAPItests):
2467 decimal = C
2468class PyPythonAPItests(PythonAPItests):
2469 decimal = P
2470
2471class ContextAPItests(unittest.TestCase):
2472
2473 def test_pickle(self):
2474
2475 Context = self.decimal.Context
2476
2477 savedecimal = sys.modules['decimal']
2478
2479 # Round trip
2480 sys.modules['decimal'] = self.decimal
2481 c = Context()
2482 e = pickle.loads(pickle.dumps(c))
2483
2484 self.assertEqual(c.prec, e.prec)
2485 self.assertEqual(c.Emin, e.Emin)
2486 self.assertEqual(c.Emax, e.Emax)
2487 self.assertEqual(c.rounding, e.rounding)
2488 self.assertEqual(c.capitals, e.capitals)
2489 self.assertEqual(c.clamp, e.clamp)
2490 self.assertEqual(c.flags, e.flags)
2491 self.assertEqual(c.traps, e.traps)
2492
2493 # Test interchangeability
2494 combinations = [(C, P), (P, C)] if C else [(P, P)]
2495 for dumper, loader in combinations:
2496 for ri, _ in enumerate(RoundingModes[dumper]):
2497 for fi, _ in enumerate(OrderedSignals[dumper]):
2498 for ti, _ in enumerate(OrderedSignals[dumper]):
2499
2500 prec = random.randrange(1, 100)
2501 emin = random.randrange(-100, 0)
2502 emax = random.randrange(1, 100)
2503 caps = random.randrange(2)
2504 clamp = random.randrange(2)
2505
2506 # One module dumps
2507 sys.modules['decimal'] = dumper
2508 c = dumper.Context(
2509 prec=prec, Emin=emin, Emax=emax,
2510 rounding=RoundingModes[dumper][ri],
2511 capitals=caps, clamp=clamp,
2512 flags=OrderedSignals[dumper][:fi],
2513 traps=OrderedSignals[dumper][:ti]
2514 )
2515 s = pickle.dumps(c)
2516
2517 # The other module loads
2518 sys.modules['decimal'] = loader
2519 d = pickle.loads(s)
2520 self.assertIsInstance(d, loader.Context)
2521
2522 self.assertEqual(d.prec, prec)
2523 self.assertEqual(d.Emin, emin)
2524 self.assertEqual(d.Emax, emax)
2525 self.assertEqual(d.rounding, RoundingModes[loader][ri])
2526 self.assertEqual(d.capitals, caps)
2527 self.assertEqual(d.clamp, clamp)
2528 assert_signals(self, d, 'flags', OrderedSignals[loader][:fi])
2529 assert_signals(self, d, 'traps', OrderedSignals[loader][:ti])
2530
2531 sys.modules['decimal'] = savedecimal
2532
2533 def test_equality_with_other_types(self):
2534 Decimal = self.decimal.Decimal
2535
2536 self.assertIn(Decimal(10), ['a', 1.0, Decimal(10), (1,2), {}])
2537 self.assertNotIn(Decimal(10), ['a', 1.0, (1,2), {}])
2538
2539 def test_copy(self):
2540 # All copies should be deep
2541 Decimal = self.decimal.Decimal
2542 Context = self.decimal.Context
2543
2544 c = Context()
2545 d = c.copy()
2546 self.assertNotEqual(id(c), id(d))
2547 self.assertNotEqual(id(c.flags), id(d.flags))
2548 self.assertNotEqual(id(c.traps), id(d.traps))
2549 k1 = set(c.flags.keys())
2550 k2 = set(d.flags.keys())
2551 self.assertEqual(k1, k2)
2552 self.assertEqual(c.flags, d.flags)
2553
2554 def test__clamp(self):
2555 # In Python 3.2, the private attribute `_clamp` was made
2556 # public (issue 8540), with the old `_clamp` becoming a
2557 # property wrapping `clamp`. For the duration of Python 3.2
2558 # only, the attribute should be gettable/settable via both
2559 # `clamp` and `_clamp`; in Python 3.3, `_clamp` should be
2560 # removed.
2561 Context = self.decimal.Context
2562 c = Context()
2563 self.assertRaises(AttributeError, getattr, c, '_clamp')
2564
2565 def test_abs(self):
2566 Decimal = self.decimal.Decimal
2567 Context = self.decimal.Context
2568
2569 c = Context()
2570 d = c.abs(Decimal(-1))
2571 self.assertEqual(c.abs(-1), d)
2572 self.assertRaises(TypeError, c.abs, '-1')
2573
2574 def test_add(self):
2575 Decimal = self.decimal.Decimal
2576 Context = self.decimal.Context
2577
2578 c = Context()
2579 d = c.add(Decimal(1), Decimal(1))
2580 self.assertEqual(c.add(1, 1), d)
2581 self.assertEqual(c.add(Decimal(1), 1), d)
2582 self.assertEqual(c.add(1, Decimal(1)), d)
2583 self.assertRaises(TypeError, c.add, '1', 1)
2584 self.assertRaises(TypeError, c.add, 1, '1')
2585
2586 def test_compare(self):
2587 Decimal = self.decimal.Decimal
2588 Context = self.decimal.Context
2589
2590 c = Context()
2591 d = c.compare(Decimal(1), Decimal(1))
2592 self.assertEqual(c.compare(1, 1), d)
2593 self.assertEqual(c.compare(Decimal(1), 1), d)
2594 self.assertEqual(c.compare(1, Decimal(1)), d)
2595 self.assertRaises(TypeError, c.compare, '1', 1)
2596 self.assertRaises(TypeError, c.compare, 1, '1')
2597
2598 def test_compare_signal(self):
2599 Decimal = self.decimal.Decimal
2600 Context = self.decimal.Context
2601
2602 c = Context()
2603 d = c.compare_signal(Decimal(1), Decimal(1))
2604 self.assertEqual(c.compare_signal(1, 1), d)
2605 self.assertEqual(c.compare_signal(Decimal(1), 1), d)
2606 self.assertEqual(c.compare_signal(1, Decimal(1)), d)
2607 self.assertRaises(TypeError, c.compare_signal, '1', 1)
2608 self.assertRaises(TypeError, c.compare_signal, 1, '1')
2609
2610 def test_compare_total(self):
2611 Decimal = self.decimal.Decimal
2612 Context = self.decimal.Context
2613
2614 c = Context()
2615 d = c.compare_total(Decimal(1), Decimal(1))
2616 self.assertEqual(c.compare_total(1, 1), d)
2617 self.assertEqual(c.compare_total(Decimal(1), 1), d)
2618 self.assertEqual(c.compare_total(1, Decimal(1)), d)
2619 self.assertRaises(TypeError, c.compare_total, '1', 1)
2620 self.assertRaises(TypeError, c.compare_total, 1, '1')
2621
2622 def test_compare_total_mag(self):
2623 Decimal = self.decimal.Decimal
2624 Context = self.decimal.Context
2625
2626 c = Context()
2627 d = c.compare_total_mag(Decimal(1), Decimal(1))
2628 self.assertEqual(c.compare_total_mag(1, 1), d)
2629 self.assertEqual(c.compare_total_mag(Decimal(1), 1), d)
2630 self.assertEqual(c.compare_total_mag(1, Decimal(1)), d)
2631 self.assertRaises(TypeError, c.compare_total_mag, '1', 1)
2632 self.assertRaises(TypeError, c.compare_total_mag, 1, '1')
2633
2634 def test_copy_abs(self):
2635 Decimal = self.decimal.Decimal
2636 Context = self.decimal.Context
2637
2638 c = Context()
2639 d = c.copy_abs(Decimal(-1))
2640 self.assertEqual(c.copy_abs(-1), d)
2641 self.assertRaises(TypeError, c.copy_abs, '-1')
2642
2643 def test_copy_decimal(self):
2644 Decimal = self.decimal.Decimal
2645 Context = self.decimal.Context
2646
2647 c = Context()
2648 d = c.copy_decimal(Decimal(-1))
2649 self.assertEqual(c.copy_decimal(-1), d)
2650 self.assertRaises(TypeError, c.copy_decimal, '-1')
2651
2652 def test_copy_negate(self):
2653 Decimal = self.decimal.Decimal
2654 Context = self.decimal.Context
2655
2656 c = Context()
2657 d = c.copy_negate(Decimal(-1))
2658 self.assertEqual(c.copy_negate(-1), d)
2659 self.assertRaises(TypeError, c.copy_negate, '-1')
2660
2661 def test_copy_sign(self):
2662 Decimal = self.decimal.Decimal
2663 Context = self.decimal.Context
2664
2665 c = Context()
2666 d = c.copy_sign(Decimal(1), Decimal(-2))
2667 self.assertEqual(c.copy_sign(1, -2), d)
2668 self.assertEqual(c.copy_sign(Decimal(1), -2), d)
2669 self.assertEqual(c.copy_sign(1, Decimal(-2)), d)
2670 self.assertRaises(TypeError, c.copy_sign, '1', -2)
2671 self.assertRaises(TypeError, c.copy_sign, 1, '-2')
2672
2673 def test_divide(self):
2674 Decimal = self.decimal.Decimal
2675 Context = self.decimal.Context
2676
2677 c = Context()
2678 d = c.divide(Decimal(1), Decimal(2))
2679 self.assertEqual(c.divide(1, 2), d)
2680 self.assertEqual(c.divide(Decimal(1), 2), d)
2681 self.assertEqual(c.divide(1, Decimal(2)), d)
2682 self.assertRaises(TypeError, c.divide, '1', 2)
2683 self.assertRaises(TypeError, c.divide, 1, '2')
2684
2685 def test_divide_int(self):
2686 Decimal = self.decimal.Decimal
2687 Context = self.decimal.Context
2688
2689 c = Context()
2690 d = c.divide_int(Decimal(1), Decimal(2))
2691 self.assertEqual(c.divide_int(1, 2), d)
2692 self.assertEqual(c.divide_int(Decimal(1), 2), d)
2693 self.assertEqual(c.divide_int(1, Decimal(2)), d)
2694 self.assertRaises(TypeError, c.divide_int, '1', 2)
2695 self.assertRaises(TypeError, c.divide_int, 1, '2')
2696
2697 def test_divmod(self):
2698 Decimal = self.decimal.Decimal
2699 Context = self.decimal.Context
2700
2701 c = Context()
2702 d = c.divmod(Decimal(1), Decimal(2))
2703 self.assertEqual(c.divmod(1, 2), d)
2704 self.assertEqual(c.divmod(Decimal(1), 2), d)
2705 self.assertEqual(c.divmod(1, Decimal(2)), d)
2706 self.assertRaises(TypeError, c.divmod, '1', 2)
2707 self.assertRaises(TypeError, c.divmod, 1, '2')
2708
2709 def test_exp(self):
2710 Decimal = self.decimal.Decimal
2711 Context = self.decimal.Context
2712
2713 c = Context()
2714 d = c.exp(Decimal(10))
2715 self.assertEqual(c.exp(10), d)
2716 self.assertRaises(TypeError, c.exp, '10')
2717
2718 def test_fma(self):
2719 Decimal = self.decimal.Decimal
2720 Context = self.decimal.Context
2721
2722 c = Context()
2723 d = c.fma(Decimal(2), Decimal(3), Decimal(4))
2724 self.assertEqual(c.fma(2, 3, 4), d)
2725 self.assertEqual(c.fma(Decimal(2), 3, 4), d)
2726 self.assertEqual(c.fma(2, Decimal(3), 4), d)
2727 self.assertEqual(c.fma(2, 3, Decimal(4)), d)
2728 self.assertEqual(c.fma(Decimal(2), Decimal(3), 4), d)
2729 self.assertRaises(TypeError, c.fma, '2', 3, 4)
2730 self.assertRaises(TypeError, c.fma, 2, '3', 4)
2731 self.assertRaises(TypeError, c.fma, 2, 3, '4')
2732
2733 # Issue 12079 for Context.fma ...
2734 self.assertRaises(TypeError, c.fma,
2735 Decimal('Infinity'), Decimal(0), "not a decimal")
2736 self.assertRaises(TypeError, c.fma,
2737 Decimal(1), Decimal('snan'), 1.222)
2738 # ... and for Decimal.fma.
2739 self.assertRaises(TypeError, Decimal('Infinity').fma,
2740 Decimal(0), "not a decimal")
2741 self.assertRaises(TypeError, Decimal(1).fma,
2742 Decimal('snan'), 1.222)
2743
2744 def test_is_finite(self):
2745 Decimal = self.decimal.Decimal
2746 Context = self.decimal.Context
2747
2748 c = Context()
2749 d = c.is_finite(Decimal(10))
2750 self.assertEqual(c.is_finite(10), d)
2751 self.assertRaises(TypeError, c.is_finite, '10')
2752
2753 def test_is_infinite(self):
2754 Decimal = self.decimal.Decimal
2755 Context = self.decimal.Context
2756
2757 c = Context()
2758 d = c.is_infinite(Decimal(10))
2759 self.assertEqual(c.is_infinite(10), d)
2760 self.assertRaises(TypeError, c.is_infinite, '10')
2761
2762 def test_is_nan(self):
2763 Decimal = self.decimal.Decimal
2764 Context = self.decimal.Context
2765
2766 c = Context()
2767 d = c.is_nan(Decimal(10))
2768 self.assertEqual(c.is_nan(10), d)
2769 self.assertRaises(TypeError, c.is_nan, '10')
2770
2771 def test_is_normal(self):
2772 Decimal = self.decimal.Decimal
2773 Context = self.decimal.Context
2774
2775 c = Context()
2776 d = c.is_normal(Decimal(10))
2777 self.assertEqual(c.is_normal(10), d)
2778 self.assertRaises(TypeError, c.is_normal, '10')
2779
2780 def test_is_qnan(self):
2781 Decimal = self.decimal.Decimal
2782 Context = self.decimal.Context
2783
2784 c = Context()
2785 d = c.is_qnan(Decimal(10))
2786 self.assertEqual(c.is_qnan(10), d)
2787 self.assertRaises(TypeError, c.is_qnan, '10')
2788
2789 def test_is_signed(self):
2790 Decimal = self.decimal.Decimal
2791 Context = self.decimal.Context
2792
2793 c = Context()
2794 d = c.is_signed(Decimal(10))
2795 self.assertEqual(c.is_signed(10), d)
2796 self.assertRaises(TypeError, c.is_signed, '10')
2797
2798 def test_is_snan(self):
2799 Decimal = self.decimal.Decimal
2800 Context = self.decimal.Context
2801
2802 c = Context()
2803 d = c.is_snan(Decimal(10))
2804 self.assertEqual(c.is_snan(10), d)
2805 self.assertRaises(TypeError, c.is_snan, '10')
2806
2807 def test_is_subnormal(self):
2808 Decimal = self.decimal.Decimal
2809 Context = self.decimal.Context
2810
2811 c = Context()
2812 d = c.is_subnormal(Decimal(10))
2813 self.assertEqual(c.is_subnormal(10), d)
2814 self.assertRaises(TypeError, c.is_subnormal, '10')
2815
2816 def test_is_zero(self):
2817 Decimal = self.decimal.Decimal
2818 Context = self.decimal.Context
2819
2820 c = Context()
2821 d = c.is_zero(Decimal(10))
2822 self.assertEqual(c.is_zero(10), d)
2823 self.assertRaises(TypeError, c.is_zero, '10')
2824
2825 def test_ln(self):
2826 Decimal = self.decimal.Decimal
2827 Context = self.decimal.Context
2828
2829 c = Context()
2830 d = c.ln(Decimal(10))
2831 self.assertEqual(c.ln(10), d)
2832 self.assertRaises(TypeError, c.ln, '10')
2833
2834 def test_log10(self):
2835 Decimal = self.decimal.Decimal
2836 Context = self.decimal.Context
2837
2838 c = Context()
2839 d = c.log10(Decimal(10))
2840 self.assertEqual(c.log10(10), d)
2841 self.assertRaises(TypeError, c.log10, '10')
2842
2843 def test_logb(self):
2844 Decimal = self.decimal.Decimal
2845 Context = self.decimal.Context
2846
2847 c = Context()
2848 d = c.logb(Decimal(10))
2849 self.assertEqual(c.logb(10), d)
2850 self.assertRaises(TypeError, c.logb, '10')
2851
2852 def test_logical_and(self):
2853 Decimal = self.decimal.Decimal
2854 Context = self.decimal.Context
2855
2856 c = Context()
2857 d = c.logical_and(Decimal(1), Decimal(1))
2858 self.assertEqual(c.logical_and(1, 1), d)
2859 self.assertEqual(c.logical_and(Decimal(1), 1), d)
2860 self.assertEqual(c.logical_and(1, Decimal(1)), d)
2861 self.assertRaises(TypeError, c.logical_and, '1', 1)
2862 self.assertRaises(TypeError, c.logical_and, 1, '1')
2863
2864 def test_logical_invert(self):
2865 Decimal = self.decimal.Decimal
2866 Context = self.decimal.Context
2867
2868 c = Context()
2869 d = c.logical_invert(Decimal(1000))
2870 self.assertEqual(c.logical_invert(1000), d)
2871 self.assertRaises(TypeError, c.logical_invert, '1000')
2872
2873 def test_logical_or(self):
2874 Decimal = self.decimal.Decimal
2875 Context = self.decimal.Context
2876
2877 c = Context()
2878 d = c.logical_or(Decimal(1), Decimal(1))
2879 self.assertEqual(c.logical_or(1, 1), d)
2880 self.assertEqual(c.logical_or(Decimal(1), 1), d)
2881 self.assertEqual(c.logical_or(1, Decimal(1)), d)
2882 self.assertRaises(TypeError, c.logical_or, '1', 1)
2883 self.assertRaises(TypeError, c.logical_or, 1, '1')
2884
2885 def test_logical_xor(self):
2886 Decimal = self.decimal.Decimal
2887 Context = self.decimal.Context
2888
2889 c = Context()
2890 d = c.logical_xor(Decimal(1), Decimal(1))
2891 self.assertEqual(c.logical_xor(1, 1), d)
2892 self.assertEqual(c.logical_xor(Decimal(1), 1), d)
2893 self.assertEqual(c.logical_xor(1, Decimal(1)), d)
2894 self.assertRaises(TypeError, c.logical_xor, '1', 1)
2895 self.assertRaises(TypeError, c.logical_xor, 1, '1')
2896
2897 def test_max(self):
2898 Decimal = self.decimal.Decimal
2899 Context = self.decimal.Context
2900
2901 c = Context()
2902 d = c.max(Decimal(1), Decimal(2))
2903 self.assertEqual(c.max(1, 2), d)
2904 self.assertEqual(c.max(Decimal(1), 2), d)
2905 self.assertEqual(c.max(1, Decimal(2)), d)
2906 self.assertRaises(TypeError, c.max, '1', 2)
2907 self.assertRaises(TypeError, c.max, 1, '2')
2908
2909 def test_max_mag(self):
2910 Decimal = self.decimal.Decimal
2911 Context = self.decimal.Context
2912
2913 c = Context()
2914 d = c.max_mag(Decimal(1), Decimal(2))
2915 self.assertEqual(c.max_mag(1, 2), d)
2916 self.assertEqual(c.max_mag(Decimal(1), 2), d)
2917 self.assertEqual(c.max_mag(1, Decimal(2)), d)
2918 self.assertRaises(TypeError, c.max_mag, '1', 2)
2919 self.assertRaises(TypeError, c.max_mag, 1, '2')
2920
2921 def test_min(self):
2922 Decimal = self.decimal.Decimal
2923 Context = self.decimal.Context
2924
2925 c = Context()
2926 d = c.min(Decimal(1), Decimal(2))
2927 self.assertEqual(c.min(1, 2), d)
2928 self.assertEqual(c.min(Decimal(1), 2), d)
2929 self.assertEqual(c.min(1, Decimal(2)), d)
2930 self.assertRaises(TypeError, c.min, '1', 2)
2931 self.assertRaises(TypeError, c.min, 1, '2')
2932
2933 def test_min_mag(self):
2934 Decimal = self.decimal.Decimal
2935 Context = self.decimal.Context
2936
2937 c = Context()
2938 d = c.min_mag(Decimal(1), Decimal(2))
2939 self.assertEqual(c.min_mag(1, 2), d)
2940 self.assertEqual(c.min_mag(Decimal(1), 2), d)
2941 self.assertEqual(c.min_mag(1, Decimal(2)), d)
2942 self.assertRaises(TypeError, c.min_mag, '1', 2)
2943 self.assertRaises(TypeError, c.min_mag, 1, '2')
2944
2945 def test_minus(self):
2946 Decimal = self.decimal.Decimal
2947 Context = self.decimal.Context
2948
2949 c = Context()
2950 d = c.minus(Decimal(10))
2951 self.assertEqual(c.minus(10), d)
2952 self.assertRaises(TypeError, c.minus, '10')
2953
2954 def test_multiply(self):
2955 Decimal = self.decimal.Decimal
2956 Context = self.decimal.Context
2957
2958 c = Context()
2959 d = c.multiply(Decimal(1), Decimal(2))
2960 self.assertEqual(c.multiply(1, 2), d)
2961 self.assertEqual(c.multiply(Decimal(1), 2), d)
2962 self.assertEqual(c.multiply(1, Decimal(2)), d)
2963 self.assertRaises(TypeError, c.multiply, '1', 2)
2964 self.assertRaises(TypeError, c.multiply, 1, '2')
2965
2966 def test_next_minus(self):
2967 Decimal = self.decimal.Decimal
2968 Context = self.decimal.Context
2969
2970 c = Context()
2971 d = c.next_minus(Decimal(10))
2972 self.assertEqual(c.next_minus(10), d)
2973 self.assertRaises(TypeError, c.next_minus, '10')
2974
2975 def test_next_plus(self):
2976 Decimal = self.decimal.Decimal
2977 Context = self.decimal.Context
2978
2979 c = Context()
2980 d = c.next_plus(Decimal(10))
2981 self.assertEqual(c.next_plus(10), d)
2982 self.assertRaises(TypeError, c.next_plus, '10')
2983
2984 def test_next_toward(self):
2985 Decimal = self.decimal.Decimal
2986 Context = self.decimal.Context
2987
2988 c = Context()
2989 d = c.next_toward(Decimal(1), Decimal(2))
2990 self.assertEqual(c.next_toward(1, 2), d)
2991 self.assertEqual(c.next_toward(Decimal(1), 2), d)
2992 self.assertEqual(c.next_toward(1, Decimal(2)), d)
2993 self.assertRaises(TypeError, c.next_toward, '1', 2)
2994 self.assertRaises(TypeError, c.next_toward, 1, '2')
2995
2996 def test_normalize(self):
2997 Decimal = self.decimal.Decimal
2998 Context = self.decimal.Context
2999
3000 c = Context()
3001 d = c.normalize(Decimal(10))
3002 self.assertEqual(c.normalize(10), d)
3003 self.assertRaises(TypeError, c.normalize, '10')
3004
3005 def test_number_class(self):
3006 Decimal = self.decimal.Decimal
3007 Context = self.decimal.Context
3008
3009 c = Context()
3010 self.assertEqual(c.number_class(123), c.number_class(Decimal(123)))
3011 self.assertEqual(c.number_class(0), c.number_class(Decimal(0)))
3012 self.assertEqual(c.number_class(-45), c.number_class(Decimal(-45)))
3013
3014 def test_plus(self):
3015 Decimal = self.decimal.Decimal
3016 Context = self.decimal.Context
3017
3018 c = Context()
3019 d = c.plus(Decimal(10))
3020 self.assertEqual(c.plus(10), d)
3021 self.assertRaises(TypeError, c.plus, '10')
3022
3023 def test_power(self):
3024 Decimal = self.decimal.Decimal
3025 Context = self.decimal.Context
3026
3027 c = Context()
3028 d = c.power(Decimal(1), Decimal(4))
3029 self.assertEqual(c.power(1, 4), d)
3030 self.assertEqual(c.power(Decimal(1), 4), d)
3031 self.assertEqual(c.power(1, Decimal(4)), d)
3032 self.assertEqual(c.power(Decimal(1), Decimal(4)), d)
3033 self.assertRaises(TypeError, c.power, '1', 4)
3034 self.assertRaises(TypeError, c.power, 1, '4')
3035 self.assertEqual(c.power(modulo=5, b=8, a=2), 1)
3036
3037 def test_quantize(self):
3038 Decimal = self.decimal.Decimal
3039 Context = self.decimal.Context
3040
3041 c = Context()
3042 d = c.quantize(Decimal(1), Decimal(2))
3043 self.assertEqual(c.quantize(1, 2), d)
3044 self.assertEqual(c.quantize(Decimal(1), 2), d)
3045 self.assertEqual(c.quantize(1, Decimal(2)), d)
3046 self.assertRaises(TypeError, c.quantize, '1', 2)
3047 self.assertRaises(TypeError, c.quantize, 1, '2')
3048
3049 def test_remainder(self):
3050 Decimal = self.decimal.Decimal
3051 Context = self.decimal.Context
3052
3053 c = Context()
3054 d = c.remainder(Decimal(1), Decimal(2))
3055 self.assertEqual(c.remainder(1, 2), d)
3056 self.assertEqual(c.remainder(Decimal(1), 2), d)
3057 self.assertEqual(c.remainder(1, Decimal(2)), d)
3058 self.assertRaises(TypeError, c.remainder, '1', 2)
3059 self.assertRaises(TypeError, c.remainder, 1, '2')
3060
3061 def test_remainder_near(self):
3062 Decimal = self.decimal.Decimal
3063 Context = self.decimal.Context
3064
3065 c = Context()
3066 d = c.remainder_near(Decimal(1), Decimal(2))
3067 self.assertEqual(c.remainder_near(1, 2), d)
3068 self.assertEqual(c.remainder_near(Decimal(1), 2), d)
3069 self.assertEqual(c.remainder_near(1, Decimal(2)), d)
3070 self.assertRaises(TypeError, c.remainder_near, '1', 2)
3071 self.assertRaises(TypeError, c.remainder_near, 1, '2')
3072
3073 def test_rotate(self):
3074 Decimal = self.decimal.Decimal
3075 Context = self.decimal.Context
3076
3077 c = Context()
3078 d = c.rotate(Decimal(1), Decimal(2))
3079 self.assertEqual(c.rotate(1, 2), d)
3080 self.assertEqual(c.rotate(Decimal(1), 2), d)
3081 self.assertEqual(c.rotate(1, Decimal(2)), d)
3082 self.assertRaises(TypeError, c.rotate, '1', 2)
3083 self.assertRaises(TypeError, c.rotate, 1, '2')
3084
3085 def test_sqrt(self):
3086 Decimal = self.decimal.Decimal
3087 Context = self.decimal.Context
3088
3089 c = Context()
3090 d = c.sqrt(Decimal(10))
3091 self.assertEqual(c.sqrt(10), d)
3092 self.assertRaises(TypeError, c.sqrt, '10')
3093
3094 def test_same_quantum(self):
3095 Decimal = self.decimal.Decimal
3096 Context = self.decimal.Context
3097
3098 c = Context()
3099 d = c.same_quantum(Decimal(1), Decimal(2))
3100 self.assertEqual(c.same_quantum(1, 2), d)
3101 self.assertEqual(c.same_quantum(Decimal(1), 2), d)
3102 self.assertEqual(c.same_quantum(1, Decimal(2)), d)
3103 self.assertRaises(TypeError, c.same_quantum, '1', 2)
3104 self.assertRaises(TypeError, c.same_quantum, 1, '2')
3105
3106 def test_scaleb(self):
3107 Decimal = self.decimal.Decimal
3108 Context = self.decimal.Context
3109
3110 c = Context()
3111 d = c.scaleb(Decimal(1), Decimal(2))
3112 self.assertEqual(c.scaleb(1, 2), d)
3113 self.assertEqual(c.scaleb(Decimal(1), 2), d)
3114 self.assertEqual(c.scaleb(1, Decimal(2)), d)
3115 self.assertRaises(TypeError, c.scaleb, '1', 2)
3116 self.assertRaises(TypeError, c.scaleb, 1, '2')
3117
3118 def test_shift(self):
3119 Decimal = self.decimal.Decimal
3120 Context = self.decimal.Context
3121
3122 c = Context()
3123 d = c.shift(Decimal(1), Decimal(2))
3124 self.assertEqual(c.shift(1, 2), d)
3125 self.assertEqual(c.shift(Decimal(1), 2), d)
3126 self.assertEqual(c.shift(1, Decimal(2)), d)
3127 self.assertRaises(TypeError, c.shift, '1', 2)
3128 self.assertRaises(TypeError, c.shift, 1, '2')
3129
3130 def test_subtract(self):
3131 Decimal = self.decimal.Decimal
3132 Context = self.decimal.Context
3133
3134 c = Context()
3135 d = c.subtract(Decimal(1), Decimal(2))
3136 self.assertEqual(c.subtract(1, 2), d)
3137 self.assertEqual(c.subtract(Decimal(1), 2), d)
3138 self.assertEqual(c.subtract(1, Decimal(2)), d)
3139 self.assertRaises(TypeError, c.subtract, '1', 2)
3140 self.assertRaises(TypeError, c.subtract, 1, '2')
3141
3142 def test_to_eng_string(self):
3143 Decimal = self.decimal.Decimal
3144 Context = self.decimal.Context
3145
3146 c = Context()
3147 d = c.to_eng_string(Decimal(10))
3148 self.assertEqual(c.to_eng_string(10), d)
3149 self.assertRaises(TypeError, c.to_eng_string, '10')
3150
3151 def test_to_sci_string(self):
3152 Decimal = self.decimal.Decimal
3153 Context = self.decimal.Context
3154
3155 c = Context()
3156 d = c.to_sci_string(Decimal(10))
3157 self.assertEqual(c.to_sci_string(10), d)
3158 self.assertRaises(TypeError, c.to_sci_string, '10')
3159
3160 def test_to_integral_exact(self):
3161 Decimal = self.decimal.Decimal
3162 Context = self.decimal.Context
3163
3164 c = Context()
3165 d = c.to_integral_exact(Decimal(10))
3166 self.assertEqual(c.to_integral_exact(10), d)
3167 self.assertRaises(TypeError, c.to_integral_exact, '10')
3168
3169 def test_to_integral_value(self):
3170 Decimal = self.decimal.Decimal
3171 Context = self.decimal.Context
3172
3173 c = Context()
3174 d = c.to_integral_value(Decimal(10))
3175 self.assertEqual(c.to_integral_value(10), d)
3176 self.assertRaises(TypeError, c.to_integral_value, '10')
3177 self.assertRaises(TypeError, c.to_integral_value, 10, 'x')
3178
3179class CContextAPItests(ContextAPItests):
3180 decimal = C
3181class PyContextAPItests(ContextAPItests):
3182 decimal = P
3183
3184class ContextWithStatement(unittest.TestCase):
3185 # Can't do these as docstrings until Python 2.6
3186 # as doctest can't handle __future__ statements
3187
3188 def test_localcontext(self):
3189 # Use a copy of the current context in the block
3190 getcontext = self.decimal.getcontext
3191 localcontext = self.decimal.localcontext
3192
3193 orig_ctx = getcontext()
3194 with localcontext() as enter_ctx:
3195 set_ctx = getcontext()
3196 final_ctx = getcontext()
3197 self.assertIs(orig_ctx, final_ctx, 'did not restore context correctly')
3198 self.assertIsNot(orig_ctx, set_ctx, 'did not copy the context')
3199 self.assertIs(set_ctx, enter_ctx, '__enter__ returned wrong context')
3200
3201 def test_localcontextarg(self):
3202 # Use a copy of the supplied context in the block
3203 Context = self.decimal.Context
3204 getcontext = self.decimal.getcontext
3205 localcontext = self.decimal.localcontext
3206
3207 localcontext = self.decimal.localcontext
3208 orig_ctx = getcontext()
3209 new_ctx = Context(prec=42)
3210 with localcontext(new_ctx) as enter_ctx:
3211 set_ctx = getcontext()
3212 final_ctx = getcontext()
3213 self.assertIs(orig_ctx, final_ctx, 'did not restore context correctly')
3214 self.assertEqual(set_ctx.prec, new_ctx.prec, 'did not set correct context')
3215 self.assertIsNot(new_ctx, set_ctx, 'did not copy the context')
3216 self.assertIs(set_ctx, enter_ctx, '__enter__ returned wrong context')
3217
3218 def test_nested_with_statements(self):
3219 # Use a copy of the supplied context in the block
3220 Decimal = self.decimal.Decimal
3221 Context = self.decimal.Context
3222 getcontext = self.decimal.getcontext
3223 localcontext = self.decimal.localcontext
3224 Clamped = self.decimal.Clamped
3225 Overflow = self.decimal.Overflow
3226
3227 orig_ctx = getcontext()
3228 orig_ctx.clear_flags()
3229 new_ctx = Context(Emax=384)
3230 with localcontext() as c1:
3231 self.assertEqual(c1.flags, orig_ctx.flags)
3232 self.assertEqual(c1.traps, orig_ctx.traps)
3233 c1.traps[Clamped] = True
3234 c1.Emin = -383
3235 self.assertNotEqual(orig_ctx.Emin, -383)
3236 self.assertRaises(Clamped, c1.create_decimal, '0e-999')
3237 self.assertTrue(c1.flags[Clamped])
3238 with localcontext(new_ctx) as c2:
3239 self.assertEqual(c2.flags, new_ctx.flags)
3240 self.assertEqual(c2.traps, new_ctx.traps)
3241 self.assertRaises(Overflow, c2.power, Decimal('3.4e200'), 2)
3242 self.assertFalse(c2.flags[Clamped])
3243 self.assertTrue(c2.flags[Overflow])
3244 del c2
3245 self.assertFalse(c1.flags[Overflow])
3246 del c1
3247 self.assertNotEqual(orig_ctx.Emin, -383)
3248 self.assertFalse(orig_ctx.flags[Clamped])
3249 self.assertFalse(orig_ctx.flags[Overflow])
3250 self.assertFalse(new_ctx.flags[Clamped])
3251 self.assertFalse(new_ctx.flags[Overflow])
3252
3253 def test_with_statements_gc1(self):
3254 localcontext = self.decimal.localcontext
3255
3256 with localcontext() as c1:
3257 del c1
3258 with localcontext() as c2:
3259 del c2
3260 with localcontext() as c3:
3261 del c3
3262 with localcontext() as c4:
3263 del c4
3264
3265 def test_with_statements_gc2(self):
3266 localcontext = self.decimal.localcontext
3267
3268 with localcontext() as c1:
3269 with localcontext(c1) as c2:
3270 del c1
3271 with localcontext(c2) as c3:
3272 del c2
3273 with localcontext(c3) as c4:
3274 del c3
3275 del c4
3276
3277 def test_with_statements_gc3(self):
3278 Context = self.decimal.Context
3279 localcontext = self.decimal.localcontext
3280 getcontext = self.decimal.getcontext
3281 setcontext = self.decimal.setcontext
3282
3283 with localcontext() as c1:
3284 del c1
3285 n1 = Context(prec=1)
3286 setcontext(n1)
3287 with localcontext(n1) as c2:
3288 del n1
3289 self.assertEqual(c2.prec, 1)
3290 del c2
3291 n2 = Context(prec=2)
3292 setcontext(n2)
3293 del n2
3294 self.assertEqual(getcontext().prec, 2)
3295 n3 = Context(prec=3)
3296 setcontext(n3)
3297 self.assertEqual(getcontext().prec, 3)
3298 with localcontext(n3) as c3:
3299 del n3
3300 self.assertEqual(c3.prec, 3)
3301 del c3
3302 n4 = Context(prec=4)
3303 setcontext(n4)
3304 del n4
3305 self.assertEqual(getcontext().prec, 4)
3306 with localcontext() as c4:
3307 self.assertEqual(c4.prec, 4)
3308 del c4
3309
3310class CContextWithStatement(ContextWithStatement):
3311 decimal = C
3312class PyContextWithStatement(ContextWithStatement):
3313 decimal = P
3314
3315class ContextFlags(unittest.TestCase):
3316
3317 def test_flags_irrelevant(self):
3318 # check that the result (numeric result + flags raised) of an
3319 # arithmetic operation doesn't depend on the current flags
3320 Decimal = self.decimal.Decimal
3321 Context = self.decimal.Context
3322 Inexact = self.decimal.Inexact
3323 Rounded = self.decimal.Rounded
3324 Underflow = self.decimal.Underflow
3325 Clamped = self.decimal.Clamped
3326 Subnormal = self.decimal.Subnormal
3327 ROUND_HALF_EVEN = self.decimal.ROUND_HALF_EVEN
3328
3329 def raise_error(context, flag):
3330 if self.decimal == C:
3331 context.flags[flag] = True
3332 if context.traps[flag]:
3333 raise flag
3334 else:
3335 context._raise_error(flag)
3336
3337 context = Context(prec=9, Emin = -425000000, Emax = 425000000,
3338 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
3339
3340 # operations that raise various flags, in the form (function, arglist)
3341 operations = [
3342 (context._apply, [Decimal("100E-425000010")]),
3343 (context.sqrt, [Decimal(2)]),
3344 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
3345 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
3346 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
3347 ]
3348
3349 # try various flags individually, then a whole lot at once
3350 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
3351 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
3352
3353 for fn, args in operations:
3354 # find answer and flags raised using a clean context
3355 context.clear_flags()
3356 ans = fn(*args)
3357 flags = [k for k, v in context.flags.items() if v]
3358
3359 for extra_flags in flagsets:
3360 # set flags, before calling operation
3361 context.clear_flags()
3362 for flag in extra_flags:
3363 raise_error(context, flag)
3364 new_ans = fn(*args)
3365
3366 # flags that we expect to be set after the operation
3367 expected_flags = list(flags)
3368 for flag in extra_flags:
3369 if flag not in expected_flags:
3370 expected_flags.append(flag)
3371 expected_flags.sort(key=id)
3372
3373 # flags we actually got
3374 new_flags = [k for k,v in context.flags.items() if v]
3375 new_flags.sort(key=id)
3376
3377 self.assertEqual(ans, new_ans,
3378 "operation produces different answers depending on flags set: " +
3379 "expected %s, got %s." % (ans, new_ans))
3380 self.assertEqual(new_flags, expected_flags,
3381 "operation raises different flags depending on flags set: " +
3382 "expected %s, got %s" % (expected_flags, new_flags))
3383
3384 def test_flag_comparisons(self):
3385 Context = self.decimal.Context
3386 Inexact = self.decimal.Inexact
3387 Rounded = self.decimal.Rounded
3388
3389 c = Context()
3390
3391 # Valid SignalDict
3392 self.assertNotEqual(c.flags, c.traps)
3393 self.assertNotEqual(c.traps, c.flags)
3394
3395 c.flags = c.traps
3396 self.assertEqual(c.flags, c.traps)
3397 self.assertEqual(c.traps, c.flags)
3398
3399 c.flags[Rounded] = True
3400 c.traps = c.flags
3401 self.assertEqual(c.flags, c.traps)
3402 self.assertEqual(c.traps, c.flags)
3403
3404 d = {}
3405 d.update(c.flags)
3406 self.assertEqual(d, c.flags)
3407 self.assertEqual(c.flags, d)
3408
3409 d[Inexact] = True
3410 self.assertNotEqual(d, c.flags)
3411 self.assertNotEqual(c.flags, d)
3412
3413 # Invalid SignalDict
3414 d = {Inexact:False}
3415 self.assertNotEqual(d, c.flags)
3416 self.assertNotEqual(c.flags, d)
3417
3418 d = ["xyz"]
3419 self.assertNotEqual(d, c.flags)
3420 self.assertNotEqual(c.flags, d)
3421
3422 @requires_IEEE_754
3423 def test_float_operation(self):
3424 Decimal = self.decimal.Decimal
3425 FloatOperation = self.decimal.FloatOperation
3426 localcontext = self.decimal.localcontext
3427
3428 with localcontext() as c:
3429 ##### trap is off by default
3430 self.assertFalse(c.traps[FloatOperation])
3431
3432 # implicit conversion sets the flag
3433 c.clear_flags()
3434 self.assertEqual(Decimal(7.5), 7.5)
3435 self.assertTrue(c.flags[FloatOperation])
3436
3437 c.clear_flags()
3438 self.assertEqual(c.create_decimal(7.5), 7.5)
3439 self.assertTrue(c.flags[FloatOperation])
3440
3441 # explicit conversion does not set the flag
3442 c.clear_flags()
3443 x = Decimal.from_float(7.5)
3444 self.assertFalse(c.flags[FloatOperation])
3445 # comparison sets the flag
3446 self.assertEqual(x, 7.5)
3447 self.assertTrue(c.flags[FloatOperation])
3448
3449 c.clear_flags()
3450 x = c.create_decimal_from_float(7.5)
3451 self.assertFalse(c.flags[FloatOperation])
3452 self.assertEqual(x, 7.5)
3453 self.assertTrue(c.flags[FloatOperation])
3454
3455 ##### set the trap
3456 c.traps[FloatOperation] = True
3457
3458 # implicit conversion raises
3459 c.clear_flags()
3460 self.assertRaises(FloatOperation, Decimal, 7.5)
3461 self.assertTrue(c.flags[FloatOperation])
3462
3463 c.clear_flags()
3464 self.assertRaises(FloatOperation, c.create_decimal, 7.5)
3465 self.assertTrue(c.flags[FloatOperation])
3466
3467 # explicit conversion is silent
3468 c.clear_flags()
3469 x = Decimal.from_float(7.5)
3470 self.assertFalse(c.flags[FloatOperation])
3471
3472 c.clear_flags()
3473 x = c.create_decimal_from_float(7.5)
3474 self.assertFalse(c.flags[FloatOperation])
3475
3476 def test_float_comparison(self):
3477 Decimal = self.decimal.Decimal
3478 Context = self.decimal.Context
3479 FloatOperation = self.decimal.FloatOperation
3480 localcontext = self.decimal.localcontext
3481
3482 def assert_attr(a, b, attr, context, signal=None):
3483 context.clear_flags()
3484 f = getattr(a, attr)
3485 if signal == FloatOperation:
3486 self.assertRaises(signal, f, b)
3487 else:
3488 self.assertIs(f(b), True)
3489 self.assertTrue(context.flags[FloatOperation])
3490
3491 small_d = Decimal('0.25')
3492 big_d = Decimal('3.0')
3493 small_f = 0.25
3494 big_f = 3.0
3495
3496 zero_d = Decimal('0.0')
3497 neg_zero_d = Decimal('-0.0')
3498 zero_f = 0.0
3499 neg_zero_f = -0.0
3500
3501 inf_d = Decimal('Infinity')
3502 neg_inf_d = Decimal('-Infinity')
3503 inf_f = float('inf')
3504 neg_inf_f = float('-inf')
3505
3506 def doit(c, signal=None):
3507 # Order
3508 for attr in '__lt__', '__le__':
3509 assert_attr(small_d, big_f, attr, c, signal)
3510
3511 for attr in '__gt__', '__ge__':
3512 assert_attr(big_d, small_f, attr, c, signal)
3513
3514 # Equality
3515 assert_attr(small_d, small_f, '__eq__', c, None)
3516
3517 assert_attr(neg_zero_d, neg_zero_f, '__eq__', c, None)
3518 assert_attr(neg_zero_d, zero_f, '__eq__', c, None)
3519
3520 assert_attr(zero_d, neg_zero_f, '__eq__', c, None)
3521 assert_attr(zero_d, zero_f, '__eq__', c, None)
3522
3523 assert_attr(neg_inf_d, neg_inf_f, '__eq__', c, None)
3524 assert_attr(inf_d, inf_f, '__eq__', c, None)
3525
3526 # Inequality
3527 assert_attr(small_d, big_f, '__ne__', c, None)
3528
3529 assert_attr(Decimal('0.1'), 0.1, '__ne__', c, None)
3530
3531 assert_attr(neg_inf_d, inf_f, '__ne__', c, None)
3532 assert_attr(inf_d, neg_inf_f, '__ne__', c, None)
3533
3534 assert_attr(Decimal('NaN'), float('nan'), '__ne__', c, None)
3535
3536 def test_containers(c, signal=None):
3537 c.clear_flags()
3538 s = set([100.0, Decimal('100.0')])
3539 self.assertEqual(len(s), 1)
3540 self.assertTrue(c.flags[FloatOperation])
3541
3542 c.clear_flags()
3543 if signal:
3544 self.assertRaises(signal, sorted, [1.0, Decimal('10.0')])
3545 else:
3546 s = sorted([10.0, Decimal('10.0')])
3547 self.assertTrue(c.flags[FloatOperation])
3548
3549 c.clear_flags()
3550 b = 10.0 in [Decimal('10.0'), 1.0]
3551 self.assertTrue(c.flags[FloatOperation])
3552
3553 c.clear_flags()
3554 b = 10.0 in {Decimal('10.0'):'a', 1.0:'b'}
3555 self.assertTrue(c.flags[FloatOperation])
3556
3557 nc = Context()
3558 with localcontext(nc) as c:
3559 self.assertFalse(c.traps[FloatOperation])
3560 doit(c, signal=None)
3561 test_containers(c, signal=None)
3562
3563 c.traps[FloatOperation] = True
3564 doit(c, signal=FloatOperation)
3565 test_containers(c, signal=FloatOperation)
3566
3567 def test_float_operation_default(self):
3568 Decimal = self.decimal.Decimal
3569 Context = self.decimal.Context
3570 Inexact = self.decimal.Inexact
3571 FloatOperation= self.decimal.FloatOperation
3572
3573 context = Context()
3574 self.assertFalse(context.flags[FloatOperation])
3575 self.assertFalse(context.traps[FloatOperation])
3576
3577 context.clear_traps()
3578 context.traps[Inexact] = True
3579 context.traps[FloatOperation] = True
3580 self.assertTrue(context.traps[FloatOperation])
3581 self.assertTrue(context.traps[Inexact])
3582
3583class CContextFlags(ContextFlags):
3584 decimal = C
3585class PyContextFlags(ContextFlags):
3586 decimal = P
3587
3588class SpecialContexts(unittest.TestCase):
3589 """Test the context templates."""
3590
3591 def test_context_templates(self):
3592 BasicContext = self.decimal.BasicContext
3593 ExtendedContext = self.decimal.ExtendedContext
3594 getcontext = self.decimal.getcontext
3595 setcontext = self.decimal.setcontext
3596 InvalidOperation = self.decimal.InvalidOperation
3597 DivisionByZero = self.decimal.DivisionByZero
3598 Overflow = self.decimal.Overflow
3599 Underflow = self.decimal.Underflow
3600 Clamped = self.decimal.Clamped
3601
3602 assert_signals(self, BasicContext, 'traps',
3603 [InvalidOperation, DivisionByZero, Overflow, Underflow, Clamped]
3604 )
3605
3606 savecontext = getcontext().copy()
3607 basic_context_prec = BasicContext.prec
3608 extended_context_prec = ExtendedContext.prec
3609
3610 ex = None
3611 try:
3612 BasicContext.prec = ExtendedContext.prec = 441
3613 for template in BasicContext, ExtendedContext:
3614 setcontext(template)
3615 c = getcontext()
3616 self.assertIsNot(c, template)
3617 self.assertEqual(c.prec, 441)
3618 except Exception as e:
3619 ex = e.__class__
3620 finally:
3621 BasicContext.prec = basic_context_prec
3622 ExtendedContext.prec = extended_context_prec
3623 setcontext(savecontext)
3624 if ex:
3625 raise ex
3626
3627 def test_default_context(self):
3628 DefaultContext = self.decimal.DefaultContext
3629 BasicContext = self.decimal.BasicContext
3630 ExtendedContext = self.decimal.ExtendedContext
3631 getcontext = self.decimal.getcontext
3632 setcontext = self.decimal.setcontext
3633 InvalidOperation = self.decimal.InvalidOperation
3634 DivisionByZero = self.decimal.DivisionByZero
3635 Overflow = self.decimal.Overflow
3636
3637 self.assertEqual(BasicContext.prec, 9)
3638 self.assertEqual(ExtendedContext.prec, 9)
3639
3640 assert_signals(self, DefaultContext, 'traps',
3641 [InvalidOperation, DivisionByZero, Overflow]
3642 )
3643
3644 savecontext = getcontext().copy()
3645 default_context_prec = DefaultContext.prec
3646
3647 ex = None
3648 try:
3649 c = getcontext()
3650 saveprec = c.prec
3651
3652 DefaultContext.prec = 961
3653 c = getcontext()
3654 self.assertEqual(c.prec, saveprec)
3655
3656 setcontext(DefaultContext)
3657 c = getcontext()
3658 self.assertIsNot(c, DefaultContext)
3659 self.assertEqual(c.prec, 961)
3660 except Exception as e:
3661 ex = e.__class__
3662 finally:
3663 DefaultContext.prec = default_context_prec
3664 setcontext(savecontext)
3665 if ex:
3666 raise ex
3667
3668class CSpecialContexts(SpecialContexts):
3669 decimal = C
3670class PySpecialContexts(SpecialContexts):
3671 decimal = P
3672
3673class ContextInputValidation(unittest.TestCase):
3674
3675 def test_invalid_context(self):
3676 Context = self.decimal.Context
3677 DefaultContext = self.decimal.DefaultContext
3678
3679 c = DefaultContext.copy()
3680
3681 # prec, Emax
3682 for attr in ['prec', 'Emax']:
3683 setattr(c, attr, 999999)
3684 self.assertEqual(getattr(c, attr), 999999)
3685 self.assertRaises(ValueError, setattr, c, attr, -1)
3686 self.assertRaises(TypeError, setattr, c, attr, 'xyz')
3687
3688 # Emin
3689 setattr(c, 'Emin', -999999)
3690 self.assertEqual(getattr(c, 'Emin'), -999999)
3691 self.assertRaises(ValueError, setattr, c, 'Emin', 1)
3692 self.assertRaises(TypeError, setattr, c, 'Emin', (1,2,3))
3693
3694 # rounding: always raise TypeError in order to get consistent
3695 # exceptions across implementations. In decimal, rounding
3696 # modes are strings, in _decimal they are integers. The idea
3697 # is to view rounding as an abstract type and not mind the
3698 # implementation details.
3699 # Hence, a user should view the rounding modes as if they
3700 # had been defined in a language that supports abstract
3701 # data types, e.g. ocaml:
3702 #
3703 # type rounding = ROUND_DOWN | ROUND_HALF_UP | ... ;;
3704 #
3705 self.assertRaises(TypeError, setattr, c, 'rounding', -1)
3706 self.assertRaises(TypeError, setattr, c, 'rounding', 9)
3707 self.assertRaises(TypeError, setattr, c, 'rounding', 1.0)
3708 self.assertRaises(TypeError, setattr, c, 'rounding', 'xyz')
3709
3710 # capitals, clamp
3711 for attr in ['capitals', 'clamp']:
3712 self.assertRaises(ValueError, setattr, c, attr, -1)
3713 self.assertRaises(ValueError, setattr, c, attr, 2)
3714 self.assertRaises(TypeError, setattr, c, attr, [1,2,3])
3715
3716 # Invalid attribute
3717 self.assertRaises(AttributeError, setattr, c, 'emax', 100)
3718
3719 # Invalid signal dict
3720 self.assertRaises(TypeError, setattr, c, 'flags', [])
3721 self.assertRaises(KeyError, setattr, c, 'flags', {})
3722 self.assertRaises(KeyError, setattr, c, 'traps',
3723 {'InvalidOperation':0})
3724
3725 # Attributes cannot be deleted
3726 for attr in ['prec', 'Emax', 'Emin', 'rounding', 'capitals', 'clamp',
3727 'flags', 'traps']:
3728 self.assertRaises(AttributeError, c.__delattr__, attr)
3729
3730 # Invalid attributes
3731 self.assertRaises(TypeError, getattr, c, 9)
3732 self.assertRaises(TypeError, setattr, c, 9)
3733
3734 # Invalid values in constructor
3735 self.assertRaises(TypeError, Context, rounding=999999)
3736 self.assertRaises(TypeError, Context, rounding='xyz')
3737 self.assertRaises(ValueError, Context, clamp=2)
3738 self.assertRaises(ValueError, Context, capitals=-1)
3739 self.assertRaises(KeyError, Context, flags=["P"])
3740 self.assertRaises(KeyError, Context, traps=["Q"])
3741
3742 # Type error in conversion
3743 self.assertRaises(TypeError, Context, flags=(0,1))
3744 self.assertRaises(TypeError, Context, traps=(1,0))
3745
3746class CContextInputValidation(ContextInputValidation):
3747 decimal = C
3748class PyContextInputValidation(ContextInputValidation):
3749 decimal = P
3750
3751class ContextSubclassing(unittest.TestCase):
3752
3753 def test_context_subclassing(self):
3754 decimal = self.decimal
3755 Decimal = decimal.Decimal
3756 Context = decimal.Context
3757 ROUND_HALF_EVEN = decimal.ROUND_HALF_EVEN
3758 ROUND_DOWN = decimal.ROUND_DOWN
3759 Clamped = decimal.Clamped
3760 DivisionByZero = decimal.DivisionByZero
3761 Inexact = decimal.Inexact
3762 Overflow = decimal.Overflow
3763 Rounded = decimal.Rounded
3764 Subnormal = decimal.Subnormal
3765 Underflow = decimal.Underflow
3766 InvalidOperation = decimal.InvalidOperation
3767
3768 class MyContext(Context):
3769 def __init__(self, prec=None, rounding=None, Emin=None, Emax=None,
3770 capitals=None, clamp=None, flags=None,
3771 traps=None):
3772 Context.__init__(self)
3773 if prec is not None:
3774 self.prec = prec
3775 if rounding is not None:
3776 self.rounding = rounding
3777 if Emin is not None:
3778 self.Emin = Emin
3779 if Emax is not None:
3780 self.Emax = Emax
3781 if capitals is not None:
3782 self.capitals = capitals
3783 if clamp is not None:
3784 self.clamp = clamp
3785 if flags is not None:
3786 if isinstance(flags, list):
3787 flags = {v:(v in flags) for v in OrderedSignals[decimal] + flags}
3788 self.flags = flags
3789 if traps is not None:
3790 if isinstance(traps, list):
3791 traps = {v:(v in traps) for v in OrderedSignals[decimal] + traps}
3792 self.traps = traps
3793
3794 c = Context()
3795 d = MyContext()
3796 for attr in ('prec', 'rounding', 'Emin', 'Emax', 'capitals', 'clamp',
3797 'flags', 'traps'):
3798 self.assertEqual(getattr(c, attr), getattr(d, attr))
3799
3800 # prec
3801 self.assertRaises(ValueError, MyContext, **{'prec':-1})
3802 c = MyContext(prec=1)
3803 self.assertEqual(c.prec, 1)
3804 self.assertRaises(InvalidOperation, c.quantize, Decimal('9e2'), 0)
3805
3806 # rounding
3807 self.assertRaises(TypeError, MyContext, **{'rounding':'XYZ'})
3808 c = MyContext(rounding=ROUND_DOWN, prec=1)
3809 self.assertEqual(c.rounding, ROUND_DOWN)
3810 self.assertEqual(c.plus(Decimal('9.9')), 9)
3811
3812 # Emin
3813 self.assertRaises(ValueError, MyContext, **{'Emin':5})
3814 c = MyContext(Emin=-1, prec=1)
3815 self.assertEqual(c.Emin, -1)
3816 x = c.add(Decimal('1e-99'), Decimal('2.234e-2000'))
3817 self.assertEqual(x, Decimal('0.0'))
3818 for signal in (Inexact, Underflow, Subnormal, Rounded, Clamped):
3819 self.assertTrue(c.flags[signal])
3820
3821 # Emax
3822 self.assertRaises(ValueError, MyContext, **{'Emax':-1})
3823 c = MyContext(Emax=1, prec=1)
3824 self.assertEqual(c.Emax, 1)
3825 self.assertRaises(Overflow, c.add, Decimal('1e99'), Decimal('2.234e2000'))
3826 if self.decimal == C:
3827 for signal in (Inexact, Overflow, Rounded):
3828 self.assertTrue(c.flags[signal])
3829
3830 # capitals
3831 self.assertRaises(ValueError, MyContext, **{'capitals':-1})
3832 c = MyContext(capitals=0)
3833 self.assertEqual(c.capitals, 0)
3834 x = c.create_decimal('1E222')
3835 self.assertEqual(c.to_sci_string(x), '1e+222')
3836
3837 # clamp
3838 self.assertRaises(ValueError, MyContext, **{'clamp':2})
3839 c = MyContext(clamp=1, Emax=99)
3840 self.assertEqual(c.clamp, 1)
3841 x = c.plus(Decimal('1e99'))
3842 self.assertEqual(str(x), '1.000000000000000000000000000E+99')
3843
3844 # flags
3845 self.assertRaises(TypeError, MyContext, **{'flags':'XYZ'})
3846 c = MyContext(flags=[Rounded, DivisionByZero])
3847 for signal in (Rounded, DivisionByZero):
3848 self.assertTrue(c.flags[signal])
3849 c.clear_flags()
3850 for signal in OrderedSignals[decimal]:
3851 self.assertFalse(c.flags[signal])
3852
3853 # traps
3854 self.assertRaises(TypeError, MyContext, **{'traps':'XYZ'})
3855 c = MyContext(traps=[Rounded, DivisionByZero])
3856 for signal in (Rounded, DivisionByZero):
3857 self.assertTrue(c.traps[signal])
3858 c.clear_traps()
3859 for signal in OrderedSignals[decimal]:
3860 self.assertFalse(c.traps[signal])
3861
3862class CContextSubclassing(ContextSubclassing):
3863 decimal = C
3864class PyContextSubclassing(ContextSubclassing):
3865 decimal = P
3866
3867@skip_if_extra_functionality
3868class CheckAttributes(unittest.TestCase):
3869
3870 def test_module_attributes(self):
3871
3872 # Architecture dependent context limits
3873 self.assertEqual(C.MAX_PREC, P.MAX_PREC)
3874 self.assertEqual(C.MAX_EMAX, P.MAX_EMAX)
3875 self.assertEqual(C.MIN_EMIN, P.MIN_EMIN)
3876 self.assertEqual(C.MIN_ETINY, P.MIN_ETINY)
3877
3878 self.assertTrue(C.HAVE_THREADS is True or C.HAVE_THREADS is False)
3879 self.assertTrue(P.HAVE_THREADS is True or P.HAVE_THREADS is False)
3880
3881 self.assertEqual(C.__version__, P.__version__)
3882
3883 x = dir(C)
3884 y = [s for s in dir(P) if '__' in s or not s.startswith('_')]
Stefan Krahfe17b2b2012-03-25 18:59:21 +02003885 self.assertEqual(set(x) - set(y), set())
Stefan Krah1919b7e2012-03-21 18:25:23 +01003886
3887 def test_context_attributes(self):
3888
3889 x = [s for s in dir(C.Context()) if '__' in s or not s.startswith('_')]
3890 y = [s for s in dir(P.Context()) if '__' in s or not s.startswith('_')]
3891 self.assertEqual(set(x) - set(y), set())
3892
3893 def test_decimal_attributes(self):
3894
3895 x = [s for s in dir(C.Decimal(9)) if '__' in s or not s.startswith('_')]
3896 y = [s for s in dir(C.Decimal(9)) if '__' in s or not s.startswith('_')]
3897 self.assertEqual(set(x) - set(y), set())
3898
3899class Coverage(unittest.TestCase):
3900
3901 def test_adjusted(self):
3902 Decimal = self.decimal.Decimal
3903
3904 self.assertEqual(Decimal('1234e9999').adjusted(), 10002)
3905 # XXX raise?
3906 self.assertEqual(Decimal('nan').adjusted(), 0)
3907 self.assertEqual(Decimal('inf').adjusted(), 0)
3908
3909 def test_canonical(self):
3910 Decimal = self.decimal.Decimal
3911 getcontext = self.decimal.getcontext
3912
3913 x = Decimal(9).canonical()
3914 self.assertEqual(x, 9)
3915
3916 c = getcontext()
3917 x = c.canonical(Decimal(9))
3918 self.assertEqual(x, 9)
3919
3920 def test_context_repr(self):
3921 c = self.decimal.DefaultContext.copy()
3922
3923 c.prec = 425000000
3924 c.Emax = 425000000
3925 c.Emin = -425000000
3926 c.rounding = self.decimal.ROUND_HALF_DOWN
3927 c.capitals = 0
3928 c.clamp = 1
3929 for sig in OrderedSignals[self.decimal]:
3930 c.flags[sig] = False
3931 c.traps[sig] = False
3932
3933 s = c.__repr__()
3934 t = "Context(prec=425000000, rounding=ROUND_HALF_DOWN, " \
3935 "Emin=-425000000, Emax=425000000, capitals=0, clamp=1, " \
3936 "flags=[], traps=[])"
3937 self.assertEqual(s, t)
3938
3939 def test_implicit_context(self):
3940 Decimal = self.decimal.Decimal
3941 localcontext = self.decimal.localcontext
3942
3943 with localcontext() as c:
3944 c.prec = 1
3945 c.Emax = 1
3946 c.Emin = -1
3947
3948 # abs
3949 self.assertEqual(abs(Decimal("-10")), 10)
3950 # add
3951 self.assertEqual(Decimal("7") + 1, 8)
3952 # divide
3953 self.assertEqual(Decimal("10") / 5, 2)
3954 # divide_int
3955 self.assertEqual(Decimal("10") // 7, 1)
3956 # fma
3957 self.assertEqual(Decimal("1.2").fma(Decimal("0.01"), 1), 1)
3958 self.assertIs(Decimal("NaN").fma(7, 1).is_nan(), True)
3959 # three arg power
3960 self.assertEqual(pow(Decimal(10), 2, 7), 2)
3961 # exp
3962 self.assertEqual(Decimal("1.01").exp(), 3)
3963 # is_normal
3964 self.assertIs(Decimal("0.01").is_normal(), False)
3965 # is_subnormal
3966 self.assertIs(Decimal("0.01").is_subnormal(), True)
3967 # ln
3968 self.assertEqual(Decimal("20").ln(), 3)
3969 # log10
3970 self.assertEqual(Decimal("20").log10(), 1)
3971 # logb
3972 self.assertEqual(Decimal("580").logb(), 2)
3973 # logical_invert
3974 self.assertEqual(Decimal("10").logical_invert(), 1)
3975 # minus
3976 self.assertEqual(-Decimal("-10"), 10)
3977 # multiply
3978 self.assertEqual(Decimal("2") * 4, 8)
3979 # next_minus
3980 self.assertEqual(Decimal("10").next_minus(), 9)
3981 # next_plus
3982 self.assertEqual(Decimal("10").next_plus(), Decimal('2E+1'))
3983 # normalize
3984 self.assertEqual(Decimal("-10").normalize(), Decimal('-1E+1'))
3985 # number_class
3986 self.assertEqual(Decimal("10").number_class(), '+Normal')
3987 # plus
3988 self.assertEqual(+Decimal("-1"), -1)
3989 # remainder
3990 self.assertEqual(Decimal("10") % 7, 3)
3991 # subtract
3992 self.assertEqual(Decimal("10") - 7, 3)
3993 # to_integral_exact
3994 self.assertEqual(Decimal("1.12345").to_integral_exact(), 1)
3995
3996 # Boolean functions
3997 self.assertTrue(Decimal("1").is_canonical())
3998 self.assertTrue(Decimal("1").is_finite())
3999 self.assertTrue(Decimal("1").is_finite())
4000 self.assertTrue(Decimal("snan").is_snan())
4001 self.assertTrue(Decimal("-1").is_signed())
4002 self.assertTrue(Decimal("0").is_zero())
4003 self.assertTrue(Decimal("0").is_zero())
4004
4005 # Copy
4006 with localcontext() as c:
4007 c.prec = 10000
4008 x = 1228 ** 1523
4009 y = -Decimal(x)
4010
4011 z = y.copy_abs()
4012 self.assertEqual(z, x)
4013
4014 z = y.copy_negate()
4015 self.assertEqual(z, x)
4016
4017 z = y.copy_sign(Decimal(1))
4018 self.assertEqual(z, x)
4019
4020 def test_divmod(self):
4021 Decimal = self.decimal.Decimal
4022 localcontext = self.decimal.localcontext
4023 InvalidOperation = self.decimal.InvalidOperation
4024 DivisionByZero = self.decimal.DivisionByZero
4025
4026 with localcontext() as c:
4027 q, r = divmod(Decimal("10912837129"), 1001)
4028 self.assertEqual(q, Decimal('10901935'))
4029 self.assertEqual(r, Decimal('194'))
4030
4031 q, r = divmod(Decimal("NaN"), 7)
4032 self.assertTrue(q.is_nan() and r.is_nan())
4033
4034 c.traps[InvalidOperation] = False
4035 q, r = divmod(Decimal("NaN"), 7)
4036 self.assertTrue(q.is_nan() and r.is_nan())
4037
4038 c.traps[InvalidOperation] = False
4039 c.clear_flags()
4040 q, r = divmod(Decimal("inf"), Decimal("inf"))
4041 self.assertTrue(q.is_nan() and r.is_nan())
4042 self.assertTrue(c.flags[InvalidOperation])
4043
4044 c.clear_flags()
4045 q, r = divmod(Decimal("inf"), 101)
4046 self.assertTrue(q.is_infinite() and r.is_nan())
4047 self.assertTrue(c.flags[InvalidOperation])
4048
4049 c.clear_flags()
4050 q, r = divmod(Decimal(0), 0)
4051 self.assertTrue(q.is_nan() and r.is_nan())
4052 self.assertTrue(c.flags[InvalidOperation])
4053
4054 c.traps[DivisionByZero] = False
4055 c.clear_flags()
4056 q, r = divmod(Decimal(11), 0)
4057 self.assertTrue(q.is_infinite() and r.is_nan())
4058 self.assertTrue(c.flags[InvalidOperation] and
4059 c.flags[DivisionByZero])
4060
4061 def test_power(self):
4062 Decimal = self.decimal.Decimal
4063 localcontext = self.decimal.localcontext
4064 Overflow = self.decimal.Overflow
4065 Rounded = self.decimal.Rounded
4066
4067 with localcontext() as c:
4068 c.prec = 3
4069 c.clear_flags()
4070 self.assertEqual(Decimal("1.0") ** 100, Decimal('1.00'))
4071 self.assertTrue(c.flags[Rounded])
4072
4073 c.prec = 1
4074 c.Emax = 1
4075 c.Emin = -1
4076 c.clear_flags()
4077 c.traps[Overflow] = False
4078 self.assertEqual(Decimal(10000) ** Decimal("0.5"), Decimal('inf'))
4079 self.assertTrue(c.flags[Overflow])
4080
4081 def test_quantize(self):
4082 Decimal = self.decimal.Decimal
4083 localcontext = self.decimal.localcontext
4084 InvalidOperation = self.decimal.InvalidOperation
4085
4086 with localcontext() as c:
4087 c.prec = 1
4088 c.Emax = 1
4089 c.Emin = -1
4090 c.traps[InvalidOperation] = False
4091 x = Decimal(99).quantize(Decimal("1e1"))
4092 self.assertTrue(x.is_nan())
4093
4094 def test_radix(self):
4095 Decimal = self.decimal.Decimal
4096 getcontext = self.decimal.getcontext
4097
4098 c = getcontext()
4099 self.assertEqual(Decimal("1").radix(), 10)
4100 self.assertEqual(c.radix(), 10)
4101
4102 def test_rop(self):
4103 Decimal = self.decimal.Decimal
4104
4105 for attr in ('__radd__', '__rsub__', '__rmul__', '__rtruediv__',
4106 '__rdivmod__', '__rmod__', '__rfloordiv__', '__rpow__'):
4107 self.assertIs(getattr(Decimal("1"), attr)("xyz"), NotImplemented)
4108
4109 def test_round(self):
4110 # Python3 behavior: round() returns Decimal
4111 Decimal = self.decimal.Decimal
4112 getcontext = self.decimal.getcontext
4113
4114 c = getcontext()
4115 c.prec = 28
4116
4117 self.assertEqual(str(Decimal("9.99").__round__()), "10")
4118 self.assertEqual(str(Decimal("9.99e-5").__round__()), "0")
4119 self.assertEqual(str(Decimal("1.23456789").__round__(5)), "1.23457")
4120 self.assertEqual(str(Decimal("1.2345").__round__(10)), "1.2345000000")
4121 self.assertEqual(str(Decimal("1.2345").__round__(-10)), "0E+10")
4122
4123 self.assertRaises(TypeError, Decimal("1.23").__round__, "5")
4124 self.assertRaises(TypeError, Decimal("1.23").__round__, 5, 8)
4125
4126 def test_create_decimal(self):
4127 c = self.decimal.Context()
4128 self.assertRaises(ValueError, c.create_decimal, ["%"])
4129
4130 def test_int(self):
4131 Decimal = self.decimal.Decimal
4132 localcontext = self.decimal.localcontext
4133
4134 with localcontext() as c:
4135 c.prec = 9999
4136 x = Decimal(1221**1271) / 10**3923
4137 self.assertEqual(int(x), 1)
4138 self.assertEqual(x.to_integral(), 2)
4139
4140 def test_copy(self):
4141 Context = self.decimal.Context
4142
4143 c = Context()
4144 c.prec = 10000
4145 x = -(1172 ** 1712)
4146
4147 y = c.copy_abs(x)
4148 self.assertEqual(y, -x)
4149
4150 y = c.copy_negate(x)
4151 self.assertEqual(y, -x)
4152
4153 y = c.copy_sign(x, 1)
4154 self.assertEqual(y, -x)
4155
4156class CCoverage(Coverage):
4157 decimal = C
4158class PyCoverage(Coverage):
4159 decimal = P
4160
4161class PyFunctionality(unittest.TestCase):
4162 """Extra functionality in decimal.py"""
4163
4164 def test_py_quantize_watchexp(self):
4165 # watchexp functionality
4166 Decimal = P.Decimal
4167 localcontext = P.localcontext
4168
4169 with localcontext() as c:
4170 c.prec = 1
4171 c.Emax = 1
4172 c.Emin = -1
4173 x = Decimal(99999).quantize(Decimal("1e3"), watchexp=False)
4174 self.assertEqual(x, Decimal('1.00E+5'))
4175
4176 def test_py_alternate_formatting(self):
4177 # triples giving a format, a Decimal, and the expected result
4178 Decimal = P.Decimal
4179 localcontext = P.localcontext
4180
4181 test_values = [
4182 # Issue 7094: Alternate formatting (specified by #)
4183 ('.0e', '1.0', '1e+0'),
4184 ('#.0e', '1.0', '1.e+0'),
4185 ('.0f', '1.0', '1'),
4186 ('#.0f', '1.0', '1.'),
4187 ('g', '1.1', '1.1'),
4188 ('#g', '1.1', '1.1'),
4189 ('.0g', '1', '1'),
4190 ('#.0g', '1', '1.'),
4191 ('.0%', '1.0', '100%'),
4192 ('#.0%', '1.0', '100.%'),
4193 ]
4194 for fmt, d, result in test_values:
4195 self.assertEqual(format(Decimal(d), fmt), result)
4196
4197class PyWhitebox(unittest.TestCase):
4198 """White box testing for decimal.py"""
4199
4200 def test_py_exact_power(self):
4201 # Rarely exercised lines in _power_exact.
4202 Decimal = P.Decimal
4203 localcontext = P.localcontext
4204
4205 with localcontext() as c:
4206 c.prec = 8
4207 x = Decimal(2**16) ** Decimal("-0.5")
4208 self.assertEqual(x, Decimal('0.00390625'))
4209
4210 x = Decimal(2**16) ** Decimal("-0.6")
4211 self.assertEqual(x, Decimal('0.0012885819'))
4212
4213 x = Decimal("256e7") ** Decimal("-0.5")
4214
4215 x = Decimal(152587890625) ** Decimal('-0.0625')
4216 self.assertEqual(x, Decimal("0.2"))
4217
4218 x = Decimal("152587890625e7") ** Decimal('-0.0625')
4219
4220 x = Decimal(5**2659) ** Decimal('-0.0625')
4221
4222 c.prec = 1
4223 x = Decimal("152587890625") ** Decimal('-0.5')
4224 c.prec = 201
4225 x = Decimal(2**578) ** Decimal("-0.5")
4226
4227 def test_py_immutability_operations(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004228 # Do operations and check that it didn't change change internal objects.
Stefan Krah1919b7e2012-03-21 18:25:23 +01004229 Decimal = P.Decimal
4230 DefaultContext = P.DefaultContext
4231 setcontext = P.setcontext
4232
4233 c = DefaultContext.copy()
4234 c.traps = dict((s, 0) for s in OrderedSignals[P])
4235 setcontext(c)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004236
4237 d1 = Decimal('-25e55')
4238 b1 = Decimal('-25e55')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004239 d2 = Decimal('33e+33')
4240 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004241
4242 def checkSameDec(operation, useOther=False):
4243 if useOther:
4244 eval("d1." + operation + "(d2)")
4245 self.assertEqual(d1._sign, b1._sign)
4246 self.assertEqual(d1._int, b1._int)
4247 self.assertEqual(d1._exp, b1._exp)
4248 self.assertEqual(d2._sign, b2._sign)
4249 self.assertEqual(d2._int, b2._int)
4250 self.assertEqual(d2._exp, b2._exp)
4251 else:
4252 eval("d1." + operation + "()")
4253 self.assertEqual(d1._sign, b1._sign)
4254 self.assertEqual(d1._int, b1._int)
4255 self.assertEqual(d1._exp, b1._exp)
4256 return
4257
4258 Decimal(d1)
4259 self.assertEqual(d1._sign, b1._sign)
4260 self.assertEqual(d1._int, b1._int)
4261 self.assertEqual(d1._exp, b1._exp)
4262
4263 checkSameDec("__abs__")
4264 checkSameDec("__add__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004265 checkSameDec("__divmod__", True)
Christian Heimes77c02eb2008-02-09 02:18:51 +00004266 checkSameDec("__eq__", True)
4267 checkSameDec("__ne__", True)
4268 checkSameDec("__le__", True)
4269 checkSameDec("__lt__", True)
4270 checkSameDec("__ge__", True)
4271 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004272 checkSameDec("__float__")
4273 checkSameDec("__floordiv__", True)
4274 checkSameDec("__hash__")
4275 checkSameDec("__int__")
Christian Heimes969fe572008-01-25 11:23:10 +00004276 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004277 checkSameDec("__mod__", True)
4278 checkSameDec("__mul__", True)
4279 checkSameDec("__neg__")
Jack Diederich4dafcc42006-11-28 19:15:13 +00004280 checkSameDec("__bool__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004281 checkSameDec("__pos__")
4282 checkSameDec("__pow__", True)
4283 checkSameDec("__radd__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004284 checkSameDec("__rdivmod__", True)
4285 checkSameDec("__repr__")
4286 checkSameDec("__rfloordiv__", True)
4287 checkSameDec("__rmod__", True)
4288 checkSameDec("__rmul__", True)
4289 checkSameDec("__rpow__", True)
4290 checkSameDec("__rsub__", True)
4291 checkSameDec("__str__")
4292 checkSameDec("__sub__", True)
4293 checkSameDec("__truediv__", True)
4294 checkSameDec("adjusted")
4295 checkSameDec("as_tuple")
4296 checkSameDec("compare", True)
4297 checkSameDec("max", True)
4298 checkSameDec("min", True)
4299 checkSameDec("normalize")
4300 checkSameDec("quantize", True)
4301 checkSameDec("remainder_near", True)
4302 checkSameDec("same_quantum", True)
4303 checkSameDec("sqrt")
4304 checkSameDec("to_eng_string")
4305 checkSameDec("to_integral")
4306
Stefan Krah1919b7e2012-03-21 18:25:23 +01004307 def test_py_decimal_id(self):
4308 Decimal = P.Decimal
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004309
Stefan Krah1919b7e2012-03-21 18:25:23 +01004310 d = Decimal(45)
4311 e = Decimal(d)
4312 self.assertEqual(str(e), '45')
4313 self.assertNotEqual(id(d), id(e))
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004314
Stefan Krah1919b7e2012-03-21 18:25:23 +01004315 def test_py_rescale(self):
4316 # Coverage
4317 Decimal = P.Decimal
4318 ROUND_UP = P.ROUND_UP
4319 localcontext = P.localcontext
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004320
Stefan Krah1919b7e2012-03-21 18:25:23 +01004321 with localcontext() as c:
4322 x = Decimal("NaN")._rescale(3, ROUND_UP)
4323 self.assertTrue(x.is_nan())
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004324
Stefan Krah1919b7e2012-03-21 18:25:23 +01004325 def test_py__round(self):
4326 # Coverage
4327 Decimal = P.Decimal
4328 ROUND_UP = P.ROUND_UP
Christian Heimes0348fb62008-03-26 12:55:56 +00004329
Stefan Krah1919b7e2012-03-21 18:25:23 +01004330 self.assertRaises(ValueError, Decimal("3.1234")._round, 0, ROUND_UP)
Mark Dickinsona2d1fe02009-10-29 12:23:02 +00004331
Stefan Krah1919b7e2012-03-21 18:25:23 +01004332class CFunctionality(unittest.TestCase):
4333 """Extra functionality in _decimal"""
Mark Dickinsona2d1fe02009-10-29 12:23:02 +00004334
Stefan Krah1919b7e2012-03-21 18:25:23 +01004335 @requires_extra_functionality
4336 def test_c_ieee_context(self):
4337 # issue 8786: Add support for IEEE 754 contexts to decimal module.
4338 IEEEContext = C.IEEEContext
4339 DECIMAL32 = C.DECIMAL32
4340 DECIMAL64 = C.DECIMAL64
4341 DECIMAL128 = C.DECIMAL128
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004342
Stefan Krah1919b7e2012-03-21 18:25:23 +01004343 def assert_rest(self, context):
4344 self.assertEqual(context.clamp, 1)
4345 assert_signals(self, context, 'traps', [])
4346 assert_signals(self, context, 'flags', [])
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004347
Stefan Krah1919b7e2012-03-21 18:25:23 +01004348 c = IEEEContext(DECIMAL32)
4349 self.assertEqual(c.prec, 7)
4350 self.assertEqual(c.Emax, 96)
4351 self.assertEqual(c.Emin, -95)
4352 assert_rest(self, c)
Raymond Hettinger82417ca2009-02-03 03:54:28 +00004353
Stefan Krah1919b7e2012-03-21 18:25:23 +01004354 c = IEEEContext(DECIMAL64)
4355 self.assertEqual(c.prec, 16)
4356 self.assertEqual(c.Emax, 384)
4357 self.assertEqual(c.Emin, -383)
4358 assert_rest(self, c)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004359
Stefan Krah1919b7e2012-03-21 18:25:23 +01004360 c = IEEEContext(DECIMAL128)
4361 self.assertEqual(c.prec, 34)
4362 self.assertEqual(c.Emax, 6144)
4363 self.assertEqual(c.Emin, -6143)
4364 assert_rest(self, c)
Raymond Hettinger5548be22004-07-05 18:49:38 +00004365
Stefan Krah1919b7e2012-03-21 18:25:23 +01004366 # Invalid values
4367 self.assertRaises(OverflowError, IEEEContext, 2**63)
4368 self.assertRaises(ValueError, IEEEContext, -1)
4369 self.assertRaises(ValueError, IEEEContext, 1024)
Mark Dickinson825fce32009-09-07 18:08:12 +00004370
Stefan Krah1919b7e2012-03-21 18:25:23 +01004371 @requires_extra_functionality
4372 def test_c_context(self):
4373 Context = C.Context
Christian Heimes969fe572008-01-25 11:23:10 +00004374
Stefan Krah1919b7e2012-03-21 18:25:23 +01004375 c = Context(flags=C.DecClamped, traps=C.DecRounded)
4376 self.assertEqual(c._flags, C.DecClamped)
4377 self.assertEqual(c._traps, C.DecRounded)
Raymond Hettinger771ed762009-01-03 19:20:32 +00004378
Stefan Krah1919b7e2012-03-21 18:25:23 +01004379 @requires_extra_functionality
4380 def test_constants(self):
4381 # Condition flags
4382 cond = (
4383 C.DecClamped, C.DecConversionSyntax, C.DecDivisionByZero,
4384 C.DecDivisionImpossible, C.DecDivisionUndefined,
4385 C.DecFpuError, C.DecInexact, C.DecInvalidContext,
4386 C.DecInvalidOperation, C.DecMallocError,
4387 C.DecFloatOperation, C.DecOverflow, C.DecRounded,
4388 C.DecSubnormal, C.DecUnderflow
Raymond Hettinger771ed762009-01-03 19:20:32 +00004389 )
Stefan Krah1919b7e2012-03-21 18:25:23 +01004390
4391 # IEEEContext
4392 self.assertEqual(C.DECIMAL32, 32)
4393 self.assertEqual(C.DECIMAL64, 64)
4394 self.assertEqual(C.DECIMAL128, 128)
4395 self.assertEqual(C.IEEE_CONTEXT_MAX_BITS, 512)
4396
4397 # Rounding modes
4398 for i, v in enumerate(RoundingModes[C]):
4399 self.assertEqual(v, i)
4400 self.assertEqual(C.ROUND_TRUNC, 8)
4401
4402 # Conditions
4403 for i, v in enumerate(cond):
4404 self.assertEqual(v, 1<<i)
4405
4406 self.assertEqual(C.DecIEEEInvalidOperation,
4407 C.DecConversionSyntax|
4408 C.DecDivisionImpossible|
4409 C.DecDivisionUndefined|
4410 C.DecFpuError|
4411 C.DecInvalidContext|
4412 C.DecInvalidOperation|
4413 C.DecMallocError)
4414
4415 self.assertEqual(C.DecErrors,
4416 C.DecIEEEInvalidOperation|
4417 C.DecDivisionByZero)
4418
4419 self.assertEqual(C.DecTraps,
4420 C.DecErrors|C.DecOverflow|C.DecUnderflow)
4421
4422class CWhitebox(unittest.TestCase):
4423 """Whitebox testing for _decimal"""
4424
4425 def test_bignum(self):
4426 # Not exactly whitebox, but too slow with pydecimal.
4427
4428 Decimal = C.Decimal
4429 localcontext = C.localcontext
4430
4431 b1 = 10**35
4432 b2 = 10**36
4433 with localcontext() as c:
4434 c.prec = 1000000
4435 for i in range(5):
4436 a = random.randrange(b1, b2)
4437 b = random.randrange(1000, 1200)
4438 x = a ** b
4439 y = Decimal(a) ** Decimal(b)
4440 self.assertEqual(x, y)
4441
4442 def test_invalid_construction(self):
4443 self.assertRaises(TypeError, C.Decimal, 9, "xyz")
4444
4445 def test_c_input_restriction(self):
4446 # Too large for _decimal to be converted exactly
4447 Decimal = C.Decimal
4448 InvalidOperation = C.InvalidOperation
4449 Context = C.Context
4450 localcontext = C.localcontext
4451
4452 with localcontext(Context()):
4453 self.assertRaises(InvalidOperation, Decimal,
4454 "1e9999999999999999999")
4455
4456 def test_c_context_repr(self):
4457 # This test is _decimal-only because flags are not printed
4458 # in the same order.
4459 DefaultContext = C.DefaultContext
4460 FloatOperation = C.FloatOperation
4461 ROUND_HALF_DOWN = C.ROUND_HALF_DOWN
4462
4463 c = DefaultContext.copy()
4464
4465 c.prec = 425000000
4466 c.Emax = 425000000
4467 c.Emin = -425000000
4468 c.rounding = ROUND_HALF_DOWN
4469 c.capitals = 0
4470 c.clamp = 1
4471 for sig in OrderedSignals[C]:
4472 c.flags[sig] = True
4473 c.traps[sig] = True
4474 c.flags[FloatOperation] = True
4475 c.traps[FloatOperation] = True
4476
4477 s = c.__repr__()
4478 t = "Context(prec=425000000, rounding=ROUND_HALF_DOWN, " \
4479 "Emin=-425000000, Emax=425000000, capitals=0, clamp=1, " \
4480 "flags=[Clamped, InvalidOperation, DivisionByZero, Inexact, " \
4481 "FloatOperation, Overflow, Rounded, Subnormal, Underflow], " \
4482 "traps=[Clamped, InvalidOperation, DivisionByZero, Inexact, " \
4483 "FloatOperation, Overflow, Rounded, Subnormal, Underflow])"
4484 self.assertEqual(s, t)
4485
4486 def test_c_context_errors(self):
4487 Context = C.Context
4488 InvalidOperation = C.InvalidOperation
4489 Overflow = C.Overflow
4490 FloatOperation = C.FloatOperation
4491 localcontext = C.localcontext
4492 getcontext = C.getcontext
4493 setcontext = C.setcontext
4494 HAVE_CONFIG_64 = (C.MAX_PREC > 425000000)
4495
4496 c = Context()
4497
4498 # SignalDict: input validation
4499 self.assertRaises(KeyError, c.flags.__setitem__, 801, 0)
4500 self.assertRaises(KeyError, c.traps.__setitem__, 801, 0)
4501 self.assertRaises(ValueError, c.flags.__delitem__, Overflow)
4502 self.assertRaises(ValueError, c.traps.__delitem__, InvalidOperation)
4503 self.assertRaises(TypeError, setattr, c, 'flags', ['x'])
4504 self.assertRaises(TypeError, setattr, c,'traps', ['y'])
4505 self.assertRaises(KeyError, setattr, c, 'flags', {0:1})
4506 self.assertRaises(KeyError, setattr, c, 'traps', {0:1})
4507
4508 # Test assignment from a signal dict with the correct length but
4509 # one invalid key.
4510 d = c.flags.copy()
4511 del d[FloatOperation]
4512 d["XYZ"] = 91283719
4513 self.assertRaises(KeyError, setattr, c, 'flags', d)
4514 self.assertRaises(KeyError, setattr, c, 'traps', d)
4515
4516 # Input corner cases
4517 int_max = 2**63-1 if HAVE_CONFIG_64 else 2**31-1
4518 gt_max_emax = 10**18 if HAVE_CONFIG_64 else 10**9
4519
4520 # prec, Emax, Emin
4521 for attr in ['prec', 'Emax']:
4522 self.assertRaises(ValueError, setattr, c, attr, gt_max_emax)
4523 self.assertRaises(ValueError, setattr, c, 'Emin', -gt_max_emax)
4524
4525 # prec, Emax, Emin in context constructor
4526 self.assertRaises(ValueError, Context, prec=gt_max_emax)
4527 self.assertRaises(ValueError, Context, Emax=gt_max_emax)
4528 self.assertRaises(ValueError, Context, Emin=-gt_max_emax)
4529
4530 # Overflow in conversion
4531 self.assertRaises(OverflowError, Context, prec=int_max+1)
4532 self.assertRaises(OverflowError, Context, Emax=int_max+1)
4533 self.assertRaises(OverflowError, Context, Emin=-int_max-2)
4534 self.assertRaises(OverflowError, Context, rounding=int_max+1)
4535 self.assertRaises(OverflowError, Context, clamp=int_max+1)
4536 self.assertRaises(OverflowError, Context, capitals=int_max+1)
4537
4538 # OverflowError, general ValueError
4539 for attr in ('prec', 'Emin', 'Emax', 'capitals', 'clamp'):
4540 self.assertRaises(OverflowError, setattr, c, attr, int_max+1)
4541 self.assertRaises(OverflowError, setattr, c, attr, -int_max-2)
4542 if sys.platform != 'win32':
4543 self.assertRaises(ValueError, setattr, c, attr, int_max)
4544 self.assertRaises(ValueError, setattr, c, attr, -int_max-1)
4545
4546 # OverflowError, general TypeError
4547 for attr in ('rounding',):
4548 self.assertRaises(OverflowError, setattr, c, attr, int_max+1)
4549 self.assertRaises(OverflowError, setattr, c, attr, -int_max-2)
4550 if sys.platform != 'win32':
4551 self.assertRaises(TypeError, setattr, c, attr, int_max)
4552 self.assertRaises(TypeError, setattr, c, attr, -int_max-1)
4553
4554 # OverflowError: _unsafe_setprec, _unsafe_setemin, _unsafe_setemax
4555 if C.MAX_PREC == 425000000:
4556 self.assertRaises(OverflowError, getattr(c, '_unsafe_setprec'),
4557 int_max+1)
4558 self.assertRaises(OverflowError, getattr(c, '_unsafe_setemax'),
4559 int_max+1)
4560 self.assertRaises(OverflowError, getattr(c, '_unsafe_setemin'),
4561 -int_max-2)
4562
4563 # ValueError: _unsafe_setprec, _unsafe_setemin, _unsafe_setemax
4564 if C.MAX_PREC == 425000000:
4565 self.assertRaises(ValueError, getattr(c, '_unsafe_setprec'), 0)
4566 self.assertRaises(ValueError, getattr(c, '_unsafe_setprec'),
4567 1070000001)
4568 self.assertRaises(ValueError, getattr(c, '_unsafe_setemax'), -1)
4569 self.assertRaises(ValueError, getattr(c, '_unsafe_setemax'),
4570 1070000001)
4571 self.assertRaises(ValueError, getattr(c, '_unsafe_setemin'),
4572 -1070000001)
4573 self.assertRaises(ValueError, getattr(c, '_unsafe_setemin'), 1)
4574
4575 # capitals, clamp
4576 for attr in ['capitals', 'clamp']:
4577 self.assertRaises(ValueError, setattr, c, attr, -1)
4578 self.assertRaises(ValueError, setattr, c, attr, 2)
4579 self.assertRaises(TypeError, setattr, c, attr, [1,2,3])
4580 if HAVE_CONFIG_64:
4581 self.assertRaises(ValueError, setattr, c, attr, 2**32)
4582 self.assertRaises(ValueError, setattr, c, attr, 2**32+1)
4583
4584 # Invalid local context
4585 self.assertRaises(TypeError, exec, 'with localcontext("xyz"): pass',
4586 locals())
4587
4588 # setcontext
4589 saved_context = getcontext()
4590 self.assertRaises(TypeError, setcontext, "xyz")
4591 setcontext(saved_context)
4592
4593 @requires_extra_functionality
4594 def test_c_context_errors_extra(self):
4595 Context = C.Context
4596 InvalidOperation = C.InvalidOperation
4597 Overflow = C.Overflow
4598 localcontext = C.localcontext
4599 getcontext = C.getcontext
4600 setcontext = C.setcontext
4601 HAVE_CONFIG_64 = (C.MAX_PREC > 425000000)
4602
4603 c = Context()
4604
4605 # Input corner cases
4606 int_max = 2**63-1 if HAVE_CONFIG_64 else 2**31-1
4607
4608 # OverflowError, general ValueError
4609 self.assertRaises(OverflowError, setattr, c, '_allcr', int_max+1)
4610 self.assertRaises(OverflowError, setattr, c, '_allcr', -int_max-2)
4611 if sys.platform != 'win32':
4612 self.assertRaises(ValueError, setattr, c, '_allcr', int_max)
4613 self.assertRaises(ValueError, setattr, c, '_allcr', -int_max-1)
4614
4615 # OverflowError, general TypeError
4616 for attr in ('_flags', '_traps'):
4617 self.assertRaises(OverflowError, setattr, c, attr, int_max+1)
4618 self.assertRaises(OverflowError, setattr, c, attr, -int_max-2)
4619 if sys.platform != 'win32':
4620 self.assertRaises(TypeError, setattr, c, attr, int_max)
4621 self.assertRaises(TypeError, setattr, c, attr, -int_max-1)
4622
4623 # _allcr
4624 self.assertRaises(ValueError, setattr, c, '_allcr', -1)
4625 self.assertRaises(ValueError, setattr, c, '_allcr', 2)
4626 self.assertRaises(TypeError, setattr, c, '_allcr', [1,2,3])
4627 if HAVE_CONFIG_64:
4628 self.assertRaises(ValueError, setattr, c, '_allcr', 2**32)
4629 self.assertRaises(ValueError, setattr, c, '_allcr', 2**32+1)
4630
4631 # _flags, _traps
4632 for attr in ['_flags', '_traps']:
4633 self.assertRaises(TypeError, setattr, c, attr, 999999)
4634 self.assertRaises(TypeError, setattr, c, attr, 'x')
4635
4636 def test_c_valid_context(self):
4637 # These tests are for code coverage in _decimal.
4638 DefaultContext = C.DefaultContext
4639 ROUND_HALF_UP = C.ROUND_HALF_UP
4640 Clamped = C.Clamped
4641 Underflow = C.Underflow
4642 Inexact = C.Inexact
4643 Rounded = C.Rounded
4644 Subnormal = C.Subnormal
4645
4646 c = DefaultContext.copy()
4647
4648 # Exercise all getters and setters
4649 c.prec = 34
4650 c.rounding = ROUND_HALF_UP
4651 c.Emax = 3000
4652 c.Emin = -3000
4653 c.capitals = 1
4654 c.clamp = 0
4655
4656 self.assertEqual(c.prec, 34)
4657 self.assertEqual(c.rounding, ROUND_HALF_UP)
4658 self.assertEqual(c.Emin, -3000)
4659 self.assertEqual(c.Emax, 3000)
4660 self.assertEqual(c.capitals, 1)
4661 self.assertEqual(c.clamp, 0)
4662
4663 self.assertEqual(c.Etiny(), -3033)
4664 self.assertEqual(c.Etop(), 2967)
4665
4666 # Exercise all unsafe setters
4667 if C.MAX_PREC == 425000000:
4668 c._unsafe_setprec(999999999)
4669 c._unsafe_setemax(999999999)
4670 c._unsafe_setemin(-999999999)
4671 self.assertEqual(c.prec, 999999999)
4672 self.assertEqual(c.Emax, 999999999)
4673 self.assertEqual(c.Emin, -999999999)
4674
4675 @requires_extra_functionality
4676 def test_c_valid_context_extra(self):
4677 DefaultContext = C.DefaultContext
4678
4679 c = DefaultContext.copy()
4680 self.assertEqual(c._allcr, 1)
4681 c._allcr = 0
4682 self.assertEqual(c._allcr, 0)
4683
4684 def test_c_round(self):
4685 # Restricted input.
4686 Decimal = C.Decimal
4687 InvalidOperation = C.InvalidOperation
4688 localcontext = C.localcontext
4689 MAX_EMAX = C.MAX_EMAX
4690 MIN_ETINY = C.MIN_ETINY
4691 int_max = 2**63-1 if C.MAX_PREC > 425000000 else 2**31-1
4692
4693 with localcontext() as c:
4694 c.traps[InvalidOperation] = True
4695 self.assertRaises(InvalidOperation, Decimal("1.23").__round__,
4696 -int_max-1)
4697 self.assertRaises(InvalidOperation, Decimal("1.23").__round__,
4698 int_max)
4699 self.assertRaises(InvalidOperation, Decimal("1").__round__,
4700 int(MAX_EMAX+1))
4701 self.assertRaises(C.InvalidOperation, Decimal("1").__round__,
4702 -int(MIN_ETINY-1))
4703 self.assertRaises(OverflowError, Decimal("1.23").__round__,
4704 -int_max-2)
4705 self.assertRaises(OverflowError, Decimal("1.23").__round__,
4706 int_max+1)
4707
4708 def test_c_format(self):
4709 # Restricted input
4710 Decimal = C.Decimal
4711 InvalidOperation = C.InvalidOperation
4712 Rounded = C.Rounded
4713 localcontext = C.localcontext
4714 HAVE_CONFIG_64 = (C.MAX_PREC > 425000000)
4715
4716 self.assertRaises(TypeError, Decimal(1).__format__, "=10.10", [], 9)
4717 self.assertRaises(TypeError, Decimal(1).__format__, "=10.10", 9)
4718 self.assertRaises(TypeError, Decimal(1).__format__, [])
4719
4720 with localcontext() as c:
4721 c.traps[InvalidOperation] = True
4722 c.traps[Rounded] = True
4723 self.assertRaises(ValueError, Decimal(1).__format__, "<>=10.10")
4724 maxsize = 2**63-1 if HAVE_CONFIG_64 else 2**31-1
4725 self.assertRaises(InvalidOperation, Decimal("1.23456789").__format__,
4726 "=%d.1" % maxsize)
4727
4728 def test_c_integral(self):
4729 Decimal = C.Decimal
4730 Inexact = C.Inexact
4731 ROUND_UP = C.ROUND_UP
4732 localcontext = C.localcontext
4733
4734 x = Decimal(10)
4735 self.assertEqual(x.to_integral(), 10)
4736 self.assertRaises(TypeError, x.to_integral, '10')
4737 self.assertRaises(TypeError, x.to_integral, 10, 'x')
4738 self.assertRaises(TypeError, x.to_integral, 10)
4739
4740 self.assertEqual(x.to_integral_value(), 10)
4741 self.assertRaises(TypeError, x.to_integral_value, '10')
4742 self.assertRaises(TypeError, x.to_integral_value, 10, 'x')
4743 self.assertRaises(TypeError, x.to_integral_value, 10)
4744
4745 self.assertEqual(x.to_integral_exact(), 10)
4746 self.assertRaises(TypeError, x.to_integral_exact, '10')
4747 self.assertRaises(TypeError, x.to_integral_exact, 10, 'x')
4748 self.assertRaises(TypeError, x.to_integral_exact, 10)
4749
4750 with localcontext() as c:
4751 x = Decimal("99999999999999999999999999.9").to_integral_value(ROUND_UP)
4752 self.assertEqual(x, Decimal('100000000000000000000000000'))
4753
4754 x = Decimal("99999999999999999999999999.9").to_integral_exact(ROUND_UP)
4755 self.assertEqual(x, Decimal('100000000000000000000000000'))
4756
4757 c.traps[Inexact] = True
4758 self.assertRaises(Inexact, Decimal("999.9").to_integral_exact, ROUND_UP)
4759
4760 def test_c_funcs(self):
4761 # Invalid arguments
4762 Decimal = C.Decimal
4763 InvalidOperation = C.InvalidOperation
4764 DivisionByZero = C.DivisionByZero
4765 ROUND_UP = C.ROUND_UP
4766 getcontext = C.getcontext
4767 localcontext = C.localcontext
4768
4769 self.assertEqual(Decimal('9.99e10').to_eng_string(), '99.9E+9')
4770
4771 self.assertRaises(TypeError, pow, Decimal(1), 2, "3")
4772 self.assertRaises(TypeError, Decimal(9).number_class, "x", "y")
4773 self.assertRaises(TypeError, Decimal(9).same_quantum, 3, "x", "y")
4774
Raymond Hettinger771ed762009-01-03 19:20:32 +00004775 self.assertRaises(
Stefan Krah1919b7e2012-03-21 18:25:23 +01004776 TypeError,
4777 Decimal("1.23456789").quantize, Decimal('1e-100000'), []
Raymond Hettinger771ed762009-01-03 19:20:32 +00004778 )
Stefan Krah1919b7e2012-03-21 18:25:23 +01004779 self.assertRaises(
4780 TypeError,
4781 Decimal("1.23456789").quantize, Decimal('1e-100000'), getcontext()
4782 )
4783 self.assertRaises(
4784 TypeError,
4785 Decimal("1.23456789").quantize, Decimal('1e-100000'), 10
4786 )
4787 self.assertRaises(
4788 TypeError,
4789 Decimal("1.23456789").quantize, Decimal('1e-100000'), ROUND_UP, 1000
4790 )
Raymond Hettinger771ed762009-01-03 19:20:32 +00004791
Stefan Krah1919b7e2012-03-21 18:25:23 +01004792 with localcontext() as c:
4793 c.clear_traps()
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00004794
Stefan Krah1919b7e2012-03-21 18:25:23 +01004795 # Invalid arguments
4796 self.assertRaises(TypeError, c.copy_sign, Decimal(1), "x", "y")
4797 self.assertRaises(TypeError, c.canonical, 200)
4798 self.assertRaises(TypeError, c.is_canonical, 200)
4799 self.assertRaises(TypeError, c.divmod, 9, 8, "x", "y")
4800 self.assertRaises(TypeError, c.same_quantum, 9, 3, "x", "y")
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00004801
Stefan Krah1919b7e2012-03-21 18:25:23 +01004802 self.assertEqual(str(c.canonical(Decimal(200))), '200')
4803 self.assertEqual(c.radix(), 10)
Raymond Hettinger0aeac102004-07-05 22:53:03 +00004804
Stefan Krah1919b7e2012-03-21 18:25:23 +01004805 c.traps[DivisionByZero] = True
4806 self.assertRaises(DivisionByZero, Decimal(9).__divmod__, 0)
4807 self.assertRaises(DivisionByZero, c.divmod, 9, 0)
4808 self.assertTrue(c.flags[InvalidOperation])
Raymond Hettinger955d2b22004-08-08 20:17:45 +00004809
Stefan Krah1919b7e2012-03-21 18:25:23 +01004810 c.clear_flags()
4811 c.traps[InvalidOperation] = True
4812 self.assertRaises(InvalidOperation, Decimal(9).__divmod__, 0)
4813 self.assertRaises(InvalidOperation, c.divmod, 9, 0)
4814 self.assertTrue(c.flags[DivisionByZero])
Mark Dickinsonb1d8e322010-05-22 18:35:36 +00004815
Stefan Krah1919b7e2012-03-21 18:25:23 +01004816 c.traps[InvalidOperation] = True
4817 c.prec = 2
4818 self.assertRaises(InvalidOperation, pow, Decimal(1000), 1, 501)
Mark Dickinson84230a12010-02-18 14:49:50 +00004819
Stefan Krah1919b7e2012-03-21 18:25:23 +01004820 @requires_extra_functionality
4821 def test_c_context_templates(self):
4822 self.assertEqual(
4823 C.BasicContext._traps,
4824 C.DecIEEEInvalidOperation|C.DecDivisionByZero|C.DecOverflow|
4825 C.DecUnderflow|C.DecClamped
4826 )
4827 self.assertEqual(
4828 C.DefaultContext._traps,
4829 C.DecIEEEInvalidOperation|C.DecDivisionByZero|C.DecOverflow
4830 )
Mark Dickinson84230a12010-02-18 14:49:50 +00004831
Stefan Krah1919b7e2012-03-21 18:25:23 +01004832 @requires_extra_functionality
4833 def test_c_signal_dict(self):
Mark Dickinson84230a12010-02-18 14:49:50 +00004834
Stefan Krah1919b7e2012-03-21 18:25:23 +01004835 # SignalDict coverage
4836 Context = C.Context
4837 DefaultContext = C.DefaultContext
Mark Dickinson84230a12010-02-18 14:49:50 +00004838
Stefan Krah1919b7e2012-03-21 18:25:23 +01004839 InvalidOperation = C.InvalidOperation
4840 DivisionByZero = C.DivisionByZero
4841 Overflow = C.Overflow
4842 Subnormal = C.Subnormal
4843 Underflow = C.Underflow
4844 Rounded = C.Rounded
4845 Inexact = C.Inexact
4846 Clamped = C.Clamped
Mark Dickinson84230a12010-02-18 14:49:50 +00004847
Stefan Krah1919b7e2012-03-21 18:25:23 +01004848 DecClamped = C.DecClamped
4849 DecInvalidOperation = C.DecInvalidOperation
4850 DecIEEEInvalidOperation = C.DecIEEEInvalidOperation
Mark Dickinson84230a12010-02-18 14:49:50 +00004851
Stefan Krah1919b7e2012-03-21 18:25:23 +01004852 def assertIsExclusivelySet(signal, signal_dict):
4853 for sig in signal_dict:
4854 if sig == signal:
4855 self.assertTrue(signal_dict[sig])
4856 else:
4857 self.assertFalse(signal_dict[sig])
Mark Dickinson84230a12010-02-18 14:49:50 +00004858
Stefan Krah1919b7e2012-03-21 18:25:23 +01004859 c = DefaultContext.copy()
Mark Dickinson84230a12010-02-18 14:49:50 +00004860
Stefan Krah1919b7e2012-03-21 18:25:23 +01004861 # Signal dict methods
4862 self.assertTrue(Overflow in c.traps)
4863 c.clear_traps()
4864 for k in c.traps.keys():
4865 c.traps[k] = True
4866 for v in c.traps.values():
4867 self.assertTrue(v)
4868 c.clear_traps()
4869 for k, v in c.traps.items():
4870 self.assertFalse(v)
Mark Dickinson84230a12010-02-18 14:49:50 +00004871
Stefan Krah1919b7e2012-03-21 18:25:23 +01004872 self.assertFalse(c.flags.get(Overflow))
4873 self.assertIs(c.flags.get("x"), None)
4874 self.assertEqual(c.flags.get("x", "y"), "y")
4875 self.assertRaises(TypeError, c.flags.get, "x", "y", "z")
Mark Dickinson84230a12010-02-18 14:49:50 +00004876
Stefan Krah1919b7e2012-03-21 18:25:23 +01004877 self.assertEqual(len(c.flags), len(c.traps))
4878 s = sys.getsizeof(c.flags)
4879 s = sys.getsizeof(c.traps)
4880 s = c.flags.__repr__()
Mark Dickinson84230a12010-02-18 14:49:50 +00004881
Stefan Krah1919b7e2012-03-21 18:25:23 +01004882 # Set flags/traps.
4883 c.clear_flags()
4884 c._flags = DecClamped
4885 self.assertTrue(c.flags[Clamped])
Mark Dickinson84230a12010-02-18 14:49:50 +00004886
Stefan Krah1919b7e2012-03-21 18:25:23 +01004887 c.clear_traps()
4888 c._traps = DecInvalidOperation
4889 self.assertTrue(c.traps[InvalidOperation])
Mark Dickinson84230a12010-02-18 14:49:50 +00004890
Stefan Krah1919b7e2012-03-21 18:25:23 +01004891 # Set flags/traps from dictionary.
4892 c.clear_flags()
4893 d = c.flags.copy()
4894 d[DivisionByZero] = True
4895 c.flags = d
4896 assertIsExclusivelySet(DivisionByZero, c.flags)
Mark Dickinson84230a12010-02-18 14:49:50 +00004897
Stefan Krah1919b7e2012-03-21 18:25:23 +01004898 c.clear_traps()
4899 d = c.traps.copy()
4900 d[Underflow] = True
4901 c.traps = d
4902 assertIsExclusivelySet(Underflow, c.traps)
Mark Dickinson84230a12010-02-18 14:49:50 +00004903
Stefan Krah1919b7e2012-03-21 18:25:23 +01004904 # Random constructors
4905 IntSignals = {
4906 Clamped: C.DecClamped,
4907 Rounded: C.DecRounded,
4908 Inexact: C.DecInexact,
4909 Subnormal: C.DecSubnormal,
4910 Underflow: C.DecUnderflow,
4911 Overflow: C.DecOverflow,
4912 DivisionByZero: C.DecDivisionByZero,
4913 InvalidOperation: C.DecIEEEInvalidOperation
4914 }
4915 IntCond = [
4916 C.DecDivisionImpossible, C.DecDivisionUndefined, C.DecFpuError,
4917 C.DecInvalidContext, C.DecInvalidOperation, C.DecMallocError,
4918 C.DecConversionSyntax,
4919 ]
Mark Dickinsonb455e582011-05-22 12:53:18 +01004920
Stefan Krah1919b7e2012-03-21 18:25:23 +01004921 lim = len(OrderedSignals[C])
4922 for r in range(lim):
4923 for t in range(lim):
4924 for round in RoundingModes[C]:
4925 flags = random.sample(OrderedSignals[C], r)
4926 traps = random.sample(OrderedSignals[C], t)
4927 prec = random.randrange(1, 10000)
4928 emin = random.randrange(-10000, 0)
4929 emax = random.randrange(0, 10000)
4930 clamp = random.randrange(0, 2)
4931 caps = random.randrange(0, 2)
4932 cr = random.randrange(0, 2)
4933 c = Context(prec=prec, rounding=round, Emin=emin, Emax=emax,
4934 capitals=caps, clamp=clamp, flags=list(flags),
4935 traps=list(traps))
Mark Dickinson84230a12010-02-18 14:49:50 +00004936
Stefan Krah1919b7e2012-03-21 18:25:23 +01004937 self.assertEqual(c.prec, prec)
4938 self.assertEqual(c.rounding, round)
4939 self.assertEqual(c.Emin, emin)
4940 self.assertEqual(c.Emax, emax)
4941 self.assertEqual(c.capitals, caps)
4942 self.assertEqual(c.clamp, clamp)
Mark Dickinson84230a12010-02-18 14:49:50 +00004943
Stefan Krah1919b7e2012-03-21 18:25:23 +01004944 f = 0
4945 for x in flags:
4946 f |= IntSignals[x]
4947 self.assertEqual(c._flags, f)
Mark Dickinson84230a12010-02-18 14:49:50 +00004948
Stefan Krah1919b7e2012-03-21 18:25:23 +01004949 f = 0
4950 for x in traps:
4951 f |= IntSignals[x]
4952 self.assertEqual(c._traps, f)
Mark Dickinson84230a12010-02-18 14:49:50 +00004953
Stefan Krah1919b7e2012-03-21 18:25:23 +01004954 for cond in IntCond:
4955 c._flags = cond
4956 self.assertTrue(c._flags&DecIEEEInvalidOperation)
4957 assertIsExclusivelySet(InvalidOperation, c.flags)
Mark Dickinson84230a12010-02-18 14:49:50 +00004958
Stefan Krah1919b7e2012-03-21 18:25:23 +01004959 for cond in IntCond:
4960 c._traps = cond
4961 self.assertTrue(c._traps&DecIEEEInvalidOperation)
4962 assertIsExclusivelySet(InvalidOperation, c.traps)
Mark Dickinson84230a12010-02-18 14:49:50 +00004963
Stefan Krah1919b7e2012-03-21 18:25:23 +01004964 def test_invalid_override(self):
4965 Decimal = C.Decimal
Mark Dickinson84230a12010-02-18 14:49:50 +00004966
Stefan Krah1919b7e2012-03-21 18:25:23 +01004967 try:
4968 from locale import CHAR_MAX
4969 except ImportError:
4970 return
Mark Dickinson84230a12010-02-18 14:49:50 +00004971
Stefan Krah1919b7e2012-03-21 18:25:23 +01004972 def make_grouping(lst):
4973 return ''.join([chr(x) for x in lst])
Mark Dickinson84230a12010-02-18 14:49:50 +00004974
Stefan Krah1919b7e2012-03-21 18:25:23 +01004975 def get_fmt(x, override=None, fmt='n'):
4976 return Decimal(x).__format__(fmt, override)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004977
Stefan Krah1919b7e2012-03-21 18:25:23 +01004978 invalid_grouping = {
4979 'decimal_point' : ',',
4980 'grouping' : make_grouping([255, 255, 0]),
4981 'thousands_sep' : ','
4982 }
4983 invalid_dot = {
4984 'decimal_point' : 'xxxxx',
4985 'grouping' : make_grouping([3, 3, 0]),
4986 'thousands_sep' : ','
4987 }
4988 invalid_sep = {
4989 'decimal_point' : '.',
4990 'grouping' : make_grouping([3, 3, 0]),
4991 'thousands_sep' : 'yyyyy'
4992 }
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004993
Stefan Krah1919b7e2012-03-21 18:25:23 +01004994 if CHAR_MAX == 127: # negative grouping in override
4995 self.assertRaises(ValueError, get_fmt, 12345,
4996 invalid_grouping, 'g')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004997
Stefan Krah1919b7e2012-03-21 18:25:23 +01004998 self.assertRaises(ValueError, get_fmt, 12345, invalid_dot, 'g')
4999 self.assertRaises(ValueError, get_fmt, 12345, invalid_sep, 'g')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005000
Stefan Krah0774e9b2012-04-05 15:21:58 +02005001 def test_exact_conversion(self):
5002 Decimal = C.Decimal
5003 localcontext = C.localcontext
5004 InvalidOperation = C.InvalidOperation
5005
5006 with localcontext() as c:
5007
5008 c.traps[InvalidOperation] = True
5009
5010 # Clamped
5011 x = "0e%d" % sys.maxsize
5012 self.assertRaises(InvalidOperation, Decimal, x)
5013
5014 x = "0e%d" % (-sys.maxsize-1)
5015 self.assertRaises(InvalidOperation, Decimal, x)
5016
5017 # Overflow
5018 x = "1e%d" % sys.maxsize
5019 self.assertRaises(InvalidOperation, Decimal, x)
5020
5021 # Underflow
5022 x = "1e%d" % (-sys.maxsize-1)
5023 self.assertRaises(InvalidOperation, Decimal, x)
5024
Stefan Krahff3eca02012-04-05 15:46:19 +02005025 def test_from_tuple(self):
5026 Decimal = C.Decimal
5027 localcontext = C.localcontext
5028 InvalidOperation = C.InvalidOperation
5029 Overflow = C.Overflow
5030 Underflow = C.Underflow
5031
5032 with localcontext() as c:
5033
5034 c.traps[InvalidOperation] = True
5035 c.traps[Overflow] = True
5036 c.traps[Underflow] = True
5037
5038 # SSIZE_MAX
5039 x = (1, (), sys.maxsize)
5040 self.assertEqual(str(c.create_decimal(x)), '-0E+999999')
5041 self.assertRaises(InvalidOperation, Decimal, x)
5042
5043 x = (1, (0, 1, 2), sys.maxsize)
5044 self.assertRaises(Overflow, c.create_decimal, x)
5045 self.assertRaises(InvalidOperation, Decimal, x)
5046
5047 # SSIZE_MIN
5048 x = (1, (), -sys.maxsize-1)
5049 self.assertEqual(str(c.create_decimal(x)), '-0E-1000026')
5050 self.assertRaises(InvalidOperation, Decimal, x)
5051
5052 x = (1, (0, 1, 2), -sys.maxsize-1)
5053 self.assertRaises(Underflow, c.create_decimal, x)
5054 self.assertRaises(InvalidOperation, Decimal, x)
5055
5056 # OverflowError
5057 x = (1, (), sys.maxsize+1)
5058 self.assertRaises(OverflowError, c.create_decimal, x)
5059 self.assertRaises(OverflowError, Decimal, x)
5060
5061 x = (1, (), -sys.maxsize-2)
5062 self.assertRaises(OverflowError, c.create_decimal, x)
5063 self.assertRaises(OverflowError, Decimal, x)
5064
5065 # Specials
5066 x = (1, (), "N")
5067 self.assertEqual(str(Decimal(x)), '-sNaN')
5068 x = (1, (0,), "N")
5069 self.assertEqual(str(Decimal(x)), '-sNaN')
5070 x = (1, (0, 1), "N")
5071 self.assertEqual(str(Decimal(x)), '-sNaN1')
5072
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005073
Stefan Krah1919b7e2012-03-21 18:25:23 +01005074all_tests = [
5075 CExplicitConstructionTest, PyExplicitConstructionTest,
5076 CImplicitConstructionTest, PyImplicitConstructionTest,
5077 CFormatTest, PyFormatTest,
5078 CArithmeticOperatorsTest, PyArithmeticOperatorsTest,
5079 CThreadingTest, PyThreadingTest,
5080 CUsabilityTest, PyUsabilityTest,
5081 CPythonAPItests, PyPythonAPItests,
5082 CContextAPItests, PyContextAPItests,
5083 CContextWithStatement, PyContextWithStatement,
5084 CContextFlags, PyContextFlags,
5085 CSpecialContexts, PySpecialContexts,
5086 CContextInputValidation, PyContextInputValidation,
5087 CContextSubclassing, PyContextSubclassing,
5088 CCoverage, PyCoverage,
5089 CFunctionality, PyFunctionality,
5090 CWhitebox, PyWhitebox,
5091 CIBMTestCases, PyIBMTestCases,
5092]
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005093
Stefan Krah1919b7e2012-03-21 18:25:23 +01005094# Delete C tests if _decimal.so is not present.
5095if not C:
5096 all_tests = all_tests[1::2]
5097else:
5098 all_tests.insert(0, CheckAttributes)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005099
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005100
5101def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00005102 """ Execute the tests.
5103
Raymond Hettingered20ad82004-09-04 20:09:13 +00005104 Runs all arithmetic tests if arith is True or if the "decimal" resource
5105 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00005106 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00005107
Stefan Krah1919b7e2012-03-21 18:25:23 +01005108 init(C)
5109 init(P)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005110 global TEST_ALL, DEBUG
Raymond Hettingered20ad82004-09-04 20:09:13 +00005111 TEST_ALL = arith or is_resource_enabled('decimal')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005112 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00005113
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005114 if todo_tests is None:
Stefan Krah1919b7e2012-03-21 18:25:23 +01005115 test_classes = all_tests
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005116 else:
Stefan Krah1919b7e2012-03-21 18:25:23 +01005117 test_classes = [CIBMTestCases, PyIBMTestCases]
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005118
5119 # Dynamically build custom test definition for each file in the test
5120 # directory and add the definitions to the DecimalTest class. This
5121 # procedure insures that new files do not get skipped.
5122 for filename in os.listdir(directory):
5123 if '.decTest' not in filename or filename.startswith("."):
5124 continue
5125 head, tail = filename.split('.')
5126 if todo_tests is not None and head not in todo_tests:
5127 continue
5128 tester = lambda self, f=filename: self.eval_file(directory + f)
Stefan Krah1919b7e2012-03-21 18:25:23 +01005129 setattr(CIBMTestCases, 'test_' + head, tester)
5130 setattr(PyIBMTestCases, 'test_' + head, tester)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005131 del filename, head, tail, tester
5132
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00005133
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00005134 try:
5135 run_unittest(*test_classes)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005136 if todo_tests is None:
Stefan Krah1919b7e2012-03-21 18:25:23 +01005137 from doctest import IGNORE_EXCEPTION_DETAIL
5138 savedecimal = sys.modules['decimal']
5139 if C:
5140 sys.modules['decimal'] = C
5141 run_doctest(C, verbose, optionflags=IGNORE_EXCEPTION_DETAIL)
5142 sys.modules['decimal'] = P
5143 run_doctest(P, verbose)
5144 sys.modules['decimal'] = savedecimal
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00005145 finally:
Stefan Krah1919b7e2012-03-21 18:25:23 +01005146 if C: C.setcontext(ORIGINAL_CONTEXT[C])
5147 P.setcontext(ORIGINAL_CONTEXT[P])
5148 if not C:
5149 warnings.warn('C tests skipped: no module named _decimal.',
5150 UserWarning)
5151 if not orig_sys_decimal is sys.modules['decimal']:
5152 raise TestFailed("Internal error: unbalanced number of changes to "
5153 "sys.modules['decimal'].")
5154
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00005155
5156if __name__ == '__main__':
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005157 import optparse
5158 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
5159 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
5160 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
5161 (opt, args) = p.parse_args()
5162
5163 if opt.skip:
5164 test_main(arith=False, verbose=True)
5165 elif args:
5166 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00005167 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005168 test_main(arith=True, verbose=True)