]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.12] gh-111495: Add tests for PyFloat C API (GH-111624) (GH-111752)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Sun, 5 Nov 2023 08:01:31 +0000 (09:01 +0100)
committerGitHub <noreply@github.com>
Sun, 5 Nov 2023 08:01:31 +0000 (10:01 +0200)
(cherry picked from commit b452202a11c4cb60f69a098a0076a8a8aabade38)

Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com>
Lib/test/test_capi/test_float.py [new file with mode: 0644]
Modules/_testcapi/float.c

diff --git a/Lib/test/test_capi/test_float.py b/Lib/test/test_capi/test_float.py
new file mode 100644 (file)
index 0000000..95635e8
--- /dev/null
@@ -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()
index 33cbda83a81af7cac0478f8f1b779c7bcb0e47bc..0c26eb9b058c5d8de618c695cd78649eddf1c0fa 100644 (file)
@@ -1,9 +1,75 @@
 #define PY_SSIZE_T_CLEAN
 
 #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]*/
@@ -98,6 +164,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},