this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include <cerrno>
3#include <cmath>
4
5#include "Python.h"
6#include "gtest/gtest.h"
7
8#include "capi-fixture.h"
9#include "capi-testing.h"
10
11namespace py {
12namespace testing {
13
14using ComplexExtensionApiTest = ExtensionApi;
15
16TEST_F(ComplexExtensionApiTest, PyCAbsReturnsComplexAbsoluteValue) {
17 EXPECT_EQ(_Py_c_abs({12, 0}), 12);
18 EXPECT_EQ(_Py_c_abs({0, 34}), 34);
19 EXPECT_EQ(_Py_c_abs({INFINITY, 56}), INFINITY);
20 EXPECT_EQ(_Py_c_abs({-INFINITY, 78}), INFINITY);
21 EXPECT_EQ(_Py_c_abs({90, INFINITY}), INFINITY);
22 EXPECT_EQ(_Py_c_abs({123, -INFINITY}), INFINITY);
23 EXPECT_TRUE(std::isnan(_Py_c_abs({456, NAN})));
24 EXPECT_TRUE(std::isnan(_Py_c_abs({NAN, 789})));
25}
26
27TEST_F(ComplexExtensionApiTest, PyCDiffReturnsComplexDifference) {
28 Py_complex diff = _Py_c_diff({2.0, 5.0}, {4.0, -3.0});
29 EXPECT_EQ(diff.real, -2.0);
30 EXPECT_EQ(diff.imag, 8.0);
31}
32
33TEST_F(ComplexExtensionApiTest, PyCNegReturnsComplexNegation) {
34 Py_complex neg = _Py_c_neg({-123.0, 456.0});
35 EXPECT_EQ(neg.real, 123.0);
36 EXPECT_EQ(neg.imag, -456);
37}
38
39TEST_F(ComplexExtensionApiTest, PyCProdReturnsComplexProduct) {
40 Py_complex prod = _Py_c_prod({1.0, -2.0}, {-3.0, 4.0});
41 EXPECT_EQ(prod.real, 5.0);
42 EXPECT_EQ(prod.imag, 10.0);
43}
44
45TEST_F(ComplexExtensionApiTest, PyCQuotReturnsComplexQuotient) {
46 // rhs.real > rhs.imag
47 errno = 0;
48 Py_complex q1 = _Py_c_quot({10, 20}, {2, 1});
49 EXPECT_EQ(errno, 0);
50 EXPECT_EQ(q1.real, 8.0);
51 EXPECT_EQ(q1.imag, 6.0);
52
53 // rhs.imag > rhs.real
54 errno = 0;
55 Py_complex q2 = _Py_c_quot({10, 20}, {1, 2});
56 EXPECT_EQ(errno, 0);
57 EXPECT_EQ(q2.real, 10.0);
58 EXPECT_EQ(q2.imag, 0.0);
59
60 // rhs.real = 0
61 errno = 0;
62 Py_complex q3 = _Py_c_quot({10, 10}, {0, 0});
63 EXPECT_EQ(errno, EDOM);
64 EXPECT_EQ(q3.real, 0.0);
65 EXPECT_EQ(q3.imag, 0.0);
66
67 // NAN
68 errno = 0;
69 Py_complex q4 = _Py_c_quot({1, 2}, {NAN, 4});
70 EXPECT_EQ(errno, 0);
71 EXPECT_TRUE(std::isnan(q4.real));
72 EXPECT_TRUE(std::isnan(q4.imag));
73}
74
75TEST_F(ComplexExtensionApiTest, PyCSumReturnsComplexSum) {
76 Py_complex sum = _Py_c_sum({2.0, 5.0}, {4.0, -3.0});
77 EXPECT_EQ(sum.real, 6.0);
78 EXPECT_EQ(sum.imag, 2.0);
79}
80
81TEST_F(ComplexExtensionApiTest, AsCComplexWithComplexReturnsValue) {
82 PyObjectPtr cmp(PyComplex_FromDoubles(1.0, 0.0));
83 Py_complex result = PyComplex_AsCComplex(cmp);
84 ASSERT_EQ(PyErr_Occurred(), nullptr);
85 EXPECT_EQ(result.real, 1.0);
86 EXPECT_EQ(result.imag, 0.0);
87}
88
89TEST_F(ComplexExtensionApiTest,
90 AsComplexWithRaisingDescriptorPropagatesException) {
91 PyRun_SimpleString(R"(
92class Desc:
93 def __get__(self, owner, fn):
94 raise UserWarning("foo")
95 def __call__(self, *args, **kwargs):
96 raise "foo"
97class Foo:
98 __complex__ = Desc()
99foo = Foo()
100)");
101 PyObjectPtr foo(mainModuleGet("foo"));
102 Py_complex result = PyComplex_AsCComplex(foo);
103 EXPECT_EQ(result.real, -1.0);
104 EXPECT_EQ(result.imag, 0.0);
105 ASSERT_NE(PyErr_Occurred(), nullptr);
106 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_UserWarning));
107}
108
109TEST_F(ComplexExtensionApiTest,
110 AsComplexWithMistypedDunderComplexRaisesTypeError) {
111 PyRun_SimpleString(R"(
112class Foo:
113 def __complex__(self):
114 return 1
115foo = Foo()
116)");
117 PyObjectPtr foo(mainModuleGet("foo"));
118 Py_complex result = PyComplex_AsCComplex(foo);
119 ASSERT_NE(PyErr_Occurred(), nullptr);
120 ASSERT_EQ(result.real, -1.0);
121 ASSERT_EQ(result.imag, 0.0);
122 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
123}
124
125TEST_F(ComplexExtensionApiTest, AsComplexWithDunderComplexReturnsValue) {
126 PyRun_SimpleString(R"(
127class Foo:
128 def __complex__(self):
129 return 1+0j
130foo = Foo()
131)");
132 PyObjectPtr foo(mainModuleGet("foo"));
133 Py_complex result = PyComplex_AsCComplex(foo);
134 ASSERT_EQ(PyErr_Occurred(), nullptr);
135 EXPECT_EQ(result.real, 1.0);
136 EXPECT_EQ(result.imag, 0.0);
137}
138
139TEST_F(ComplexExtensionApiTest, AsCComplexWithFloatReturnsRealValue) {
140 PyObjectPtr flt(PyFloat_FromDouble(1.0));
141 Py_complex result = PyComplex_AsCComplex(flt);
142 ASSERT_EQ(PyErr_Occurred(), nullptr);
143 EXPECT_EQ(result.real, 1.0);
144 EXPECT_EQ(result.imag, 0.0);
145}
146
147TEST_F(ComplexExtensionApiTest, FromDoublesReturnsComplex) {
148 PyObjectPtr cmp(PyComplex_FromDoubles(0.0, 0.0));
149 EXPECT_TRUE(PyComplex_CheckExact(cmp));
150}
151
152TEST_F(ComplexExtensionApiTest, FromCComplexReturnsComplex) {
153 Py_complex c = {1.0, 0.0};
154 PyObjectPtr cmp(PyComplex_FromCComplex(c));
155 EXPECT_TRUE(PyComplex_CheckExact(cmp));
156}
157
158TEST_F(ComplexExtensionApiTest, ImagAsDoubleWithComplexReturnsValue) {
159 PyObjectPtr cmp(PyComplex_FromDoubles(0.0, 1.0));
160 double result = PyComplex_ImagAsDouble(cmp);
161 ASSERT_EQ(PyErr_Occurred(), nullptr);
162 EXPECT_EQ(result, 1.0);
163}
164
165TEST_F(ComplexExtensionApiTest, ImagAsDoubleWithNonComplexReturnsZero) {
166 PyObjectPtr flt(PyFloat_FromDouble(1.0));
167 double result = PyComplex_ImagAsDouble(flt);
168 ASSERT_EQ(PyErr_Occurred(), nullptr);
169 EXPECT_EQ(result, 0.0);
170}
171
172TEST_F(ComplexExtensionApiTest, RealAsDoubleWithComplexReturnsValue) {
173 PyObjectPtr cmp(PyComplex_FromDoubles(1.0, 0.0));
174 double result = PyComplex_RealAsDouble(cmp);
175 ASSERT_EQ(PyErr_Occurred(), nullptr);
176 EXPECT_EQ(result, 1.0);
177}
178
179TEST_F(ComplexExtensionApiTest, RealAsDoubleWithFloatReturnsFloatValue) {
180 PyObjectPtr flt(PyFloat_FromDouble(1.0));
181 double result = PyComplex_RealAsDouble(flt);
182 ASSERT_EQ(PyErr_Occurred(), nullptr);
183 EXPECT_EQ(result, 1.0);
184}
185
186TEST_F(ComplexExtensionApiTest, RealAsDoubleWithNonFloatRaisesTypeError) {
187 PyObjectPtr foo(PyTuple_New(0));
188 double result = PyComplex_RealAsDouble(foo);
189 ASSERT_NE(PyErr_Occurred(), nullptr);
190 ASSERT_EQ(result, -1.0);
191 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
192}
193
194} // namespace testing
195} // namespace py