Skip to content

Commit 7795860

Browse files
skirpichevGlyphack
authored andcommitted
pythongh-111495: Add tests for PyFloat C API (pythonGH-111624)
1 parent a9f2ec7 commit 7795860

File tree

2 files changed

+191
-0
lines changed

2 files changed

+191
-0
lines changed

Lib/test/test_capi/test_float.py

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import math
2+
import sys
3+
import unittest
4+
import warnings
5+
6+
from test.test_capi.test_getargs import (Float, FloatSubclass, FloatSubclass2,
7+
BadIndex2, BadFloat2, Index, BadIndex,
8+
BadFloat)
9+
from test.support import import_helper
10+
11+
_testcapi = import_helper.import_module('_testcapi')
12+
13+
NULL = None
14+
15+
16+
class CAPIFloatTest(unittest.TestCase):
17+
def test_check(self):
18+
# Test PyFloat_Check()
19+
check = _testcapi.float_check
20+
21+
self.assertTrue(check(4.25))
22+
self.assertTrue(check(FloatSubclass(4.25)))
23+
self.assertFalse(check(Float()))
24+
self.assertFalse(check(3))
25+
self.assertFalse(check(object()))
26+
27+
# CRASHES check(NULL)
28+
29+
def test_checkexact(self):
30+
# Test PyFloat_CheckExact()
31+
checkexact = _testcapi.float_checkexact
32+
33+
self.assertTrue(checkexact(4.25))
34+
self.assertFalse(checkexact(FloatSubclass(4.25)))
35+
self.assertFalse(checkexact(Float()))
36+
self.assertFalse(checkexact(3))
37+
self.assertFalse(checkexact(object()))
38+
39+
# CRASHES checkexact(NULL)
40+
41+
def test_fromstring(self):
42+
# Test PyFloat_FromString()
43+
fromstring = _testcapi.float_fromstring
44+
45+
self.assertEqual(fromstring("4.25"), 4.25)
46+
self.assertEqual(fromstring(b"4.25"), 4.25)
47+
self.assertRaises(ValueError, fromstring, "4.25\0")
48+
self.assertRaises(ValueError, fromstring, b"4.25\0")
49+
50+
self.assertEqual(fromstring(bytearray(b"4.25")), 4.25)
51+
52+
self.assertEqual(fromstring(memoryview(b"4.25")), 4.25)
53+
self.assertEqual(fromstring(memoryview(b"4.255")[:-1]), 4.25)
54+
self.assertRaises(TypeError, fromstring, memoryview(b"4.25")[::2])
55+
56+
self.assertRaises(TypeError, fromstring, 4.25)
57+
58+
# CRASHES fromstring(NULL)
59+
60+
def test_fromdouble(self):
61+
# Test PyFloat_FromDouble()
62+
fromdouble = _testcapi.float_fromdouble
63+
64+
self.assertEqual(fromdouble(4.25), 4.25)
65+
66+
def test_asdouble(self):
67+
# Test PyFloat_AsDouble()
68+
asdouble = _testcapi.float_asdouble
69+
70+
class BadFloat3:
71+
def __float__(self):
72+
raise RuntimeError
73+
74+
self.assertEqual(asdouble(4.25), 4.25)
75+
self.assertEqual(asdouble(-1.0), -1.0)
76+
self.assertEqual(asdouble(42), 42.0)
77+
self.assertEqual(asdouble(-1), -1.0)
78+
self.assertEqual(asdouble(2**1000), float(2**1000))
79+
80+
self.assertEqual(asdouble(FloatSubclass(4.25)), 4.25)
81+
self.assertEqual(asdouble(FloatSubclass2(4.25)), 4.25)
82+
self.assertEqual(asdouble(Index()), 99.)
83+
84+
self.assertRaises(TypeError, asdouble, BadIndex())
85+
self.assertRaises(TypeError, asdouble, BadFloat())
86+
self.assertRaises(RuntimeError, asdouble, BadFloat3())
87+
with self.assertWarns(DeprecationWarning):
88+
self.assertEqual(asdouble(BadIndex2()), 1.)
89+
with self.assertWarns(DeprecationWarning):
90+
self.assertEqual(asdouble(BadFloat2()), 4.25)
91+
with warnings.catch_warnings():
92+
warnings.simplefilter("error", DeprecationWarning)
93+
self.assertRaises(DeprecationWarning, asdouble, BadFloat2())
94+
self.assertRaises(TypeError, asdouble, object())
95+
self.assertRaises(TypeError, asdouble, NULL)
96+
97+
def test_getinfo(self):
98+
# Test PyFloat_GetInfo()
99+
getinfo = _testcapi.float_getinfo
100+
101+
self.assertEqual(getinfo(), sys.float_info)
102+
103+
def test_getmax(self):
104+
# Test PyFloat_GetMax()
105+
getmax = _testcapi.float_getmax
106+
107+
self.assertEqual(getmax(), sys.float_info.max)
108+
109+
def test_getmin(self):
110+
# Test PyFloat_GetMax()
111+
getmin = _testcapi.float_getmin
112+
113+
self.assertEqual(getmin(), sys.float_info.min)
114+
115+
116+
if __name__ == "__main__":
117+
unittest.main()

Modules/_testcapi/float.c

+74
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,75 @@
22
#define PYTESTCAPI_NEED_INTERNAL_API
33

44
#include "parts.h"
5+
#include "util.h"
56
#include "clinic/float.c.h"
67

78

9+
static PyObject *
10+
float_check(PyObject *Py_UNUSED(module), PyObject *obj)
11+
{
12+
NULLABLE(obj);
13+
return PyLong_FromLong(PyFloat_Check(obj));
14+
}
15+
16+
static PyObject *
17+
float_checkexact(PyObject *Py_UNUSED(module), PyObject *obj)
18+
{
19+
NULLABLE(obj);
20+
return PyLong_FromLong(PyFloat_CheckExact(obj));
21+
}
22+
23+
static PyObject *
24+
float_fromstring(PyObject *Py_UNUSED(module), PyObject *obj)
25+
{
26+
NULLABLE(obj);
27+
return PyFloat_FromString(obj);
28+
}
29+
30+
static PyObject *
31+
float_fromdouble(PyObject *Py_UNUSED(module), PyObject *obj)
32+
{
33+
double d;
34+
35+
if (!PyArg_Parse(obj, "d", &d)) {
36+
return NULL;
37+
}
38+
39+
return PyFloat_FromDouble(d);
40+
}
41+
42+
static PyObject *
43+
float_asdouble(PyObject *Py_UNUSED(module), PyObject *obj)
44+
{
45+
double d;
46+
47+
NULLABLE(obj);
48+
d = PyFloat_AsDouble(obj);
49+
if (d == -1. && PyErr_Occurred()) {
50+
return NULL;
51+
}
52+
53+
return PyFloat_FromDouble(d);
54+
}
55+
56+
static PyObject *
57+
float_getinfo(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(arg))
58+
{
59+
return PyFloat_GetInfo();
60+
}
61+
62+
static PyObject *
63+
float_getmax(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(arg))
64+
{
65+
return PyFloat_FromDouble(PyFloat_GetMax());
66+
}
67+
68+
static PyObject *
69+
float_getmin(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(arg))
70+
{
71+
return PyFloat_FromDouble(PyFloat_GetMin());
72+
}
73+
874
/*[clinic input]
975
module _testcapi
1076
[clinic start generated code]*/
@@ -99,6 +165,14 @@ _testcapi_float_unpack_impl(PyObject *module, const char *data,
99165
}
100166

101167
static PyMethodDef test_methods[] = {
168+
{"float_check", float_check, METH_O},
169+
{"float_checkexact", float_checkexact, METH_O},
170+
{"float_fromstring", float_fromstring, METH_O},
171+
{"float_fromdouble", float_fromdouble, METH_O},
172+
{"float_asdouble", float_asdouble, METH_O},
173+
{"float_getinfo", float_getinfo, METH_NOARGS},
174+
{"float_getmax", float_getmax, METH_NOARGS},
175+
{"float_getmin", float_getmin, METH_NOARGS},
102176
_TESTCAPI_FLOAT_PACK_METHODDEF
103177
_TESTCAPI_FLOAT_UNPACK_METHODDEF
104178
{NULL},

0 commit comments

Comments
 (0)