this repo has no description
at trunk 389 lines 13 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include <cfloat> 3#include <cmath> 4#include <cstring> 5 6#include "Python.h" 7#include "gtest/gtest.h" 8 9#include "capi-fixture.h" 10#include "capi-testing.h" 11 12namespace py { 13namespace testing { 14 15using FloatExtensionApiTest = ExtensionApi; 16 17TEST_F(FloatExtensionApiTest, PyFloatFromStringWithUnicodeReturnsFloat) { 18 const char* str = "15.5"; 19 PyObjectPtr pyunicode(PyUnicode_FromString(str)); 20 PyObjectPtr flt(PyFloat_FromString(pyunicode)); 21 ASSERT_EQ(PyErr_Occurred(), nullptr); 22 ASSERT_TRUE(PyFloat_CheckExact(flt)); 23 EXPECT_EQ(PyFloat_AsDouble(flt), 15.5); 24} 25 26TEST_F(FloatExtensionApiTest, PyFloatFromStringWithBytesReturnsFloat) { 27 const char* str = "25.5"; 28 PyObjectPtr pybytes(PyBytes_FromString(str)); 29 PyObjectPtr flt(PyFloat_FromString(pybytes)); 30 ASSERT_EQ(PyErr_Occurred(), nullptr); 31 ASSERT_TRUE(PyFloat_CheckExact(flt)); 32 EXPECT_EQ(PyFloat_AsDouble(flt), 25.5); 33} 34 35TEST_F(FloatExtensionApiTest, PyFloatFromStringWithMemoryViewReturnsFloat) { 36 const char* str = "5.5"; 37 PyObjectPtr memory_view( 38 PyMemoryView_FromMemory(const_cast<char*>(str), 3, PyBUF_READ)); 39 PyObjectPtr flt(PyFloat_FromString(memory_view)); 40 ASSERT_EQ(PyErr_Occurred(), nullptr); 41 ASSERT_TRUE(PyFloat_CheckExact(flt)); 42 EXPECT_EQ(PyFloat_AsDouble(flt), 5.5); 43} 44 45// TODO(T57022841): Needs PyFloatFromStringWithByteArrayReturnsFloat 46// when bytearray support is added to float() 47 48TEST_F(FloatExtensionApiTest, PyFloatFromStringWithUserBufferReturnsFloat) { 49 static char contents[] = "45.5"; 50 static Py_ssize_t contents_len = std::strlen(contents); 51 getbufferproc mocked_getbuffer_func = [](PyObject* obj, Py_buffer* view, 52 int flags) { 53 return PyBuffer_FillInfo(view, obj, contents, contents_len, /*readonly=*/1, 54 flags); 55 }; 56 releasebufferproc mocked_releasebuffer_func = [](PyObject*, Py_buffer* view) { 57 view->buf = nullptr; 58 view->obj = nullptr; 59 }; 60 PyType_Slot slots[] = { 61 {Py_bf_getbuffer, reinterpret_cast<void*>(mocked_getbuffer_func)}, 62 {Py_bf_releasebuffer, reinterpret_cast<void*>(mocked_releasebuffer_func)}, 63 {0, nullptr}, 64 }; 65 static PyType_Spec spec; 66 spec = { 67 "foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT, slots, 68 }; 69 PyObjectPtr buf_type(PyType_FromSpec(&spec)); 70 ASSERT_NE(buf_type, nullptr); 71 ASSERT_TRUE(PyType_CheckExact(buf_type)); 72 73 PyObjectPtr instance(PyObject_CallFunction(buf_type, nullptr)); 74 ASSERT_TRUE(PyObject_CheckBuffer(instance.get())); 75 76 PyObjectPtr flt(PyFloat_FromString(instance)); 77 ASSERT_EQ(PyErr_Occurred(), nullptr); 78 ASSERT_TRUE(PyFloat_CheckExact(flt)); 79 EXPECT_EQ(PyFloat_AsDouble(flt), 45.5); 80} 81 82TEST_F(FloatExtensionApiTest, 83 PyFloatFromStringWithUserBufferAndOnlyGetbufferReturnsFloat) { 84 static char contents[] = "45.5"; 85 static Py_ssize_t contents_len = std::strlen(contents); 86 getbufferproc mocked_getbuffer_func = [](PyObject* obj, Py_buffer* view, 87 int flags) { 88 return PyBuffer_FillInfo(view, obj, contents, contents_len, /*readonly=*/1, 89 flags); 90 }; 91 PyType_Slot slots[] = { 92 {Py_bf_getbuffer, reinterpret_cast<void*>(mocked_getbuffer_func)}, 93 {0, nullptr}, 94 }; 95 static PyType_Spec spec; 96 spec = { 97 "foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT, slots, 98 }; 99 PyObjectPtr buf_type(PyType_FromSpec(&spec)); 100 ASSERT_NE(buf_type, nullptr); 101 ASSERT_TRUE(PyType_CheckExact(buf_type)); 102 103 PyObjectPtr instance(PyObject_CallFunction(buf_type, nullptr)); 104 ASSERT_TRUE(PyObject_CheckBuffer(instance.get())); 105 106 PyObjectPtr flt(PyFloat_FromString(instance)); 107 ASSERT_EQ(PyErr_Occurred(), nullptr); 108 ASSERT_TRUE(PyFloat_CheckExact(flt)); 109 EXPECT_EQ(PyFloat_AsDouble(flt), 45.5); 110} 111 112TEST_F(FloatExtensionApiTest, 113 PyFloatFromStringWithNonNullTermUserBufferReturnsFloat) { 114 static char contents[] = "55.5 not null terminated"; 115 static Py_ssize_t contents_len = 4; // Not the whole string 116 getbufferproc mocked_getbuffer_func = [](PyObject* obj, Py_buffer* view, 117 int flags) { 118 return PyBuffer_FillInfo(view, obj, contents, contents_len, /*readonly*/ 1, 119 flags); 120 }; 121 releasebufferproc mocked_releasebuffer_func = [](PyObject*, Py_buffer* view) { 122 view->buf = nullptr; 123 view->obj = nullptr; 124 }; 125 PyType_Slot slots[] = { 126 {Py_bf_getbuffer, reinterpret_cast<void*>(mocked_getbuffer_func)}, 127 {Py_bf_releasebuffer, reinterpret_cast<void*>(mocked_releasebuffer_func)}, 128 {0, nullptr}, 129 }; 130 static PyType_Spec spec; 131 spec = { 132 "foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT, slots, 133 }; 134 PyObjectPtr buf_type(PyType_FromSpec(&spec)); 135 ASSERT_NE(buf_type, nullptr); 136 ASSERT_TRUE(PyType_CheckExact(buf_type)); 137 138 PyObjectPtr instance(PyObject_CallFunction(buf_type, nullptr)); 139 ASSERT_TRUE(PyObject_CheckBuffer(instance.get())); 140 141 PyObjectPtr flt(PyFloat_FromString(instance)); 142 ASSERT_EQ(PyErr_Occurred(), nullptr); 143 ASSERT_TRUE(PyFloat_CheckExact(flt)); 144 EXPECT_EQ(PyFloat_AsDouble(flt), 55.5); 145} 146 147TEST_F(FloatExtensionApiTest, 148 PyFloatFromStringWithEmbededNullTermUserBufferRaisesValueError) { 149 static char contents[] = "55.5\0 embeded null"; 150 static Py_ssize_t contents_len = 18; // Include the null and more... 151 getbufferproc mocked_getbuffer_func = [](PyObject* obj, Py_buffer* view, 152 int flags) { 153 return PyBuffer_FillInfo(view, obj, contents, contents_len, /*readonly*/ 1, 154 flags); 155 }; 156 releasebufferproc mocked_releasebuffer_func = [](PyObject*, Py_buffer* view) { 157 view->buf = nullptr; 158 view->obj = nullptr; 159 }; 160 PyType_Slot slots[] = { 161 {Py_bf_getbuffer, reinterpret_cast<void*>(mocked_getbuffer_func)}, 162 {Py_bf_releasebuffer, reinterpret_cast<void*>(mocked_releasebuffer_func)}, 163 {0, nullptr}, 164 }; 165 static PyType_Spec spec; 166 spec = { 167 "foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT, slots, 168 }; 169 PyObjectPtr buf_type(PyType_FromSpec(&spec)); 170 ASSERT_NE(buf_type, nullptr); 171 ASSERT_TRUE(PyType_CheckExact(buf_type)); 172 173 PyObjectPtr instance(PyObject_CallFunction(buf_type, nullptr)); 174 ASSERT_TRUE(PyObject_CheckBuffer(instance.get())); 175 176 PyObjectPtr flt(PyFloat_FromString(instance)); 177 EXPECT_FALSE(flt); 178 ASSERT_NE(PyErr_Occurred(), nullptr); 179 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_ValueError)); 180} 181 182TEST_F(FloatExtensionApiTest, 183 PyFloatFromStringWithUserBufferAndRaisingGetBufferRaisesTypeError) { 184 getbufferproc mocked_getbuffer_func = [](PyObject*, Py_buffer*, int) { 185 PyErr_Format(PyExc_NotImplementedError, "not implemented"); 186 return -1; 187 }; 188 releasebufferproc mocked_releasebuffer_func = [](PyObject*, Py_buffer* view) { 189 view->buf = nullptr; 190 view->obj = nullptr; 191 }; 192 PyType_Slot slots[] = { 193 {Py_bf_getbuffer, reinterpret_cast<void*>(mocked_getbuffer_func)}, 194 {Py_bf_releasebuffer, reinterpret_cast<void*>(mocked_releasebuffer_func)}, 195 {0, nullptr}, 196 }; 197 static PyType_Spec spec; 198 spec = { 199 "foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT, slots, 200 }; 201 PyObjectPtr buf_type(PyType_FromSpec(&spec)); 202 ASSERT_NE(buf_type, nullptr); 203 ASSERT_TRUE(PyType_CheckExact(buf_type)); 204 205 PyObjectPtr instance(PyObject_CallFunction(buf_type, nullptr)); 206 ASSERT_TRUE(PyObject_CheckBuffer(instance.get())); 207 208 PyObjectPtr flt(PyFloat_FromString(instance)); 209 EXPECT_FALSE(flt); 210 ASSERT_NE(PyErr_Occurred(), nullptr); 211 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); 212} 213 214TEST_F(FloatExtensionApiTest, PyFloatFromStringWithIntRaisesTypeError) { 215 PyObjectPtr integer(PyLong_FromLong(100)); 216 EXPECT_EQ(PyFloat_FromString(integer), nullptr); 217 ASSERT_NE(PyErr_Occurred(), nullptr); 218 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); 219} 220 221TEST_F(FloatExtensionApiTest, PyFloatFromStringWithFloatRaisesTypeError) { 222 PyObjectPtr flt(PyFloat_FromDouble(1.5)); 223 EXPECT_EQ(PyFloat_FromString(flt), nullptr); 224 ASSERT_NE(PyErr_Occurred(), nullptr); 225 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); 226} 227 228TEST_F(FloatExtensionApiTest, PyFloatFromStringWithNoneRaisesTypeError) { 229 EXPECT_EQ(PyFloat_FromString(Py_None), nullptr); 230 ASSERT_NE(PyErr_Occurred(), nullptr); 231 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); 232} 233 234TEST_F(FloatExtensionApiTest, FromDoubleReturnsFloat) { 235 const double val = 15.4; 236 PyObjectPtr flt(PyFloat_FromDouble(val)); 237 ASSERT_TRUE(PyFloat_CheckExact(flt)); 238 EXPECT_EQ(PyFloat_AsDouble(flt), val); 239} 240 241TEST_F(FloatExtensionApiTest, NegativeFromDoubleReturnsFloat) { 242 const double val = -10000.123; 243 PyObjectPtr flt(PyFloat_FromDouble(val)); 244 EXPECT_TRUE(PyFloat_CheckExact(flt)); 245 EXPECT_EQ(PyFloat_AsDouble(flt), val); 246} 247 248TEST_F(FloatExtensionApiTest, AsDoubleFromNullRaisesException) { 249 double res = PyFloat_AsDouble(nullptr); 250 EXPECT_EQ(res, -1); 251 252 ASSERT_NE(PyErr_Occurred(), nullptr); 253 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); 254} 255 256TEST_F(FloatExtensionApiTest, AsDoubleFromNonFloatRaisesException) { 257 PyObjectPtr list(PyList_New(0)); 258 double res = PyFloat_AsDouble(list); 259 EXPECT_EQ(res, -1); 260 261 ASSERT_NE(PyErr_Occurred(), nullptr); 262 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); 263} 264 265TEST_F(FloatExtensionApiTest, AsDoubleCallsDunderFloat) { 266 PyRun_SimpleString(R"( 267class FloatLikeClass: 268 def __float__(self): 269 return 1.5 270 271f = FloatLikeClass(); 272 )"); 273 PyObjectPtr f(testing::mainModuleGet("f")); 274 double res = PyFloat_AsDouble(f); 275 EXPECT_EQ(res, 1.5); 276} 277 278TEST_F(FloatExtensionApiTest, AsDoubleWithDunderFloatPropagatesException) { 279 PyRun_SimpleString(R"( 280class FloatLikeClass: 281 @property 282 def __float__(self): 283 raise KeyError 284 285f = FloatLikeClass(); 286 )"); 287 PyObjectPtr f(mainModuleGet("f")); 288 EXPECT_EQ(PyFloat_AsDouble(f), -1.0); 289 290 ASSERT_NE(PyErr_Occurred(), nullptr); 291 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_KeyError)); 292} 293 294TEST_F(FloatExtensionApiTest, AsDoubleFromFloatSubclassReturnsFloat) { 295 PyRun_SimpleString(R"( 296class SubFloat(float): 297 def __new__(self, value): 298 self.foo = 3 299 return super().__new__(self, value) 300subfloat = SubFloat(1.5) 301subfloat_foo = subfloat.foo 302 )"); 303 PyObjectPtr subfloat(testing::mainModuleGet("subfloat")); 304 ASSERT_FALSE(PyLong_CheckExact(subfloat)); 305 ASSERT_TRUE(PyFloat_Check(subfloat)); 306 EXPECT_EQ(1.5, PyFloat_AsDouble(subfloat)); 307 308 PyObjectPtr subfloat_foo(testing::mainModuleGet("subfloat_foo")); 309 ASSERT_TRUE(PyLong_Check(subfloat_foo)); 310 EXPECT_EQ(3, PyLong_AsLong(subfloat_foo)); 311} 312 313TEST_F(FloatExtensionApiTest, GetMaxReturnsDblMax) { 314 EXPECT_EQ(PyFloat_GetMax(), DBL_MAX); 315} 316 317TEST_F(FloatExtensionApiTest, GetMinReturnsDblMin) { 318 EXPECT_EQ(PyFloat_GetMin(), DBL_MIN); 319} 320 321TEST_F(FloatExtensionApiTest, Pack2) { 322 double expected = 1.5; 323 unsigned char ptr[2] = {}; 324 ASSERT_EQ(_PyFloat_Pack2(expected, ptr, /* le */ true), 0); 325 // 00000000 00111110 326 ASSERT_EQ(ptr[0], 0); 327 ASSERT_EQ(ptr[1], 62); 328 EXPECT_EQ(_PyFloat_Unpack2(ptr, /* le */ true), 1.5); 329} 330 331TEST_F(FloatExtensionApiTest, Pack4) { 332 double expected = 1.5; 333 unsigned char ptr[4] = {}; 334 ASSERT_EQ(_PyFloat_Pack4(expected, ptr, /* le */ true), 0); 335 // 0000000 0000000 11000000 00111111 336 ASSERT_EQ(ptr[0], 0); 337 ASSERT_EQ(ptr[1], 0); 338 ASSERT_EQ(ptr[2], 192); 339 ASSERT_EQ(ptr[3], 63); 340 EXPECT_EQ(_PyFloat_Unpack4(ptr, /* le */ true), 1.5); 341} 342 343TEST_F(FloatExtensionApiTest, Pack8) { 344 double expected = 1.5; 345 unsigned char ptr[8] = {}; 346 ASSERT_EQ(_PyFloat_Pack8(expected, ptr, /* le */ true), 0); 347 // 0000000 0000000 0000000 0000000 0000000 0000000 11111000 00111111 348 ASSERT_EQ(ptr[0], 0); 349 ASSERT_EQ(ptr[1], 0); 350 ASSERT_EQ(ptr[2], 0); 351 ASSERT_EQ(ptr[3], 0); 352 ASSERT_EQ(ptr[4], 0); 353 ASSERT_EQ(ptr[5], 0); 354 ASSERT_EQ(ptr[6], 248); 355 ASSERT_EQ(ptr[7], 63); 356 EXPECT_EQ(_PyFloat_Unpack8(ptr, /* le */ true), 1.5); 357} 358 359TEST_F(FloatExtensionApiTest, PyReturnNanReturnsNan) { 360 PyObjectPtr module(PyModule_New("mod")); 361 binaryfunc meth = [](PyObject*, PyObject*) { Py_RETURN_NAN; }; 362 static PyMethodDef foo_func = {"foo", meth, METH_NOARGS}; 363 PyObjectPtr func(PyCFunction_NewEx(&foo_func, nullptr, module)); 364 PyObjectPtr result(_PyObject_CallNoArg(func)); 365 EXPECT_TRUE(std::isnan(PyFloat_AsDouble(result))); 366} 367 368TEST_F(FloatExtensionApiTest, PyReturnINFReturnsInf) { 369 PyObjectPtr module(PyModule_New("mod")); 370 binaryfunc meth = [](PyObject*, PyObject*) { Py_RETURN_INF(0); }; 371 static PyMethodDef foo_func = {"foo", meth, METH_NOARGS}; 372 PyObjectPtr func(PyCFunction_NewEx(&foo_func, nullptr, module)); 373 PyObjectPtr result(_PyObject_CallNoArg(func)); 374 EXPECT_TRUE(std::isinf(PyFloat_AsDouble(result))); 375 EXPECT_GT(PyFloat_AsDouble(result), 0.); 376} 377 378TEST_F(FloatExtensionApiTest, PyReturnINFReturnsNegativeInf) { 379 PyObjectPtr module(PyModule_New("mod")); 380 binaryfunc meth = [](PyObject*, PyObject*) { Py_RETURN_INF(-1); }; 381 static PyMethodDef foo_func = {"foo", meth, METH_NOARGS}; 382 PyObjectPtr func(PyCFunction_NewEx(&foo_func, nullptr, module)); 383 PyObjectPtr result(_PyObject_CallNoArg(func)); 384 EXPECT_TRUE(std::isinf(PyFloat_AsDouble(result))); 385 EXPECT_LT(PyFloat_AsDouble(result), 0.); 386} 387 388} // namespace testing 389} // namespace py