mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 03:44:55 +00:00 
			
		
		
		
	Issue #26995: Added tests for "f", "d", "D", "S", "Y", and "U" format codes
in PyArg_ParseTuple().
This commit is contained in:
		
						commit
						c944c2dab8
					
				
					 2 changed files with 222 additions and 1 deletions
				
			
		| 
						 | 
				
			
			@ -1,4 +1,6 @@
 | 
			
		|||
import unittest
 | 
			
		||||
import math
 | 
			
		||||
import sys
 | 
			
		||||
from test import support
 | 
			
		||||
# Skip this test if the _testcapi module isn't available.
 | 
			
		||||
support.import_module('_testcapi')
 | 
			
		||||
| 
						 | 
				
			
			@ -43,7 +45,11 @@ VERY_LARGE = 0xFF0000121212121212121242
 | 
			
		|||
 | 
			
		||||
from _testcapi import UCHAR_MAX, USHRT_MAX, UINT_MAX, ULONG_MAX, INT_MAX, \
 | 
			
		||||
     INT_MIN, LONG_MIN, LONG_MAX, PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, \
 | 
			
		||||
     SHRT_MIN, SHRT_MAX
 | 
			
		||||
     SHRT_MIN, SHRT_MAX, FLT_MIN, FLT_MAX, DBL_MIN, DBL_MAX
 | 
			
		||||
 | 
			
		||||
DBL_MAX_EXP = sys.float_info.max_exp
 | 
			
		||||
INF = float('inf')
 | 
			
		||||
NAN = float('nan')
 | 
			
		||||
 | 
			
		||||
# fake, they are not defined in Python's header files
 | 
			
		||||
LLONG_MAX = 2**63-1
 | 
			
		||||
| 
						 | 
				
			
			@ -70,6 +76,55 @@ class BadInt3(int):
 | 
			
		|||
    def __int__(self):
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Float:
 | 
			
		||||
    def __float__(self):
 | 
			
		||||
        return 4.25
 | 
			
		||||
 | 
			
		||||
class FloatSubclass(float):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
class FloatSubclass2(float):
 | 
			
		||||
    def __float__(self):
 | 
			
		||||
        return 4.25
 | 
			
		||||
 | 
			
		||||
class BadFloat:
 | 
			
		||||
    def __float__(self):
 | 
			
		||||
        return 687
 | 
			
		||||
 | 
			
		||||
class BadFloat2:
 | 
			
		||||
    def __float__(self):
 | 
			
		||||
        return FloatSubclass(4.25)
 | 
			
		||||
 | 
			
		||||
class BadFloat3(float):
 | 
			
		||||
    def __float__(self):
 | 
			
		||||
        return FloatSubclass(4.25)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Complex:
 | 
			
		||||
    def __complex__(self):
 | 
			
		||||
        return 4.25+0.5j
 | 
			
		||||
 | 
			
		||||
class ComplexSubclass(complex):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
class ComplexSubclass2(complex):
 | 
			
		||||
    def __complex__(self):
 | 
			
		||||
        return 4.25+0.5j
 | 
			
		||||
 | 
			
		||||
class BadComplex:
 | 
			
		||||
    def __complex__(self):
 | 
			
		||||
        return 1.25
 | 
			
		||||
 | 
			
		||||
class BadComplex2:
 | 
			
		||||
    def __complex__(self):
 | 
			
		||||
        return ComplexSubclass(4.25+0.5j)
 | 
			
		||||
 | 
			
		||||
class BadComplex3(complex):
 | 
			
		||||
    def __complex__(self):
 | 
			
		||||
        return ComplexSubclass(4.25+0.5j)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TupleSubclass(tuple):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -295,6 +350,81 @@ class LongLong_TestCase(unittest.TestCase):
 | 
			
		|||
 | 
			
		||||
        self.assertEqual(VERY_LARGE & ULLONG_MAX, getargs_K(VERY_LARGE))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Float_TestCase(unittest.TestCase):
 | 
			
		||||
    def assertEqualWithSign(self, actual, expected):
 | 
			
		||||
        self.assertEqual(actual, expected)
 | 
			
		||||
        self.assertEqual(math.copysign(1, actual), math.copysign(1, expected))
 | 
			
		||||
 | 
			
		||||
    def test_f(self):
 | 
			
		||||
        from _testcapi import getargs_f
 | 
			
		||||
        self.assertEqual(getargs_f(4.25), 4.25)
 | 
			
		||||
        self.assertEqual(getargs_f(4), 4.0)
 | 
			
		||||
        self.assertRaises(TypeError, getargs_f, 4.25+0j)
 | 
			
		||||
        self.assertEqual(getargs_f(Float()), 4.25)
 | 
			
		||||
        self.assertEqual(getargs_f(FloatSubclass(7.5)), 7.5)
 | 
			
		||||
        self.assertEqual(getargs_f(FloatSubclass2(7.5)), 7.5)
 | 
			
		||||
        self.assertRaises(TypeError, getargs_f, BadFloat())
 | 
			
		||||
        self.assertEqual(getargs_f(BadFloat2()), 4.25)
 | 
			
		||||
        self.assertEqual(getargs_f(BadFloat3(7.5)), 7.5)
 | 
			
		||||
 | 
			
		||||
        for x in (FLT_MIN, -FLT_MIN, FLT_MAX, -FLT_MAX, INF, -INF):
 | 
			
		||||
            self.assertEqual(getargs_f(x), x)
 | 
			
		||||
        if FLT_MAX < DBL_MAX:
 | 
			
		||||
            self.assertEqual(getargs_f(DBL_MAX), INF)
 | 
			
		||||
            self.assertEqual(getargs_f(-DBL_MAX), -INF)
 | 
			
		||||
        if FLT_MIN > DBL_MIN:
 | 
			
		||||
            self.assertEqualWithSign(getargs_f(DBL_MIN), 0.0)
 | 
			
		||||
            self.assertEqualWithSign(getargs_f(-DBL_MIN), -0.0)
 | 
			
		||||
        self.assertEqualWithSign(getargs_f(0.0), 0.0)
 | 
			
		||||
        self.assertEqualWithSign(getargs_f(-0.0), -0.0)
 | 
			
		||||
        r = getargs_f(NAN)
 | 
			
		||||
        self.assertNotEqual(r, r)
 | 
			
		||||
 | 
			
		||||
    def test_d(self):
 | 
			
		||||
        from _testcapi import getargs_d
 | 
			
		||||
        self.assertEqual(getargs_d(4.25), 4.25)
 | 
			
		||||
        self.assertEqual(getargs_d(4), 4.0)
 | 
			
		||||
        self.assertRaises(TypeError, getargs_d, 4.25+0j)
 | 
			
		||||
        self.assertEqual(getargs_d(Float()), 4.25)
 | 
			
		||||
        self.assertEqual(getargs_d(FloatSubclass(7.5)), 7.5)
 | 
			
		||||
        self.assertEqual(getargs_d(FloatSubclass2(7.5)), 7.5)
 | 
			
		||||
        self.assertRaises(TypeError, getargs_d, BadFloat())
 | 
			
		||||
        self.assertEqual(getargs_d(BadFloat2()), 4.25)
 | 
			
		||||
        self.assertEqual(getargs_d(BadFloat3(7.5)), 7.5)
 | 
			
		||||
 | 
			
		||||
        for x in (DBL_MIN, -DBL_MIN, DBL_MAX, -DBL_MAX, INF, -INF):
 | 
			
		||||
            self.assertEqual(getargs_d(x), x)
 | 
			
		||||
        self.assertRaises(OverflowError, getargs_d, 1<<DBL_MAX_EXP)
 | 
			
		||||
        self.assertRaises(OverflowError, getargs_d, -1<<DBL_MAX_EXP)
 | 
			
		||||
        self.assertEqualWithSign(getargs_d(0.0), 0.0)
 | 
			
		||||
        self.assertEqualWithSign(getargs_d(-0.0), -0.0)
 | 
			
		||||
        r = getargs_d(NAN)
 | 
			
		||||
        self.assertNotEqual(r, r)
 | 
			
		||||
 | 
			
		||||
    def test_D(self):
 | 
			
		||||
        from _testcapi import getargs_D
 | 
			
		||||
        self.assertEqual(getargs_D(4.25+0.5j), 4.25+0.5j)
 | 
			
		||||
        self.assertEqual(getargs_D(4.25), 4.25+0j)
 | 
			
		||||
        self.assertEqual(getargs_D(4), 4.0+0j)
 | 
			
		||||
        self.assertEqual(getargs_D(Complex()), 4.25+0.5j)
 | 
			
		||||
        self.assertEqual(getargs_D(ComplexSubclass(7.5+0.25j)), 7.5+0.25j)
 | 
			
		||||
        self.assertEqual(getargs_D(ComplexSubclass2(7.5+0.25j)), 7.5+0.25j)
 | 
			
		||||
        self.assertRaises(TypeError, getargs_D, BadComplex())
 | 
			
		||||
        self.assertEqual(getargs_D(BadComplex2()), 4.25+0.5j)
 | 
			
		||||
        self.assertEqual(getargs_D(BadComplex3(7.5+0.25j)), 7.5+0.25j)
 | 
			
		||||
 | 
			
		||||
        for x in (DBL_MIN, -DBL_MIN, DBL_MAX, -DBL_MAX, INF, -INF):
 | 
			
		||||
            c = complex(x, 1.0)
 | 
			
		||||
            self.assertEqual(getargs_D(c), c)
 | 
			
		||||
            c = complex(1.0, x)
 | 
			
		||||
            self.assertEqual(getargs_D(c), c)
 | 
			
		||||
        self.assertEqualWithSign(getargs_D(complex(0.0, 1.0)).real, 0.0)
 | 
			
		||||
        self.assertEqualWithSign(getargs_D(complex(-0.0, 1.0)).real, -0.0)
 | 
			
		||||
        self.assertEqualWithSign(getargs_D(complex(1.0, 0.0)).imag, 0.0)
 | 
			
		||||
        self.assertEqualWithSign(getargs_D(complex(1.0, -0.0)).imag, -0.0)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Paradox:
 | 
			
		||||
    "This statement is false."
 | 
			
		||||
    def __bool__(self):
 | 
			
		||||
| 
						 | 
				
			
			@ -760,5 +890,33 @@ class String_TestCase(unittest.TestCase):
 | 
			
		|||
        self.assertIsNone(getargs_Z_hash(None))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Object_TestCase(unittest.TestCase):
 | 
			
		||||
    def test_S(self):
 | 
			
		||||
        from _testcapi import getargs_S
 | 
			
		||||
        obj = b'bytes'
 | 
			
		||||
        self.assertIs(getargs_S(obj), obj)
 | 
			
		||||
        self.assertRaises(TypeError, getargs_S, bytearray(b'bytearray'))
 | 
			
		||||
        self.assertRaises(TypeError, getargs_S, 'str')
 | 
			
		||||
        self.assertRaises(TypeError, getargs_S, None)
 | 
			
		||||
        self.assertRaises(TypeError, getargs_S, memoryview(obj))
 | 
			
		||||
 | 
			
		||||
    def test_Y(self):
 | 
			
		||||
        from _testcapi import getargs_Y
 | 
			
		||||
        obj = bytearray(b'bytearray')
 | 
			
		||||
        self.assertIs(getargs_Y(obj), obj)
 | 
			
		||||
        self.assertRaises(TypeError, getargs_Y, b'bytes')
 | 
			
		||||
        self.assertRaises(TypeError, getargs_Y, 'str')
 | 
			
		||||
        self.assertRaises(TypeError, getargs_Y, None)
 | 
			
		||||
        self.assertRaises(TypeError, getargs_Y, memoryview(obj))
 | 
			
		||||
 | 
			
		||||
    def test_U(self):
 | 
			
		||||
        from _testcapi import getargs_U
 | 
			
		||||
        obj = 'str'
 | 
			
		||||
        self.assertIs(getargs_U(obj), obj)
 | 
			
		||||
        self.assertRaises(TypeError, getargs_U, b'bytes')
 | 
			
		||||
        self.assertRaises(TypeError, getargs_U, bytearray(b'bytearray'))
 | 
			
		||||
        self.assertRaises(TypeError, getargs_U, None)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    unittest.main()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1102,6 +1102,63 @@ test_k_code(PyObject *self)
 | 
			
		|||
    return Py_None;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static PyObject *
 | 
			
		||||
getargs_f(PyObject *self, PyObject *args)
 | 
			
		||||
{
 | 
			
		||||
    float f;
 | 
			
		||||
    if (!PyArg_ParseTuple(args, "f", &f))
 | 
			
		||||
        return NULL;
 | 
			
		||||
    return PyFloat_FromDouble(f);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static PyObject *
 | 
			
		||||
getargs_d(PyObject *self, PyObject *args)
 | 
			
		||||
{
 | 
			
		||||
    double d;
 | 
			
		||||
    if (!PyArg_ParseTuple(args, "d", &d))
 | 
			
		||||
        return NULL;
 | 
			
		||||
    return PyFloat_FromDouble(d);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static PyObject *
 | 
			
		||||
getargs_D(PyObject *self, PyObject *args)
 | 
			
		||||
{
 | 
			
		||||
    Py_complex cval;
 | 
			
		||||
    if (!PyArg_ParseTuple(args, "D", &cval))
 | 
			
		||||
        return NULL;
 | 
			
		||||
    return PyComplex_FromCComplex(cval);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static PyObject *
 | 
			
		||||
getargs_S(PyObject *self, PyObject *args)
 | 
			
		||||
{
 | 
			
		||||
    PyObject *obj;
 | 
			
		||||
    if (!PyArg_ParseTuple(args, "S", &obj))
 | 
			
		||||
        return NULL;
 | 
			
		||||
    Py_INCREF(obj);
 | 
			
		||||
    return obj;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static PyObject *
 | 
			
		||||
getargs_Y(PyObject *self, PyObject *args)
 | 
			
		||||
{
 | 
			
		||||
    PyObject *obj;
 | 
			
		||||
    if (!PyArg_ParseTuple(args, "Y", &obj))
 | 
			
		||||
        return NULL;
 | 
			
		||||
    Py_INCREF(obj);
 | 
			
		||||
    return obj;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static PyObject *
 | 
			
		||||
getargs_U(PyObject *self, PyObject *args)
 | 
			
		||||
{
 | 
			
		||||
    PyObject *obj;
 | 
			
		||||
    if (!PyArg_ParseTuple(args, "U", &obj))
 | 
			
		||||
        return NULL;
 | 
			
		||||
    Py_INCREF(obj);
 | 
			
		||||
    return obj;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static PyObject *
 | 
			
		||||
getargs_c(PyObject *self, PyObject *args)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -3829,6 +3886,12 @@ static PyMethodDef TestMethods[] = {
 | 
			
		|||
        (PyCFunction)test_long_long_and_overflow, METH_NOARGS},
 | 
			
		||||
    {"test_L_code",             (PyCFunction)test_L_code,        METH_NOARGS},
 | 
			
		||||
#endif
 | 
			
		||||
    {"getargs_f",               getargs_f,                       METH_VARARGS},
 | 
			
		||||
    {"getargs_d",               getargs_d,                       METH_VARARGS},
 | 
			
		||||
    {"getargs_D",               getargs_D,                       METH_VARARGS},
 | 
			
		||||
    {"getargs_S",               getargs_S,                       METH_VARARGS},
 | 
			
		||||
    {"getargs_Y",               getargs_Y,                       METH_VARARGS},
 | 
			
		||||
    {"getargs_U",               getargs_U,                       METH_VARARGS},
 | 
			
		||||
    {"getargs_c",               getargs_c,                       METH_VARARGS},
 | 
			
		||||
    {"getargs_C",               getargs_C,                       METH_VARARGS},
 | 
			
		||||
    {"getargs_s",               getargs_s,                       METH_VARARGS},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue