test interactions between int float decimal and fraction constants related to the hash implementation hashx is based on the reduction of x modulo the prime pyhashmodulus dummy integral class to test conversion of the rational to float def mulself other return dummyintegralsuper mulother rmul mul def truedivself other return notimplemented rtruediv truediv property def numeratorself return dummyintegralself property def denominatorself return dummyintegral1 class hashtestunittest testcase def checkequalhashself x y check both that x and y are equal and that their hashes are equal self assertequalhashx hashy got different hashes for r and r formatx y self assertequalx y def testboolsself self checkequalhashfalse 0 self checkequalhashtrue 1 def testintegersself check that equal values hash equal exact integers for i in range1000 1000 self checkequalhashi floati self checkequalhashi di self checkequalhashi fi the current hash is based on reduction modulo 2n1 for some n so pay special attention to numbers of the form 2n and 2n1 for i in range100 n 2i 1 if n intfloatn self checkequalhashn floatn self checkequalhashn floatn self checkequalhashn dn self checkequalhashn fn self checkequalhashn dn self checkequalhashn fn n 2i self checkequalhashn floatn self checkequalhashn floatn self checkequalhashn dn self checkequalhashn fn self checkequalhashn dn self checkequalhashn fn random values of various sizes for in range1000 e random randrange300 n random randrange10e 10e self checkequalhashn dn self checkequalhashn fn if n intfloatn self checkequalhashn floatn def testbinaryfloatsself check that floats hash equal to corresponding fractions and decimals floats that are distinct but numerically equal should hash the same self checkequalhash0 0 0 0 zeros self checkequalhash0 0 d0 self checkequalhash0 0 d0 self checkequalhash0 0 d 0 0 self checkequalhash0 0 f0 infinities and nans self checkequalhashfloat inf d inf self checkequalhashfloat inf d inf for in range1000 x random random math exprandom random200 0 100 0 self checkequalhashx d fromfloatx self checkequalhashx f fromfloatx def testcomplexself complex numbers with zero imaginary part should hash equal to the corresponding float testvalues 0 0 0 0 1 0 1 0 0 40625 5136 5 float inf float inf for zero in 0 0 0 0 for value in testvalues self checkequalhashvalue complexvalue zero def testdecimalsself check that decimal instances that have different representations but equal values give the same hash zeros 0 0 0 0 0 0e10 000e10 for zero in zeros self checkequalhashdzero d0 self checkequalhashd 1 00 d1 self checkequalhashd 1 00000 d1 self checkequalhashd 1 00 d1 self checkequalhashd 1 00000 d1 self checkequalhashd 123e2 d12300 self checkequalhashd 1230e1 d12300 self checkequalhashd 12300 d12300 self checkequalhashd 12300 0 d12300 self checkequalhashd 12300 00 d12300 self checkequalhashd 12300 000 d12300 def testfractionsself check special case for fractions where either the numerator or the denominator is a multiple of pyhashmodulus self assertequalhashf1 pyhashmodulus pyhashinf self assertequalhashf1 3pyhashmodulus pyhashinf self assertequalhashf7pyhashmodulus 1 0 self assertequalhashfpyhashmodulus 1 0 the numbers abc doesn t enforce that the true division of integers produces a float this tests that the rational float method has required type conversions x f fromcoprimeintsdummyintegral1 dummyintegral2 self assertraisestypeerror lambda x numeratorx denominator self assertequalfloatx 0 5 def testhashnormalizationself test for a bug encountered while changing longhash given objects x and y it should be possible for y s hash method to return hashx in order to ensure that hashx hashy but hashx is not exactly equal to the result of x hash there s some internal normalization to make sure that the result fits in a c long and is not equal to the invalid hash value 1 this internal normalization must therefore not change the result of hashx for any x class halibutproxy def hashself return hash halibut def eqself other return other halibut x halibut halibutproxy self assertequallenx 1 class comparisontestunittest testcase def testmixedcomparisonsself ordered list of distinct test values of various types int float fraction decimal testvalues float inf d 1e425000000 1e308 f22 7 3 14 2 0 0 1e320 true f 1 2 d 1 3 float 1 4 f275807 195025 d 1 414213562373095048801688724 f114243 80782 f473596569 84615 7e200 d infinity for i first in enumeratetestvalues for second in testvaluesi1 self assertlessfirst second self assertlessequalfirst second self assertgreatersecond first self assertgreaterequalsecond first def testcomplexself comparisons with complex are special equality and inequality comparisons should always succeed but order comparisons should raise typeerror z 1 0 0j w 3 14 2 7j for v in 1 1 0 f1 d1 complex1 self assertequalz v self assertequalv z for v in 2 2 0 f2 d2 complex2 self assertnotequalz v self assertnotequalv z self assertnotequalw v self assertnotequalv w for v in 1 1 0 f1 d1 complex1 2 2 0 f2 d2 complex2 w for op in operator le operator lt operator ge operator gt self assertraisestypeerror op z v self assertraisestypeerror op v z if name main unittest main test interactions between int float decimal and fraction constants related to the hash implementation hash x is based on the reduction of x modulo the prime _pyhash_modulus dummy integral class to test conversion of the rational to float check both that x and y are equal and that their hashes are equal check that equal values hash equal exact integers the current hash is based on reduction modulo 2 n 1 for some n so pay special attention to numbers of the form 2 n and 2 n 1 random values of various sizes check that floats hash equal to corresponding fractions and decimals floats that are distinct but numerically equal should hash the same zeros infinities and nans complex numbers with zero imaginary part should hash equal to the corresponding float check that decimal instances that have different representations but equal values give the same hash check special case for fractions where either the numerator or the denominator is a multiple of _pyhash_modulus the numbers abc doesn t enforce that the true division of integers produces a float this tests that the rational __float__ method has required type conversions test for a bug encountered while changing long_hash given objects x and y it should be possible for y s __hash__ method to return hash x in order to ensure that hash x hash y but hash x is not exactly equal to the result of x __hash__ there s some internal normalization to make sure that the result fits in a c long and is not equal to the invalid hash value 1 this internal normalization must therefore not change the result of hash x for any x ordered list of distinct test values of various types int float fraction decimal comparisons with complex are special equality and inequality comparisons should always succeed but order comparisons should raise typeerror
import unittest
import random
import math
import sys
import operator

from decimal import Decimal as D
from fractions import Fraction as F



_PyHASH_MODULUS = sys.hash_info.modulus
_PyHASH_INF = sys.hash_info.inf


class DummyIntegral(int):
    

    def __mul__(self, other):
        return DummyIntegral(super().__mul__(other))
    __rmul__ = __mul__

    def __truediv__(self, other):
        return NotImplemented
    __rtruediv__ = __truediv__

    @property
    def numerator(self):
        return DummyIntegral(self)

    @property
    def denominator(self):
        return DummyIntegral(1)


class HashTest(unittest.TestCase):
    def check_equal_hash(self, x, y):
        
        self.assertEqual(hash(x), hash(y),
                         "got different hashes for {!r} and {!r}".format(x, y))
        self.assertEqual(x, y)

    def test_bools(self):
        self.check_equal_hash(False, 0)
        self.check_equal_hash(True, 1)

    def test_integers(self):
        

        
        for i in range(-1000, 1000):
            self.check_equal_hash(i, float(i))
            self.check_equal_hash(i, D(i))
            self.check_equal_hash(i, F(i))

        
        
        for i in range(100):
            n = 2**i - 1
            if n == int(float(n)):
                self.check_equal_hash(n, float(n))
                self.check_equal_hash(-n, -float(n))
            self.check_equal_hash(n, D(n))
            self.check_equal_hash(n, F(n))
            self.check_equal_hash(-n, D(-n))
            self.check_equal_hash(-n, F(-n))

            n = 2**i
            self.check_equal_hash(n, float(n))
            self.check_equal_hash(-n, -float(n))
            self.check_equal_hash(n, D(n))
            self.check_equal_hash(n, F(n))
            self.check_equal_hash(-n, D(-n))
            self.check_equal_hash(-n, F(-n))

        
        for _ in range(1000):
            e = random.randrange(300)
            n = random.randrange(-10**e, 10**e)
            self.check_equal_hash(n, D(n))
            self.check_equal_hash(n, F(n))
            if n == int(float(n)):
                self.check_equal_hash(n, float(n))

    def test_binary_floats(self):
        

        
        self.check_equal_hash(0.0, -0.0)

        
        self.check_equal_hash(0.0, D(0))
        self.check_equal_hash(-0.0, D(0))
        self.check_equal_hash(-0.0, D('-0.0'))
        self.check_equal_hash(0.0, F(0))

        
        self.check_equal_hash(float('inf'), D('inf'))
        self.check_equal_hash(float('-inf'), D('-inf'))

        for _ in range(1000):
            x = random.random() * math.exp(random.random()*200.0 - 100.0)
            self.check_equal_hash(x, D.from_float(x))
            self.check_equal_hash(x, F.from_float(x))

    def test_complex(self):
        
        

        test_values = [0.0, -0.0, 1.0, -1.0, 0.40625, -5136.5,
                       float('inf'), float('-inf')]

        for zero in -0.0, 0.0:
            for value in test_values:
                self.check_equal_hash(value, complex(value, zero))

    def test_decimals(self):
        
        
        zeros = ['0', '-0', '0.0', '-0.0e10', '000e-10']
        for zero in zeros:
            self.check_equal_hash(D(zero), D(0))

        self.check_equal_hash(D('1.00'), D(1))
        self.check_equal_hash(D('1.00000'), D(1))
        self.check_equal_hash(D('-1.00'), D(-1))
        self.check_equal_hash(D('-1.00000'), D(-1))
        self.check_equal_hash(D('123e2'), D(12300))
        self.check_equal_hash(D('1230e1'), D(12300))
        self.check_equal_hash(D('12300'), D(12300))
        self.check_equal_hash(D('12300.0'), D(12300))
        self.check_equal_hash(D('12300.00'), D(12300))
        self.check_equal_hash(D('12300.000'), D(12300))

    def test_fractions(self):
        
        
        self.assertEqual(hash(F(1, _PyHASH_MODULUS)), _PyHASH_INF)
        self.assertEqual(hash(F(-1, 3*_PyHASH_MODULUS)), -_PyHASH_INF)
        self.assertEqual(hash(F(7*_PyHASH_MODULUS, 1)), 0)
        self.assertEqual(hash(F(-_PyHASH_MODULUS, 1)), 0)

        
        
        
        x = F._from_coprime_ints(DummyIntegral(1), DummyIntegral(2))
        self.assertRaises(TypeError, lambda: x.numerator/x.denominator)
        self.assertEqual(float(x), 0.5)

    def test_hash_normalization(self):
        
        
        
        
        
        
        
        
        
        

        class HalibutProxy:
            def __hash__(self):
                return hash('halibut')
            def __eq__(self, other):
                return other == 'halibut'

        x = {'halibut', HalibutProxy()}
        self.assertEqual(len(x), 1)

class ComparisonTest(unittest.TestCase):
    def test_mixed_comparisons(self):

        
        
        test_values = [
            float('-inf'),
            D('-1e425000000'),
            -1e308,
            F(-22, 7),
            -3.14,
            -2,
            0.0,
            1e-320,
            True,
            F('1.2'),
            D('1.3'),
            float('1.4'),
            F(275807, 195025),
            D('1.414213562373095048801688724'),
            F(114243, 80782),
            F(473596569, 84615),
            7e200,
            D('infinity'),
            ]
        for i, first in enumerate(test_values):
            for second in test_values[i+1:]:
                self.assertLess(first, second)
                self.assertLessEqual(first, second)
                self.assertGreater(second, first)
                self.assertGreaterEqual(second, first)

    def test_complex(self):
        
        
        
        z = 1.0 + 0j
        w = -3.14 + 2.7j

        for v in 1, 1.0, F(1), D(1), complex(1):
            self.assertEqual(z, v)
            self.assertEqual(v, z)

        for v in 2, 2.0, F(2), D(2), complex(2):
            self.assertNotEqual(z, v)
            self.assertNotEqual(v, z)
            self.assertNotEqual(w, v)
            self.assertNotEqual(v, w)

        for v in (1, 1.0, F(1), D(1), complex(1),
                  2, 2.0, F(2), D(2), complex(2), w):
            for op in operator.le, operator.lt, operator.ge, operator.gt:
                self.assertRaises(TypeError, op, z, v)
                self.assertRaises(TypeError, op, v, z)


if __name__ == '__main__':
    unittest.main()