py_number_ut.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. #include "ut3/py_test_engine.h"
  2. #include <library/cpp/testing/unittest/registar.h>
  3. #define PY_CHECKER(Name, PyType, AsType, Type) \
  4. struct TPy##Name##Checker { \
  5. void operator()(PyObject* pyVal, Type expected) { \
  6. UNIT_ASSERT(Py##PyType##_Check(pyVal)); \
  7. Type val = Py##PyType##_As##AsType(pyVal); \
  8. UNIT_ASSERT(val != static_cast<Type>(-1) || !PyErr_Occurred()); \
  9. UNIT_ASSERT_EQUAL(val, expected); \
  10. } \
  11. };
  12. #if PY_MAJOR_VERSION >= 3
  13. PY_CHECKER(Long, Long, Long, long)
  14. #else
  15. PY_CHECKER(Int, Int, Long, long)
  16. #endif
  17. #ifdef HAVE_LONG_LONG
  18. PY_CHECKER(LLong, Long, LongLong, long long)
  19. PY_CHECKER(Ulong, Long, UnsignedLongLong, unsigned long long)
  20. #else
  21. PY_CHECKER(LLong, Long, Long, long)
  22. PY_CHECKER(Ulong, Long, UnsignedLong, unsigned long)
  23. #endif
  24. PY_CHECKER(Float, Float, Double, long)
  25. #undef PY_CHECKER
  26. using namespace NPython;
  27. Y_UNIT_TEST_SUITE(TPyNumberTest) {
  28. template <typename T, typename TPyChecker>
  29. void TestCastsInRange(T begin, T end) {
  30. for (T i = begin; i < end; i++) {
  31. TPyObjectPtr pyVal = PyCast<T>(i);
  32. UNIT_ASSERT(pyVal.Get() != nullptr);
  33. TPyChecker c;
  34. c(pyVal.Get(), i);
  35. T cppVal = PyCast<T>(pyVal.Get());
  36. UNIT_ASSERT_EQUAL(cppVal, i);
  37. }
  38. }
  39. template <typename T, typename TPyChecker, int range = 10>
  40. void TestSignedCasts() {
  41. TPythonTestEngine engine;
  42. TestCastsInRange<T, TPyChecker>(Min<T>(), Min<T>() + range);
  43. TestCastsInRange<T, TPyChecker>(-range, range);
  44. TestCastsInRange<T, TPyChecker>(Max<T>() - range, Max<T>());
  45. }
  46. template <typename T, typename TPyDownChecker,
  47. typename TPyUpChecker = TPyDownChecker, int range = 10>
  48. void TestUnsignedCasts() {
  49. TPythonTestEngine engine;
  50. TestCastsInRange<T, TPyDownChecker>(Min<T>(), Min<T>() + range);
  51. TestCastsInRange<T, TPyUpChecker>(Max<T>() - range, Max<T>());
  52. }
  53. Y_UNIT_TEST(Bool) {
  54. TPythonTestEngine engine;
  55. UNIT_ASSERT_EQUAL(PyCast<bool>(Py_True), true);
  56. UNIT_ASSERT_EQUAL(PyCast<bool>(Py_False), false);
  57. TPyObjectPtr list = PyList_New(0);
  58. UNIT_ASSERT_EQUAL(PyCast<bool>(list.Get()), false);
  59. bool res1;
  60. UNIT_ASSERT(TryPyCast<bool>(list.Get(), res1));
  61. UNIT_ASSERT_EQUAL(res1, false);
  62. PyList_Append(list.Get(), Py_None);
  63. UNIT_ASSERT_EQUAL(PyCast<bool>(list.Get()), true);
  64. bool res2;
  65. UNIT_ASSERT(TryPyCast<bool>(list.Get(), res2));
  66. UNIT_ASSERT_EQUAL(res2, true);
  67. }
  68. Y_UNIT_TEST(Float) {
  69. TestSignedCasts<float, TPyFloatChecker>();
  70. }
  71. Y_UNIT_TEST(Double) {
  72. TestUnsignedCasts<double, TPyFloatChecker>();
  73. }
  74. Y_UNIT_TEST(I64) {
  75. TestSignedCasts<i64, TPyLLongChecker>();
  76. }
  77. Y_UNIT_TEST(Ui64) {
  78. TestUnsignedCasts<ui64, TPyUlongChecker>();
  79. }
  80. #if PY_MAJOR_VERSION >= 3
  81. Y_UNIT_TEST(I8) {
  82. TestSignedCasts<i8, TPyLongChecker>();
  83. }
  84. Y_UNIT_TEST(Ui8) {
  85. TestUnsignedCasts<ui8, TPyLongChecker>();
  86. }
  87. Y_UNIT_TEST(I16) {
  88. TestSignedCasts<i16, TPyLongChecker>();
  89. }
  90. Y_UNIT_TEST(Ui16) {
  91. TestUnsignedCasts<ui16, TPyLongChecker>();
  92. }
  93. Y_UNIT_TEST(I32) {
  94. TestSignedCasts<i32, TPyLongChecker>();
  95. }
  96. Y_UNIT_TEST(Ui32) {
  97. TestUnsignedCasts<ui32, TPyLongChecker>();
  98. }
  99. Y_UNIT_TEST(ImplicitIntCasts) {
  100. TPythonTestEngine engine;
  101. const ui64 longMask = sizeof(long) == 4 ? Max<ui32>() : Max<ui64>();
  102. i64 expected = longMask & (static_cast<i64>(Max<ui32>()) + 10);
  103. TPyObjectPtr pyInt = PyLong_FromLong(expected);
  104. { // signed
  105. i64 actual = PyCast<i64>(pyInt.Get());
  106. UNIT_ASSERT_EQUAL(actual, expected);
  107. bool isOk = TryPyCast<i64>(pyInt.Get(), actual);
  108. UNIT_ASSERT(isOk);
  109. UNIT_ASSERT_EQUAL(actual, expected);
  110. }
  111. { // unsigned
  112. ui64 actual = PyCast<ui64>(pyInt.Get());
  113. UNIT_ASSERT_EQUAL(actual, static_cast<ui64>(expected));
  114. bool isOk = TryPyCast<ui64>(pyInt.Get(), actual);
  115. UNIT_ASSERT(isOk);
  116. UNIT_ASSERT_EQUAL(actual, static_cast<ui64>(expected));
  117. }
  118. { // to float
  119. float f = PyCast<float>(pyInt.Get());
  120. UNIT_ASSERT_DOUBLES_EQUAL(f, expected, 0.000001);
  121. bool isOk = TryPyCast<float>(pyInt.Get(), f);
  122. UNIT_ASSERT(isOk);
  123. UNIT_ASSERT_DOUBLES_EQUAL(f, expected, 0.000001);
  124. }
  125. { // to double
  126. double d = PyCast<double>(pyInt.Get());
  127. UNIT_ASSERT_DOUBLES_EQUAL(d, expected, 0.000001);
  128. bool isOk = TryPyCast<double>(pyInt.Get(), d);
  129. UNIT_ASSERT(isOk);
  130. UNIT_ASSERT_DOUBLES_EQUAL(d, expected, 0.000001);
  131. }
  132. // expected overflow
  133. i32 tmp;
  134. UNIT_ASSERT(!TryPyCast<i32>(pyInt.Get(), tmp));
  135. ui32 tmpu;
  136. UNIT_ASSERT(!TryPyCast<ui32>(pyInt.Get(), tmpu));
  137. }
  138. #else
  139. Y_UNIT_TEST(I8) {
  140. TestSignedCasts<i8, TPyIntChecker>();
  141. }
  142. Y_UNIT_TEST(Ui8) {
  143. TestUnsignedCasts<ui8, TPyIntChecker>();
  144. }
  145. Y_UNIT_TEST(I16) {
  146. TestSignedCasts<i16, TPyIntChecker>();
  147. }
  148. Y_UNIT_TEST(Ui16) {
  149. TestUnsignedCasts<ui16, TPyIntChecker>();
  150. }
  151. Y_UNIT_TEST(I32) {
  152. TestSignedCasts<i32, TPyIntChecker>();
  153. }
  154. Y_UNIT_TEST(Ui32) {
  155. if (sizeof(long) == 4) {
  156. TestUnsignedCasts<ui32, TPyIntChecker, TPyLLongChecker>();
  157. } else {
  158. TestUnsignedCasts<ui32, TPyIntChecker>();
  159. }
  160. }
  161. Y_UNIT_TEST(ImplicitIntCasts) {
  162. TPythonTestEngine engine;
  163. const ui64 longMask = sizeof(long) == 4 ? Max<ui32>() : Max<ui64>();
  164. i64 expected = longMask & (static_cast<i64>(Max<ui32>()) + 10);
  165. TPyObjectPtr pyInt = PyInt_FromLong(expected);
  166. { // signed
  167. i64 actual = PyCast<i64>(pyInt.Get());
  168. UNIT_ASSERT_EQUAL(actual, expected);
  169. bool isOk = TryPyCast<i64>(pyInt.Get(), actual);
  170. UNIT_ASSERT(isOk);
  171. UNIT_ASSERT_EQUAL(actual, expected);
  172. }
  173. { // unsigned
  174. ui64 actual = PyCast<ui64>(pyInt.Get());
  175. UNIT_ASSERT_EQUAL(actual, static_cast<ui64>(expected));
  176. bool isOk = TryPyCast<ui64>(pyInt.Get(), actual);
  177. UNIT_ASSERT(isOk);
  178. UNIT_ASSERT_EQUAL(actual, static_cast<ui64>(expected));
  179. }
  180. { // to float
  181. float f = PyCast<float>(pyInt.Get());
  182. UNIT_ASSERT_DOUBLES_EQUAL(f, expected, 0.000001);
  183. bool isOk = TryPyCast<float>(pyInt.Get(), f);
  184. UNIT_ASSERT(isOk);
  185. UNIT_ASSERT_DOUBLES_EQUAL(f, expected, 0.000001);
  186. }
  187. { // to double
  188. double d = PyCast<double>(pyInt.Get());
  189. UNIT_ASSERT_DOUBLES_EQUAL(d, expected, 0.000001);
  190. bool isOk = TryPyCast<double>(pyInt.Get(), d);
  191. UNIT_ASSERT(isOk);
  192. UNIT_ASSERT_DOUBLES_EQUAL(d, expected, 0.000001);
  193. }
  194. // expected overflow
  195. i32 tmp;
  196. UNIT_ASSERT(!TryPyCast<i32>(pyInt.Get(), tmp));
  197. ui32 tmpu;
  198. UNIT_ASSERT(!TryPyCast<ui32>(pyInt.Get(), tmpu));
  199. }
  200. #endif
  201. Y_UNIT_TEST(ImplicitLongCasts) {
  202. TPythonTestEngine engine;
  203. i64 expected = static_cast<i64>(Max<ui32>()) + 10;
  204. TPyObjectPtr pyLong;
  205. #ifdef HAVE_LONG_LONG
  206. pyLong = PyLong_FromLongLong(expected);
  207. #else
  208. pyLong = PyLong_FromLong(expected)
  209. #endif
  210. { // signed
  211. i64 actual = PyCast<i64>(pyLong.Get());
  212. UNIT_ASSERT_EQUAL(actual, expected);
  213. bool isOk = TryPyCast<i64>(pyLong.Get(), actual);
  214. UNIT_ASSERT(isOk);
  215. UNIT_ASSERT_EQUAL(actual, expected);
  216. }
  217. { // unsigned
  218. ui64 actual = PyCast<ui64>(pyLong.Get());
  219. UNIT_ASSERT_EQUAL(actual, static_cast<ui64>(expected));
  220. bool isOk = TryPyCast<ui64>(pyLong.Get(), actual);
  221. UNIT_ASSERT(isOk);
  222. UNIT_ASSERT_EQUAL(actual, static_cast<ui64>(expected));
  223. }
  224. { // to float
  225. float f = PyCast<float>(pyLong.Get());
  226. UNIT_ASSERT_DOUBLES_EQUAL(f, expected, 0.000001);
  227. bool isOk = TryPyCast<float>(pyLong.Get(), f);
  228. UNIT_ASSERT(isOk);
  229. UNIT_ASSERT_DOUBLES_EQUAL(f, expected, 0.000001);
  230. }
  231. { // to double
  232. double d = PyCast<double>(pyLong.Get());
  233. UNIT_ASSERT_DOUBLES_EQUAL(d, expected, 0.000001);
  234. bool isOk = TryPyCast<double>(pyLong.Get(), d);
  235. UNIT_ASSERT(isOk);
  236. UNIT_ASSERT_DOUBLES_EQUAL(d, expected, 0.000001);
  237. }
  238. // expected overflow
  239. i8 tmp;
  240. UNIT_ASSERT(!TryPyCast<i8>(pyLong.Get(), tmp));
  241. }
  242. Y_UNIT_TEST(HugeLongOverflow) {
  243. TPythonTestEngine engine;
  244. TPyObjectPtr pyLong = PyLong_FromString((char*)"0xfffffffffffffffff", nullptr, 0);
  245. TPyObjectPtr bitLength = PyObject_CallMethod(pyLong.Get(), (char*)"bit_length", (char*)"()");
  246. UNIT_ASSERT_EQUAL(PyCast<ui32>(bitLength.Get()), 68); // 68 bits number
  247. ui64 resUI64;
  248. UNIT_ASSERT(!TryPyCast(pyLong.Get(), resUI64));
  249. i64 resI64;
  250. UNIT_ASSERT(!TryPyCast(pyLong.Get(), resI64));
  251. ui32 resUI32;
  252. UNIT_ASSERT(!TryPyCast(pyLong.Get(), resUI32));
  253. i32 resI32;
  254. UNIT_ASSERT(!TryPyCast(pyLong.Get(), resI32));
  255. ui16 resUI16;
  256. UNIT_ASSERT(!TryPyCast(pyLong.Get(), resUI16));
  257. i16 resI16;
  258. UNIT_ASSERT(!TryPyCast(pyLong.Get(), resI16));
  259. ui8 resUI8;
  260. UNIT_ASSERT(!TryPyCast(pyLong.Get(), resUI8));
  261. i8 resI8;
  262. UNIT_ASSERT(!TryPyCast(pyLong.Get(), resI8));
  263. }
  264. Y_UNIT_TEST(ImplicitFloatCasts) {
  265. TPythonTestEngine engine;
  266. double expected = 3.14159;
  267. TPyObjectPtr pyFloat = PyFloat_FromDouble(expected);
  268. { // to float
  269. float f = PyCast<float>(pyFloat.Get());
  270. UNIT_ASSERT_DOUBLES_EQUAL(f, expected, 0.000001);
  271. bool isOk = TryPyCast<float>(pyFloat.Get(), f);
  272. UNIT_ASSERT(isOk);
  273. UNIT_ASSERT_DOUBLES_EQUAL(f, expected, 0.000001);
  274. }
  275. { // to double
  276. double d = PyCast<double>(pyFloat.Get());
  277. UNIT_ASSERT_DOUBLES_EQUAL(d, expected, 0.000001);
  278. bool isOk = TryPyCast<double>(pyFloat.Get(), d);
  279. UNIT_ASSERT(isOk);
  280. UNIT_ASSERT_DOUBLES_EQUAL(d, expected, 0.000001);
  281. }
  282. }
  283. }