517 lines
13 KiB
Plaintext
517 lines
13 KiB
Plaintext
|
# Test cases for floats (compile and run)
|
||
|
|
||
|
[case testFloatOps]
|
||
|
from __future__ import annotations
|
||
|
from typing import Any, cast
|
||
|
from typing_extensions import Final
|
||
|
from testutil import assertRaises, float_vals, FLOAT_MAGIC
|
||
|
import math
|
||
|
|
||
|
def test_arithmetic() -> None:
|
||
|
zero = float(0.0)
|
||
|
one = zero + 1.0
|
||
|
x = one + one / 2.0
|
||
|
assert x == 1.5
|
||
|
assert x - one == 0.5
|
||
|
assert x * x == 2.25
|
||
|
assert x / 2.0 == 0.75
|
||
|
assert x * (-0.5) == -0.75
|
||
|
assert -x == -1.5
|
||
|
for x in float_vals:
|
||
|
assert repr(-x) == repr(getattr(x, "__neg__")())
|
||
|
|
||
|
for y in float_vals:
|
||
|
assert repr(x + y) == repr(getattr(x, "__add__")(y))
|
||
|
assert repr(x - y) == repr(getattr(x, "__sub__")(y))
|
||
|
assert repr(x * y) == repr(getattr(x, "__mul__")(y))
|
||
|
if y != 0:
|
||
|
assert repr(x / y) == repr(getattr(x, "__truediv__")(y))
|
||
|
|
||
|
def test_mod() -> None:
|
||
|
zero = float(0.0)
|
||
|
one = zero + 1.0
|
||
|
x = one + one / 2.0
|
||
|
assert x % 0.4 == 0.29999999999999993
|
||
|
assert (-x) % 0.4 == 0.10000000000000009
|
||
|
assert x % -0.4 == -0.10000000000000009
|
||
|
assert (-x) % -0.4 == -0.29999999999999993
|
||
|
for x in float_vals:
|
||
|
for y in float_vals:
|
||
|
if y != 0:
|
||
|
assert repr(x % y) == repr(getattr(x, "__mod__")(y))
|
||
|
|
||
|
def test_floor_div() -> None:
|
||
|
for x in float_vals:
|
||
|
for y in float_vals:
|
||
|
if y != 0:
|
||
|
assert repr(x // y) == repr(getattr(x, "__floordiv__")(y))
|
||
|
else:
|
||
|
with assertRaises(ZeroDivisionError, "float floor division by zero"):
|
||
|
x // y
|
||
|
|
||
|
def test_mixed_arithmetic() -> None:
|
||
|
zf = float(0.0)
|
||
|
zn = int()
|
||
|
assert (zf + 5.5) + (zn + 1) == 6.5
|
||
|
assert (zn - 2) - (zf - 5.5) == 3.5
|
||
|
x = zf + 3.4
|
||
|
x += zn + 2
|
||
|
assert x == 5.4
|
||
|
|
||
|
def test_arithmetic_errors() -> None:
|
||
|
zero = float(0.0)
|
||
|
one = zero + 1.0
|
||
|
with assertRaises(ZeroDivisionError, "float division by zero"):
|
||
|
print(one / zero)
|
||
|
with assertRaises(ZeroDivisionError, "float modulo"):
|
||
|
print(one % zero)
|
||
|
|
||
|
def test_comparisons() -> None:
|
||
|
zero = float(0.0)
|
||
|
one = zero + 1.0
|
||
|
x = one + one / 2.0
|
||
|
assert x < (1.51 + zero)
|
||
|
assert not (x < (1.49 + zero))
|
||
|
assert x > (1.49 + zero)
|
||
|
assert not (x > (1.51 + zero))
|
||
|
assert x <= (1.5 + zero)
|
||
|
assert not (x <= (1.49 + zero))
|
||
|
assert x >= (1.5 + zero)
|
||
|
assert not (x >= (1.51 + zero))
|
||
|
for x in float_vals:
|
||
|
for y in float_vals:
|
||
|
assert (x <= y) == getattr(x, "__le__")(y)
|
||
|
assert (x < y) == getattr(x, "__lt__")(y)
|
||
|
assert (x >= y) == getattr(x, "__ge__")(y)
|
||
|
assert (x > y) == getattr(x, "__gt__")(y)
|
||
|
assert (x == y) == getattr(x, "__eq__")(y)
|
||
|
assert (x != y) == getattr(x, "__ne__")(y)
|
||
|
|
||
|
def test_mixed_comparisons() -> None:
|
||
|
zf = float(0.0)
|
||
|
zn = int()
|
||
|
if (zf + 1.0) == (zn + 1):
|
||
|
assert True
|
||
|
else:
|
||
|
assert False
|
||
|
if (zf + 1.1) == (zn + 1):
|
||
|
assert False
|
||
|
else:
|
||
|
assert True
|
||
|
assert (zf + 1.1) != (zn + 1)
|
||
|
assert (zf + 1.1) > (zn + 1)
|
||
|
assert not (zf + 0.9) > (zn + 1)
|
||
|
assert (zn + 1) < (zf + 1.1)
|
||
|
|
||
|
def test_boxing_and_unboxing() -> None:
|
||
|
x = 1.5
|
||
|
boxed: Any = x
|
||
|
assert repr(boxed) == "1.5"
|
||
|
assert type(boxed) is float
|
||
|
y: float = boxed
|
||
|
assert y == x
|
||
|
boxed_int: Any = 5
|
||
|
assert [type(boxed_int)] == [int] # Avoid mypy type narrowing
|
||
|
z: float = boxed_int
|
||
|
assert z == 5.0
|
||
|
for xx in float_vals:
|
||
|
bb: Any = xx
|
||
|
yy: float = bb
|
||
|
assert repr(xx) == repr(bb)
|
||
|
assert repr(xx) == repr(yy)
|
||
|
for b in True, False:
|
||
|
boxed_bool: Any = b
|
||
|
assert type(boxed_bool) is bool
|
||
|
zz: float = boxed_bool
|
||
|
assert zz == int(b)
|
||
|
|
||
|
def test_unboxing_failure() -> None:
|
||
|
boxed: Any = '1.5'
|
||
|
with assertRaises(TypeError):
|
||
|
x: float = boxed
|
||
|
|
||
|
def identity(x: float) -> float:
|
||
|
return x
|
||
|
|
||
|
def test_coerce_from_int_literal() -> None:
|
||
|
assert identity(34) == 34.0
|
||
|
assert identity(-1) == -1.0
|
||
|
|
||
|
def test_coerce_from_short_tagged_int() -> None:
|
||
|
n = int() - 17
|
||
|
assert identity(n) == -17.0
|
||
|
for i in range(-300, 300):
|
||
|
assert identity(i) == float(i)
|
||
|
|
||
|
def test_coerce_from_long_tagged_int() -> None:
|
||
|
n = int() + 2**100
|
||
|
x = identity(n)
|
||
|
assert repr(x) == '1.2676506002282294e+30'
|
||
|
n = int() - 2**100
|
||
|
y = identity(n)
|
||
|
assert repr(y) == '-1.2676506002282294e+30'
|
||
|
|
||
|
def test_coerce_from_very_long_tagged_int() -> None:
|
||
|
n = int() + 10**1000
|
||
|
with assertRaises(OverflowError, "int too large to convert to float"):
|
||
|
identity(n)
|
||
|
with assertRaises(OverflowError, "int too large to convert to float"):
|
||
|
identity(int(n))
|
||
|
n = int() - 10**1000
|
||
|
with assertRaises(OverflowError, "int too large to convert to float"):
|
||
|
identity(n)
|
||
|
with assertRaises(OverflowError, "int too large to convert to float"):
|
||
|
identity(int(n))
|
||
|
|
||
|
def test_explicit_conversion_from_int() -> None:
|
||
|
float_any: Any = float
|
||
|
a = [0, 1, 2, 3, -1, -2, 13257, -928745]
|
||
|
for n in range(1, 100):
|
||
|
for delta in -1, 0, 1, 2342345:
|
||
|
a.append(2**n + delta)
|
||
|
a.append(-2**n + delta)
|
||
|
for x in a:
|
||
|
assert repr(float(x)) == repr(float_any(x))
|
||
|
|
||
|
def test_explicit_conversion_to_int() -> None:
|
||
|
int_any: Any = int
|
||
|
for x in float_vals:
|
||
|
if math.isinf(x):
|
||
|
with assertRaises(OverflowError, "cannot convert float infinity to integer"):
|
||
|
int(x)
|
||
|
elif math.isnan(x):
|
||
|
with assertRaises(ValueError, "cannot convert float NaN to integer"):
|
||
|
int(x)
|
||
|
else:
|
||
|
assert repr(int(x)) == repr(int_any(x))
|
||
|
|
||
|
# Test some edge cases
|
||
|
assert 2**30 == int(2.0**30 + int())
|
||
|
assert 2**30 - 1 == int(1073741823.9999999 + int()) # math.nextafter(2.0**30, 0))
|
||
|
assert -2**30 - 1 == int(-2.0**30 - 1 + int())
|
||
|
assert -2**30 == int(-1073741824.9999998 + int()) # math.nextafter(-2.0**30 - 1, 0)
|
||
|
assert 2**62 == int(2.0**62 + int())
|
||
|
assert 2**62 == int(2.0**62 - 1 + int())
|
||
|
assert -2**62 == int(-2.0**62 + int())
|
||
|
assert -2**62 == int(-2.0**62 - 1 + int())
|
||
|
|
||
|
def str_to_float(x: str) -> float:
|
||
|
return float(x)
|
||
|
|
||
|
def test_str_to_float() -> None:
|
||
|
assert str_to_float("1") == 1.0
|
||
|
assert str_to_float("1.234567") == 1.234567
|
||
|
assert str_to_float("44324") == 44324.0
|
||
|
assert str_to_float("23.4") == 23.4
|
||
|
assert str_to_float("-43.44e-4") == -43.44e-4
|
||
|
assert str_to_float("-43.44e-4") == -43.44e-4
|
||
|
assert math.isinf(str_to_float("inf"))
|
||
|
assert math.isinf(str_to_float("-inf"))
|
||
|
assert str_to_float("inf") > 0.0
|
||
|
assert str_to_float("-inf") < 0.0
|
||
|
assert math.isnan(str_to_float("nan"))
|
||
|
assert math.isnan(str_to_float("NaN"))
|
||
|
assert repr(str_to_float("-0.0")) == "-0.0"
|
||
|
|
||
|
def test_abs() -> None:
|
||
|
assert abs(0.0) == 0.0
|
||
|
assert abs(-1.234567) == 1.234567
|
||
|
assert abs(44324.732) == 44324.732
|
||
|
assert abs(-23.4) == 23.4
|
||
|
assert abs(-43.44e-4) == 43.44e-4
|
||
|
abs_any: Any = abs
|
||
|
for x in float_vals:
|
||
|
assert repr(abs(x)) == repr(abs_any(x))
|
||
|
|
||
|
def test_float_min_max() -> None:
|
||
|
for x in float_vals:
|
||
|
for y in float_vals:
|
||
|
min_any: Any = min
|
||
|
assert repr(min(x, y)) == repr(min_any(x, y))
|
||
|
max_any: Any = max
|
||
|
assert repr(max(x, y)) == repr(max_any(x, y))
|
||
|
|
||
|
def default(x: float = 2) -> float:
|
||
|
return x + 1
|
||
|
|
||
|
def test_float_default_value() -> None:
|
||
|
assert default(1.2) == 2.2
|
||
|
for i in range(-200, 200):
|
||
|
assert default(float(i)) == i + 1
|
||
|
assert default() == 3.0
|
||
|
|
||
|
def test_float_default_value_wrapper() -> None:
|
||
|
f: Any = default
|
||
|
assert f(1.2) == 2.2
|
||
|
for i in range(-200, 200):
|
||
|
assert f(float(i)) == i + 1
|
||
|
assert f() == 3.0
|
||
|
|
||
|
class C:
|
||
|
def __init__(self, x: float) -> None:
|
||
|
self.x = x
|
||
|
|
||
|
def test_float_attr() -> None:
|
||
|
for i in range(-200, 200):
|
||
|
f = float(i)
|
||
|
c = C(f)
|
||
|
assert c.x == f
|
||
|
a: Any = c
|
||
|
assert a.x == f
|
||
|
c.x = FLOAT_MAGIC
|
||
|
assert c.x == FLOAT_MAGIC
|
||
|
assert a.x == FLOAT_MAGIC
|
||
|
a.x = 1.0
|
||
|
assert a.x == 1.0
|
||
|
a.x = FLOAT_MAGIC
|
||
|
assert a.x == FLOAT_MAGIC
|
||
|
|
||
|
class D:
|
||
|
def __init__(self, x: float) -> None:
|
||
|
if x:
|
||
|
self.x = x
|
||
|
|
||
|
def test_float_attr_maybe_undefned() -> None:
|
||
|
for i in range(-200, 200):
|
||
|
if i == 0:
|
||
|
d = D(0.0)
|
||
|
with assertRaises(AttributeError):
|
||
|
d.x
|
||
|
a: Any = d
|
||
|
with assertRaises(AttributeError):
|
||
|
a.x
|
||
|
d.x = FLOAT_MAGIC
|
||
|
assert d.x == FLOAT_MAGIC
|
||
|
assert a.x == FLOAT_MAGIC
|
||
|
d.x = 0.0
|
||
|
assert d.x == 0.0
|
||
|
assert a.x == 0.0
|
||
|
a.x = FLOAT_MAGIC
|
||
|
assert a.x == FLOAT_MAGIC
|
||
|
d = D(0.0)
|
||
|
a = cast(Any, d)
|
||
|
a.x = FLOAT_MAGIC
|
||
|
assert d.x == FLOAT_MAGIC
|
||
|
else:
|
||
|
f = float(i)
|
||
|
d = D(f)
|
||
|
assert d.x == f
|
||
|
a2: Any = d
|
||
|
assert a2.x == f
|
||
|
|
||
|
def f(x: float) -> float:
|
||
|
return x + 1
|
||
|
|
||
|
def test_return_values() -> None:
|
||
|
a: Any = f
|
||
|
for i in range(-200, 200):
|
||
|
x = float(i)
|
||
|
assert f(x) == x + 1
|
||
|
assert a(x) == x + 1
|
||
|
for x in float_vals:
|
||
|
if not math.isnan(x):
|
||
|
assert f(x) == x + 1
|
||
|
else:
|
||
|
assert math.isnan(f(x))
|
||
|
|
||
|
def exc() -> float:
|
||
|
raise IndexError('x')
|
||
|
|
||
|
def test_exception() -> None:
|
||
|
with assertRaises(IndexError):
|
||
|
exc()
|
||
|
a: Any = exc
|
||
|
with assertRaises(IndexError):
|
||
|
a()
|
||
|
|
||
|
def test_undefined_local_var() -> None:
|
||
|
if not int():
|
||
|
x = -113.0
|
||
|
assert x == -113.0
|
||
|
if int():
|
||
|
y = -113.0
|
||
|
with assertRaises(UnboundLocalError, 'local variable "y" referenced before assignment'):
|
||
|
print(y)
|
||
|
if not int():
|
||
|
x2 = -1.0
|
||
|
assert x2 == -1.0
|
||
|
if int():
|
||
|
y2 = -1.0
|
||
|
with assertRaises(UnboundLocalError, 'local variable "y2" referenced before assignment'):
|
||
|
print(y2)
|
||
|
|
||
|
def test_tuples() -> None:
|
||
|
t1: tuple[float, float] = (1.5, 2.5)
|
||
|
assert t1 == tuple([1.5, 2.5])
|
||
|
n = int() + 5
|
||
|
t2: tuple[float, float, float, float] = (n, 1.5, -7, -113)
|
||
|
assert t2 == tuple([5.0, 1.5, -7.0, -113.0])
|
||
|
|
||
|
[case testFloatGlueMethodsAndInheritance]
|
||
|
from typing import Any
|
||
|
from typing_extensions import Final
|
||
|
|
||
|
from mypy_extensions import trait
|
||
|
|
||
|
from testutil import assertRaises
|
||
|
|
||
|
MAGIC: Final = -113.0
|
||
|
|
||
|
class Base:
|
||
|
def foo(self) -> float:
|
||
|
return 5.0
|
||
|
|
||
|
def bar(self, x: float = 2.0) -> float:
|
||
|
return x + 1
|
||
|
|
||
|
def hoho(self, x: float) -> float:
|
||
|
return x - 1
|
||
|
|
||
|
class Derived(Base):
|
||
|
def foo(self, x: float = 5.0) -> float:
|
||
|
return x + 10
|
||
|
|
||
|
def bar(self, x: float = 3, y: float = 20) -> float:
|
||
|
return x + y + 2
|
||
|
|
||
|
def hoho(self, x: float = 7) -> float:
|
||
|
return x - 2
|
||
|
|
||
|
def test_derived_adds_bitmap() -> None:
|
||
|
b: Base = Derived()
|
||
|
assert b.foo() == 15
|
||
|
|
||
|
def test_derived_adds_another_default_arg() -> None:
|
||
|
b: Base = Derived()
|
||
|
assert b.bar() == 25
|
||
|
assert b.bar(1) == 23
|
||
|
assert b.bar(MAGIC) == MAGIC + 22
|
||
|
|
||
|
def test_derived_switches_arg_to_have_default() -> None:
|
||
|
b: Base = Derived()
|
||
|
assert b.hoho(5) == 3
|
||
|
assert b.hoho(MAGIC) == MAGIC - 2
|
||
|
|
||
|
@trait
|
||
|
class T:
|
||
|
@property
|
||
|
def x(self) -> float: ...
|
||
|
@property
|
||
|
def y(self) -> float: ...
|
||
|
|
||
|
class C(T):
|
||
|
x: float = 1.0
|
||
|
y: float = 4
|
||
|
|
||
|
def test_read_only_property_in_trait_implemented_as_attribute() -> None:
|
||
|
c = C()
|
||
|
c.x = 5.5
|
||
|
assert c.x == 5.5
|
||
|
c.x = MAGIC
|
||
|
assert c.x == MAGIC
|
||
|
assert c.y == 4
|
||
|
c.y = 6.5
|
||
|
assert c.y == 6.5
|
||
|
t: T = C()
|
||
|
assert t.y == 4
|
||
|
t = c
|
||
|
assert t.x == MAGIC
|
||
|
c.x = 55.5
|
||
|
assert t.x == 55.5
|
||
|
assert t.y == 6.5
|
||
|
a: Any = c
|
||
|
assert a.x == 55.5
|
||
|
assert a.y == 6.5
|
||
|
a.x = 7.0
|
||
|
a.y = 8.0
|
||
|
assert a.x == 7
|
||
|
assert a.y == 8
|
||
|
|
||
|
class D(T):
|
||
|
xx: float
|
||
|
|
||
|
@property
|
||
|
def x(self) -> float:
|
||
|
return self.xx
|
||
|
|
||
|
@property
|
||
|
def y(self) -> float:
|
||
|
raise TypeError
|
||
|
|
||
|
def test_read_only_property_in_trait_implemented_as_property() -> None:
|
||
|
d = D()
|
||
|
d.xx = 5.0
|
||
|
assert d.x == 5
|
||
|
d.xx = MAGIC
|
||
|
assert d.x == MAGIC
|
||
|
with assertRaises(TypeError):
|
||
|
d.y
|
||
|
t: T = d
|
||
|
assert t.x == MAGIC
|
||
|
d.xx = 6.0
|
||
|
assert t.x == 6
|
||
|
with assertRaises(TypeError):
|
||
|
t.y
|
||
|
|
||
|
@trait
|
||
|
class T2:
|
||
|
x: float
|
||
|
y: float
|
||
|
|
||
|
class C2(T2):
|
||
|
pass
|
||
|
|
||
|
def test_inherit_trait_attribute() -> None:
|
||
|
c = C2()
|
||
|
c.x = 5.0
|
||
|
assert c.x == 5
|
||
|
c.x = MAGIC
|
||
|
assert c.x == MAGIC
|
||
|
with assertRaises(AttributeError):
|
||
|
c.y
|
||
|
c.y = 6.0
|
||
|
assert c.y == 6.0
|
||
|
t: T2 = C2()
|
||
|
with assertRaises(AttributeError):
|
||
|
t.y
|
||
|
t = c
|
||
|
assert t.x == MAGIC
|
||
|
c.x = 55.0
|
||
|
assert t.x == 55
|
||
|
assert t.y == 6
|
||
|
a: Any = c
|
||
|
assert a.x == 55
|
||
|
assert a.y == 6
|
||
|
a.x = 7.0
|
||
|
a.y = 8.0
|
||
|
assert a.x == 7
|
||
|
assert a.y == 8
|
||
|
|
||
|
class D2(T2):
|
||
|
x: float
|
||
|
y: float = 4
|
||
|
|
||
|
def test_implement_trait_attribute() -> None:
|
||
|
d = D2()
|
||
|
d.x = 5.0
|
||
|
assert d.x == 5
|
||
|
d.x = MAGIC
|
||
|
assert d.x == MAGIC
|
||
|
assert d.y == 4
|
||
|
d.y = 6.0
|
||
|
assert d.y == 6
|
||
|
t: T2 = D2()
|
||
|
assert t.y == 4
|
||
|
t = d
|
||
|
assert t.x == MAGIC
|
||
|
d.x = 55.0
|
||
|
assert t.x == 55
|
||
|
assert t.y == 6
|
||
|
a: Any = d
|
||
|
assert a.x == 55
|
||
|
assert a.y == 6
|
||
|
a.x = 7.0
|
||
|
a.y = 8.0
|
||
|
assert a.x == 7
|
||
|
assert a.y == 8
|