summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSergey B Kirpichev <skirpichev@gmail.com>2023-11-05 07:20:12 (GMT)
committerGitHub <noreply@github.com>2023-11-05 07:20:12 (GMT)
commitb452202a11c4cb60f69a098a0076a8a8aabade38 (patch)
tree9e796b98fb8a3d69814bb78983634b91154d9edb
parent72e27a67b97993f277e69c9dafb063007ba79adf (diff)
downloadcpython-b452202a11c4cb60f69a098a0076a8a8aabade38.zip
cpython-b452202a11c4cb60f69a098a0076a8a8aabade38.tar.gz
cpython-b452202a11c4cb60f69a098a0076a8a8aabade38.tar.bz2
gh-111495: Add tests for PyFloat C API (GH-111624)
-rw-r--r--Lib/test/test_capi/test_float.py117
-rw-r--r--Modules/_testcapi/float.c74
2 files changed, 191 insertions, 0 deletions
diff --git a/Lib/test/test_capi/test_float.py b/Lib/test/test_capi/test_float.py
new file mode 100644
index 0000000..95635e8
--- /dev/null
+++ b/Lib/test/test_capi/test_float.py
@@ -0,0 +1,117 @@
+import math
+import sys
+import unittest
+import warnings
+
+from test.test_capi.test_getargs import (Float, FloatSubclass, FloatSubclass2,
+ BadIndex2, BadFloat2, Index, BadIndex,
+ BadFloat)
+from test.support import import_helper
+
+_testcapi = import_helper.import_module('_testcapi')
+
+NULL = None
+
+
+class CAPIFloatTest(unittest.TestCase):
+ def test_check(self):
+ # Test PyFloat_Check()
+ check = _testcapi.float_check
+
+ self.assertTrue(check(4.25))
+ self.assertTrue(check(FloatSubclass(4.25)))
+ self.assertFalse(check(Float()))
+ self.assertFalse(check(3))
+ self.assertFalse(check(object()))
+
+ # CRASHES check(NULL)
+
+ def test_checkexact(self):
+ # Test PyFloat_CheckExact()
+ checkexact = _testcapi.float_checkexact
+
+ self.assertTrue(checkexact(4.25))
+ self.assertFalse(checkexact(FloatSubclass(4.25)))
+ self.assertFalse(checkexact(Float()))
+ self.assertFalse(checkexact(3))
+ self.assertFalse(checkexact(object()))
+
+ # CRASHES checkexact(NULL)
+
+ def test_fromstring(self):
+ # Test PyFloat_FromString()
+ fromstring = _testcapi.float_fromstring
+
+ self.assertEqual(fromstring("4.25"), 4.25)
+ self.assertEqual(fromstring(b"4.25"), 4.25)
+ self.assertRaises(ValueError, fromstring, "4.25\0")
+ self.assertRaises(ValueError, fromstring, b"4.25\0")
+
+ self.assertEqual(fromstring(bytearray(b"4.25")), 4.25)
+
+ self.assertEqual(fromstring(memoryview(b"4.25")), 4.25)
+ self.assertEqual(fromstring(memoryview(b"4.255")[:-1]), 4.25)
+ self.assertRaises(TypeError, fromstring, memoryview(b"4.25")[::2])
+
+ self.assertRaises(TypeError, fromstring, 4.25)
+
+ # CRASHES fromstring(NULL)
+
+ def test_fromdouble(self):
+ # Test PyFloat_FromDouble()
+ fromdouble = _testcapi.float_fromdouble
+
+ self.assertEqual(fromdouble(4.25), 4.25)
+
+ def test_asdouble(self):
+ # Test PyFloat_AsDouble()
+ asdouble = _testcapi.float_asdouble
+
+ class BadFloat3:
+ def __float__(self):
+ raise RuntimeError
+
+ self.assertEqual(asdouble(4.25), 4.25)
+ self.assertEqual(asdouble(-1.0), -1.0)
+ self.assertEqual(asdouble(42), 42.0)
+ self.assertEqual(asdouble(-1), -1.0)
+ self.assertEqual(asdouble(2**1000), float(2**1000))
+
+ self.assertEqual(asdouble(FloatSubclass(4.25)), 4.25)
+ self.assertEqual(asdouble(FloatSubclass2(4.25)), 4.25)
+ self.assertEqual(asdouble(Index()), 99.)
+
+ self.assertRaises(TypeError, asdouble, BadIndex())
+ self.assertRaises(TypeError, asdouble, BadFloat())
+ self.assertRaises(RuntimeError, asdouble, BadFloat3())
+ with self.assertWarns(DeprecationWarning):
+ self.assertEqual(asdouble(BadIndex2()), 1.)
+ with self.assertWarns(DeprecationWarning):
+ self.assertEqual(asdouble(BadFloat2()), 4.25)
+ with warnings.catch_warnings():
+ warnings.simplefilter("error", DeprecationWarning)
+ self.assertRaises(DeprecationWarning, asdouble, BadFloat2())
+ self.assertRaises(TypeError, asdouble, object())
+ self.assertRaises(TypeError, asdouble, NULL)
+
+ def test_getinfo(self):
+ # Test PyFloat_GetInfo()
+ getinfo = _testcapi.float_getinfo
+
+ self.assertEqual(getinfo(), sys.float_info)
+
+ def test_getmax(self):
+ # Test PyFloat_GetMax()
+ getmax = _testcapi.float_getmax
+
+ self.assertEqual(getmax(), sys.float_info.max)
+
+ def test_getmin(self):
+ # Test PyFloat_GetMax()
+ getmin = _testcapi.float_getmin
+
+ self.assertEqual(getmin(), sys.float_info.min)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/Modules/_testcapi/float.c b/Modules/_testcapi/float.c
index 2a7d979..4fcbaf3 100644
--- a/Modules/_testcapi/float.c
+++ b/Modules/_testcapi/float.c
@@ -2,9 +2,75 @@
#define PYTESTCAPI_NEED_INTERNAL_API
#include "parts.h"
+#include "util.h"
#include "clinic/float.c.h"
+static PyObject *
+float_check(PyObject *Py_UNUSED(module), PyObject *obj)
+{
+ NULLABLE(obj);
+ return PyLong_FromLong(PyFloat_Check(obj));
+}
+
+static PyObject *
+float_checkexact(PyObject *Py_UNUSED(module), PyObject *obj)
+{
+ NULLABLE(obj);
+ return PyLong_FromLong(PyFloat_CheckExact(obj));
+}
+
+static PyObject *
+float_fromstring(PyObject *Py_UNUSED(module), PyObject *obj)
+{
+ NULLABLE(obj);
+ return PyFloat_FromString(obj);
+}
+
+static PyObject *
+float_fromdouble(PyObject *Py_UNUSED(module), PyObject *obj)
+{
+ double d;
+
+ if (!PyArg_Parse(obj, "d", &d)) {
+ return NULL;
+ }
+
+ return PyFloat_FromDouble(d);
+}
+
+static PyObject *
+float_asdouble(PyObject *Py_UNUSED(module), PyObject *obj)
+{
+ double d;
+
+ NULLABLE(obj);
+ d = PyFloat_AsDouble(obj);
+ if (d == -1. && PyErr_Occurred()) {
+ return NULL;
+ }
+
+ return PyFloat_FromDouble(d);
+}
+
+static PyObject *
+float_getinfo(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(arg))
+{
+ return PyFloat_GetInfo();
+}
+
+static PyObject *
+float_getmax(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(arg))
+{
+ return PyFloat_FromDouble(PyFloat_GetMax());
+}
+
+static PyObject *
+float_getmin(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(arg))
+{
+ return PyFloat_FromDouble(PyFloat_GetMin());
+}
+
/*[clinic input]
module _testcapi
[clinic start generated code]*/
@@ -99,6 +165,14 @@ _testcapi_float_unpack_impl(PyObject *module, const char *data,
}
static PyMethodDef test_methods[] = {
+ {"float_check", float_check, METH_O},
+ {"float_checkexact", float_checkexact, METH_O},
+ {"float_fromstring", float_fromstring, METH_O},
+ {"float_fromdouble", float_fromdouble, METH_O},
+ {"float_asdouble", float_asdouble, METH_O},
+ {"float_getinfo", float_getinfo, METH_NOARGS},
+ {"float_getmax", float_getmax, METH_NOARGS},
+ {"float_getmin", float_getmin, METH_NOARGS},
_TESTCAPI_FLOAT_PACK_METHODDEF
_TESTCAPI_FLOAT_UNPACK_METHODDEF
{NULL},