this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include "float-builtins.h"
3
4#include <limits>
5
6#include "gtest/gtest.h"
7
8#include "builtins.h"
9#include "handles.h"
10#include "int-builtins.h"
11#include "objects.h"
12#include "runtime.h"
13#include "test-utils.h"
14
15namespace py {
16namespace testing {
17
18using FloatBuiltinsTest = testing::RuntimeFixture;
19
20TEST(FloatBuiltinsTestNoFixture,
21 DecodeDoubleWithPositiveDoubleReturnsIsNegFalse) {
22 double input = 100.0;
23 bool is_neg;
24 int exp;
25 int64_t mantissa;
26 decodeDouble(input, &is_neg, &exp, &mantissa);
27 EXPECT_EQ(is_neg, false);
28}
29
30TEST(FloatBuiltinsTestNoFixture,
31 DecodeDoubleWithNegativeDoubleReturnsIsNegTrue) {
32 double input = -100.0;
33 bool is_neg;
34 int exp;
35 int64_t mantissa;
36 decodeDouble(input, &is_neg, &exp, &mantissa);
37 EXPECT_EQ(is_neg, true);
38}
39
40TEST(FloatBuiltinsTestNoFixture,
41 DecodeDoubleWithMaximumExponentReturnsCorrectValue) {
42 double input = std::strtod("0x1.0p+1024", nullptr);
43 bool is_neg;
44 int exp;
45 int64_t mantissa;
46 decodeDouble(input, &is_neg, &exp, &mantissa);
47 EXPECT_EQ(exp, 1024);
48}
49
50TEST(FloatBuiltinsTestNoFixture,
51 DecodeDoubleWithMinimumExponentReturnsCorrectValue) {
52 double input = std::strtod("0x1.0p-1023", nullptr);
53 bool is_neg;
54 int exp;
55 int64_t mantissa;
56 decodeDouble(input, &is_neg, &exp, &mantissa);
57 EXPECT_EQ(exp, -1023);
58}
59
60TEST(FloatBuiltinsTestNoFixture, DecodeDoubleWithMantissaReturnsCorrectValue) {
61 double input = std::strtod("0x1.29ef685b3f6fbp+52", nullptr);
62 bool is_neg;
63 int exp;
64 int64_t mantissa;
65 decodeDouble(input, &is_neg, &exp, &mantissa);
66 EXPECT_EQ(mantissa, 0x29ef685b3f6fb);
67}
68
69TEST_F(FloatBuiltinsTest, DunderMulWithDoubleReturnsDouble) {
70 HandleScope scope(thread_);
71 Float left(&scope, runtime_->newFloat(2.0));
72 Float right(&scope, runtime_->newFloat(1.5));
73 Object result(&scope, runBuiltin(METH(float, __mul__), left, right));
74 EXPECT_TRUE(isFloatEqualsDouble(*result, 3.0));
75}
76
77TEST_F(FloatBuiltinsTest, DunderMulWithSmallIntReturnsDouble) {
78 HandleScope scope(thread_);
79 Float left(&scope, runtime_->newFloat(2.5));
80 Int right(&scope, runtime_->newInt(1));
81 Object result(&scope, runBuiltin(METH(float, __mul__), left, right));
82 EXPECT_TRUE(isFloatEqualsDouble(*result, 2.5));
83}
84
85TEST_F(FloatBuiltinsTest, DunderMulWithNonFloatSelfRaisesTypeError) {
86 HandleScope scope(thread_);
87 Object left(&scope, NoneType::object());
88 Float right(&scope, runtime_->newFloat(1.0));
89 Object result(&scope, runBuiltin(METH(float, __mul__), left, right));
90 EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
91}
92
93TEST_F(FloatBuiltinsTest, DunderMulWithNonFloatOtherReturnsNotImplemented) {
94 HandleScope scope(thread_);
95 Float left(&scope, runtime_->newFloat(1.0));
96 Object right(&scope, NoneType::object());
97 Object result(&scope, runBuiltin(METH(float, __mul__), left, right));
98 EXPECT_TRUE(result.isNotImplementedType());
99}
100
101TEST_F(FloatBuiltinsTest, DunderNeWithInequalFloatsReturnsTrue) {
102 ASSERT_FALSE(
103 runFromCStr(runtime_, "result = float.__ne__(12.2, 2.12)").isError());
104 EXPECT_EQ(mainModuleAt(runtime_, "result"), Bool::trueObj());
105}
106
107TEST_F(FloatBuiltinsTest, DunderNeWithEqualFloatIntReturnsFalse) {
108 ASSERT_FALSE(
109 runFromCStr(runtime_, "result = float.__ne__(34.0, 34)").isError());
110 EXPECT_EQ(mainModuleAt(runtime_, "result"), Bool::falseObj());
111}
112
113TEST_F(FloatBuiltinsTest, DunderNeWithStringReturnsNotImplemented) {
114 ASSERT_FALSE(
115 runFromCStr(runtime_, "result = float.__ne__(5.5, '')").isError());
116 EXPECT_TRUE(mainModuleAt(runtime_, "result").isNotImplementedType());
117}
118
119TEST_F(FloatBuiltinsTest, DunderAbsZeroReturnsZero) {
120 HandleScope scope(thread_);
121 Float self(&scope, runtime_->newFloat(0.0));
122 Object result(&scope, runBuiltin(METH(float, __abs__), self));
123 EXPECT_TRUE(isFloatEqualsDouble(*result, 0.0));
124}
125
126TEST_F(FloatBuiltinsTest, DunderAbsNegativeReturnsPositive) {
127 HandleScope scope(thread_);
128 Float self(&scope, runtime_->newFloat(-1234.0));
129 Object result(&scope, runBuiltin(METH(float, __abs__), self));
130 EXPECT_TRUE(isFloatEqualsDouble(*result, 1234.0));
131}
132
133TEST_F(FloatBuiltinsTest, DunderAbsPositiveReturnsPositive) {
134 HandleScope scope(thread_);
135 Float self(&scope, runtime_->newFloat(5678.0));
136 Object result(&scope, runBuiltin(METH(float, __abs__), self));
137 EXPECT_TRUE(isFloatEqualsDouble(*result, 5678.0));
138}
139
140TEST_F(FloatBuiltinsTest, BinaryAddDouble) {
141 HandleScope scope(thread_);
142
143 ASSERT_FALSE(runFromCStr(runtime_, R"(
144a = 2.0
145b = 1.5
146c = a + b
147)")
148 .isError());
149
150 Object c(&scope, mainModuleAt(runtime_, "c"));
151 EXPECT_TRUE(isFloatEqualsDouble(*c, 3.5));
152}
153
154TEST_F(FloatBuiltinsTest, BinaryAddSmallInt) {
155 HandleScope scope(thread_);
156
157 ASSERT_FALSE(runFromCStr(runtime_, R"(
158a = 2.5
159b = 1
160c = a + b
161)")
162 .isError());
163
164 Object c(&scope, mainModuleAt(runtime_, "c"));
165 EXPECT_TRUE(isFloatEqualsDouble(*c, 3.5));
166}
167
168TEST_F(FloatBuiltinsTest, AddWithNonFloatOtherRaisesTypeError) {
169 const char* src = R"(
1701.0 + None
171)";
172 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, src), LayoutId::kTypeError,
173 "float.__add__(NoneType) is not supported"));
174}
175
176TEST_F(FloatBuiltinsTest, DunderAddWithFloatSubclassReturnsFloatSum) {
177 HandleScope scope(thread_);
178 EXPECT_FALSE(runFromCStr(runtime_, R"(
179class SubFloat(float):
180 pass
181
182left = SubFloat(1.0)
183right = SubFloat(2.0)
184)")
185 .isError());
186 Object left(&scope, mainModuleAt(runtime_, "left"));
187 Object right(&scope, mainModuleAt(runtime_, "right"));
188 Object result(&scope, runBuiltin(METH(float, __add__), left, right));
189 EXPECT_TRUE(isFloatEqualsDouble(*result, 3.0));
190}
191
192TEST_F(FloatBuiltinsTest, DunderBoolWithZeroReturnsFalse) {
193 HandleScope scope(thread_);
194 Float self(&scope, runtime_->newFloat(0.0));
195 Object result(&scope, runBuiltin(METH(float, __bool__), self));
196 EXPECT_EQ(*result, Bool::falseObj());
197}
198
199TEST_F(FloatBuiltinsTest, DunderBoolWithNonZeroReturnsTrue) {
200 HandleScope scope(thread_);
201 Float self(&scope, runtime_->newFloat(1234.0));
202 Object result(&scope, runBuiltin(METH(float, __bool__), self));
203 EXPECT_EQ(*result, Bool::trueObj());
204}
205
206TEST_F(FloatBuiltinsTest, DunderTrueDivWithDoubleReturnsDouble) {
207 HandleScope scope(thread_);
208 Float left(&scope, runtime_->newFloat(3.0));
209 Float right(&scope, runtime_->newFloat(2.0));
210 Object result(&scope, runBuiltin(METH(float, __truediv__), left, right));
211 EXPECT_TRUE(isFloatEqualsDouble(*result, 1.5));
212}
213
214TEST_F(FloatBuiltinsTest, DunderTrueDivWithSmallIntReturnsDouble) {
215 HandleScope scope(thread_);
216 Float left(&scope, runtime_->newFloat(3.0));
217 Int right(&scope, runtime_->newInt(2));
218 Object result(&scope, runBuiltin(METH(float, __truediv__), left, right));
219 EXPECT_TRUE(isFloatEqualsDouble(*result, 1.5));
220}
221
222TEST_F(FloatBuiltinsTest, DunderTrueDivWithNonFloatSelfRaisesTypeError) {
223 HandleScope scope(thread_);
224 Object left(&scope, NoneType::object());
225 Float right(&scope, runtime_->newFloat(1.0));
226 Object result(&scope, runBuiltin(METH(float, __truediv__), left, right));
227 EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
228}
229
230TEST_F(FloatBuiltinsTest, DunderTrueDivWithNonFloatOtherReturnsNotImplemented) {
231 HandleScope scope(thread_);
232 Float left(&scope, runtime_->newFloat(1.0));
233 Object right(&scope, NoneType::object());
234 Object result(&scope, runBuiltin(METH(float, __truediv__), left, right));
235 EXPECT_TRUE(result.isNotImplementedType());
236}
237
238TEST_F(FloatBuiltinsTest, DunderTrueDivWithZeroFloatRaisesZeroDivisionError) {
239 HandleScope scope(thread_);
240 Float left(&scope, runtime_->newFloat(1.0));
241 Float right(&scope, runtime_->newFloat(0.0));
242 Object result(&scope, runBuiltin(METH(float, __truediv__), left, right));
243 EXPECT_TRUE(raised(*result, LayoutId::kZeroDivisionError));
244}
245
246TEST_F(FloatBuiltinsTest,
247 DunderTrueDivWithZeroSmallIntRaisesZeroDivisionError) {
248 HandleScope scope(thread_);
249 Float left(&scope, runtime_->newFloat(1.0));
250 Int right(&scope, runtime_->newInt(0));
251 Object result(&scope, runBuiltin(METH(float, __truediv__), left, right));
252 EXPECT_TRUE(raised(*result, LayoutId::kZeroDivisionError));
253}
254
255TEST_F(FloatBuiltinsTest, DunderTrueDivWithZeroBoolRaisesZeroDivisionError) {
256 HandleScope scope(thread_);
257 Float left(&scope, runtime_->newFloat(1.0));
258 Bool right(&scope, RawBool::falseObj());
259 Object result(&scope, runBuiltin(METH(float, __truediv__), left, right));
260 EXPECT_TRUE(raised(*result, LayoutId::kZeroDivisionError));
261}
262
263TEST_F(FloatBuiltinsTest, DunderRtruedivWithDoubleReturnsDouble) {
264 HandleScope scope(thread_);
265 Float left(&scope, runtime_->newFloat(2.0));
266 Float right(&scope, runtime_->newFloat(3.0));
267 Object result(&scope, runBuiltin(METH(float, __rtruediv__), left, right));
268 EXPECT_TRUE(isFloatEqualsDouble(*result, 1.5));
269}
270
271TEST_F(FloatBuiltinsTest, DunderRtruedivWithSmallIntReturnsDouble) {
272 HandleScope scope(thread_);
273 Float left(&scope, runtime_->newFloat(2.0));
274 Int right(&scope, runtime_->newInt(3));
275 Object result(&scope, runBuiltin(METH(float, __rtruediv__), left, right));
276 EXPECT_TRUE(isFloatEqualsDouble(*result, 1.5));
277}
278
279TEST_F(FloatBuiltinsTest, DunderRtruedivWithNonFloatSelfRaisesTypeError) {
280 HandleScope scope(thread_);
281 Object left(&scope, NoneType::object());
282 Float right(&scope, runtime_->newFloat(1.0));
283 Object result(&scope, runBuiltin(METH(float, __rtruediv__), left, right));
284 EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
285}
286
287TEST_F(FloatBuiltinsTest,
288 DunderRtruedivWithNonFloatOtherReturnsNotImplemented) {
289 HandleScope scope(thread_);
290 Float left(&scope, runtime_->newFloat(1.0));
291 Object right(&scope, NoneType::object());
292 Object result(&scope, runBuiltin(METH(float, __rtruediv__), left, right));
293 EXPECT_TRUE(result.isNotImplementedType());
294}
295
296TEST_F(FloatBuiltinsTest, DunderRtruedivWithZeroFloatRaisesZeroDivisionError) {
297 HandleScope scope(thread_);
298 Float left(&scope, runtime_->newFloat(0.0));
299 Float right(&scope, runtime_->newFloat(1.0));
300 Object result(&scope, runBuiltin(METH(float, __rtruediv__), left, right));
301 EXPECT_TRUE(raised(*result, LayoutId::kZeroDivisionError));
302}
303
304TEST_F(FloatBuiltinsTest, BinarySubtractDouble) {
305 HandleScope scope(thread_);
306
307 ASSERT_FALSE(runFromCStr(runtime_, R"(
308a = 2.0
309b = 1.5
310c = a - b
311)")
312 .isError());
313
314 Object c(&scope, mainModuleAt(runtime_, "c"));
315 EXPECT_TRUE(isFloatEqualsDouble(*c, 0.5));
316}
317
318TEST_F(FloatBuiltinsTest, BinarySubtractSmallInt) {
319 HandleScope scope(thread_);
320
321 ASSERT_FALSE(runFromCStr(runtime_, R"(
322a = 2.5
323b = 1
324c = a - b
325)")
326 .isError());
327
328 Object c(&scope, mainModuleAt(runtime_, "c"));
329 EXPECT_TRUE(isFloatEqualsDouble(*c, 1.5));
330}
331
332TEST_F(FloatBuiltinsTest, FloatSubclassKeepsFloatInMro) {
333 const char* src = R"(
334class Test(float):
335 pass
336)";
337 HandleScope scope(thread_);
338 ASSERT_FALSE(runFromCStr(runtime_, src).isError());
339 Object value(&scope, mainModuleAt(runtime_, "Test"));
340 ASSERT_TRUE(value.isType());
341
342 Type type(&scope, *value);
343 ASSERT_TRUE(type.mro().isTuple());
344
345 Tuple mro(&scope, type.mro());
346 ASSERT_EQ(mro.length(), 3);
347 EXPECT_EQ(mro.at(0), *type);
348 EXPECT_EQ(mro.at(1), runtime_->typeAt(LayoutId::kFloat));
349 EXPECT_EQ(mro.at(2), runtime_->typeAt(LayoutId::kObject));
350}
351
352TEST_F(FloatBuiltinsTest, PowFloatAndFloat) {
353 ASSERT_FALSE(runFromCStr(runtime_, R"(
354base = 2.0
355x = base ** 4.0
356)")
357 .isError());
358 EXPECT_TRUE(isFloatEqualsDouble(mainModuleAt(runtime_, "x"), 16.0));
359}
360
361TEST_F(FloatBuiltinsTest, PowFloatAndInt) {
362 ASSERT_FALSE(runFromCStr(runtime_, R"(
363base = 2.0
364x = base ** 4
365)")
366 .isError());
367 EXPECT_TRUE(isFloatEqualsDouble(mainModuleAt(runtime_, "x"), 16.0));
368}
369
370TEST_F(FloatBuiltinsTest, InplacePowFloatAndFloat) {
371 ASSERT_FALSE(runFromCStr(runtime_, R"(
372x = 2.0
373x **= 4.0
374)")
375 .isError());
376 EXPECT_TRUE(isFloatEqualsDouble(mainModuleAt(runtime_, "x"), 16.0));
377}
378
379TEST_F(FloatBuiltinsTest, InplacePowFloatAndInt) {
380 ASSERT_FALSE(runFromCStr(runtime_, R"(
381x = 2.0
382x **= 4
383)")
384 .isError());
385 EXPECT_TRUE(isFloatEqualsDouble(mainModuleAt(runtime_, "x"), 16.0));
386}
387
388TEST_F(FloatBuiltinsTest, SubWithNonFloatOtherRaisesTypeError) {
389 const char* src = R"(
3901.0 - None
391)";
392 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, src), LayoutId::kTypeError,
393 "float.__sub__(NoneType) is not supported"));
394}
395
396TEST_F(FloatBuiltinsTest, DunderEqWithFloatsReturnsBool) {
397 HandleScope scope(thread_);
398 Object nan(&scope, runtime_->newFloat(kDoubleNaN));
399 Object f0(&scope, runtime_->newFloat(1.0));
400 Object f1(&scope, runtime_->newFloat(-42.5));
401 Object zero(&scope, runtime_->newFloat(0.0));
402 Object neg_zero(&scope, runtime_->newFloat(-0.0));
403 Object null(&scope, runtime_->newInt(0));
404 EXPECT_EQ(runBuiltin(METH(float, __eq__), f0, f0), Bool::trueObj());
405 EXPECT_EQ(runBuiltin(METH(float, __eq__), f0, f1), Bool::falseObj());
406 EXPECT_EQ(runBuiltin(METH(float, __eq__), nan, nan), Bool::falseObj());
407 EXPECT_EQ(runBuiltin(METH(float, __eq__), zero, neg_zero), Bool::trueObj());
408 EXPECT_EQ(runBuiltin(METH(float, __eq__), neg_zero, null), Bool::trueObj());
409}
410
411TEST_F(FloatBuiltinsTest, DunderEqWithIntSubclassReturnsBool) {
412 HandleScope scope(thread_);
413 ASSERT_FALSE(runFromCStr(runtime_, R"(
414class C(int): pass
415zero = C()
416one = C(1)
417two = C(2)
418)")
419 .isError());
420 Object self(&scope, runtime_->newFloat(1.0));
421 Object zero(&scope, mainModuleAt(runtime_, "zero"));
422 Object one(&scope, mainModuleAt(runtime_, "one"));
423 Object two(&scope, mainModuleAt(runtime_, "two"));
424 EXPECT_EQ(runBuiltin(METH(float, __eq__), self, zero), Bool::falseObj());
425 EXPECT_EQ(runBuiltin(METH(float, __eq__), self, one), Bool::trueObj());
426 EXPECT_EQ(runBuiltin(METH(float, __eq__), self, two), Bool::falseObj());
427}
428
429TEST_F(FloatBuiltinsTest, DunderEqWithSmallIntExactReturnsBool) {
430 HandleScope scope(thread_);
431 Object float0(&scope, runtime_->newFloat(31.0));
432 Object float1(&scope, runtime_->newFloat(31.125));
433 Object int0(&scope, runtime_->newFloat(31));
434 EXPECT_EQ(runBuiltin(METH(float, __eq__), float0, int0), Bool::trueObj());
435 EXPECT_EQ(runBuiltin(METH(float, __eq__), float1, int0), Bool::falseObj());
436 word mantissa_max = (word{1} << (kDoubleMantissaBits + 1)) - 1;
437 Object max_float(&scope,
438 runtime_->newFloat(static_cast<double>(mantissa_max)));
439 Object max_int(&scope, runtime_->newFloat(mantissa_max));
440 EXPECT_EQ(runBuiltin(METH(float, __eq__), max_float, max_int),
441 Bool::trueObj());
442 Object neg_max_float(&scope,
443 runtime_->newFloat(static_cast<double>(-mantissa_max)));
444 Object neg_max_int(&scope, runtime_->newInt(-mantissa_max));
445 EXPECT_EQ(runBuiltin(METH(float, __eq__), neg_max_float, neg_max_int),
446 Bool::trueObj());
447
448 word big0 = word(1) << (kDoubleMantissaBits + 2);
449 ASSERT_EQ(static_cast<double>(big0), static_cast<double>(big0) + 1.0);
450 Object big0_float(&scope, runtime_->newFloat(static_cast<double>(big0)));
451 Int big0_int(&scope, runtime_->newInt(big0));
452 EXPECT_EQ(runBuiltin(METH(float, __eq__), big0_float, big0_int),
453 Bool::trueObj());
454
455 word big1 = (word(1) << (kDoubleMantissaBits + 1)) | (word(1) << 11);
456 ASSERT_EQ(static_cast<double>(big1), static_cast<double>(big1) + 1.0);
457 Object big1_float(&scope, runtime_->newFloat(static_cast<double>(big1)));
458 Int big1_int(&scope, runtime_->newInt(big1));
459 EXPECT_EQ(runBuiltin(METH(float, __eq__), big1_float, big1_int),
460 Bool::trueObj());
461}
462
463TEST_F(FloatBuiltinsTest, DunderEqWithSmallIntInexactReturnsFalse) {
464 HandleScope scope(thread_);
465 word big = (word(1) << (kDoubleMantissaBits + 4)) + 3;
466 ASSERT_EQ(static_cast<double>(big), static_cast<double>(big) + 3.0);
467 Object big_float(&scope, runtime_->newFloat(static_cast<double>(big)));
468 Int big_int(&scope, runtime_->newInt(big));
469 EXPECT_EQ(runBuiltin(METH(float, __eq__), big_float, big_int),
470 Bool::falseObj());
471}
472
473TEST_F(FloatBuiltinsTest, DunderEqWithLargeIntExactReturnsTrue) {
474 HandleScope scope(thread_);
475 const uword digits[] = {0, 1};
476 Object int0(&scope, runtime_->newLargeIntWithDigits(digits));
477 Object float0(&scope, runtime_->newFloat(std::strtod("0x1p64", nullptr)));
478 EXPECT_EQ(runBuiltin(METH(float, __eq__), float0, int0), Bool::trueObj());
479}
480
481TEST_F(FloatBuiltinsTest, DunderEqWithLargeIntInexactReturnsFalse) {
482 HandleScope scope(thread_);
483 const uword digits[] = {0x800, 1};
484 Object int0(&scope, runtime_->newLargeIntWithDigits(digits));
485 Object float0(&scope, runtime_->newFloat(std::strtod("0x1p64", nullptr)));
486 ASSERT_EQ(Float::cast(runBuiltin(METH(int, __float__), int0)).value(),
487 Float::cast(*float0).value());
488 EXPECT_EQ(runBuiltin(METH(float, __eq__), float0, int0), Bool::falseObj());
489}
490
491TEST_F(FloatBuiltinsTest, DunderEqWithNonFiniteFloatIntReturnsFalse) {
492 HandleScope scope(thread_);
493 Object nan(&scope, runtime_->newFloat(kDoubleNaN));
494 Object inf(&scope,
495 runtime_->newFloat(std::numeric_limits<double>::infinity()));
496 Object int0(&scope, runtime_->newInt(7));
497 uword digits[100] = {};
498 digits[99] = 1;
499 Object int1(&scope, runtime_->newLargeIntWithDigits(digits));
500 EXPECT_EQ(runBuiltin(METH(float, __eq__), nan, int0), Bool::falseObj());
501 EXPECT_EQ(runBuiltin(METH(float, __eq__), inf, int0), Bool::falseObj());
502 EXPECT_EQ(runBuiltin(METH(float, __eq__), nan, int1), Bool::falseObj());
503 EXPECT_EQ(runBuiltin(METH(float, __eq__), inf, int1), Bool::falseObj());
504}
505
506TEST_F(FloatBuiltinsTest, DunderEqWithFloatOverflowingIntReturnsFalse) {
507 HandleScope scope(thread_);
508 Object float0(&scope, runtime_->newFloat(8.25));
509 uword digits[100] = {};
510 digits[99] = 1;
511 Object int0(&scope, runtime_->newLargeIntWithDigits(digits));
512 EXPECT_EQ(runBuiltin(METH(float, __eq__), float0, int0), Bool::falseObj());
513}
514
515TEST_F(FloatBuiltinsTest, DunderFloatWithFloatLiteralReturnsSameObject) {
516 HandleScope scope(thread_);
517
518 ASSERT_FALSE(runFromCStr(runtime_, "a = (7.0).__float__()").isError());
519 Object a(&scope, mainModuleAt(runtime_, "a"));
520 EXPECT_TRUE(isFloatEqualsDouble(*a, 7.0));
521}
522
523TEST_F(FloatBuiltinsTest, DunderFloatFromFloatClassReturnsSameValue) {
524 HandleScope scope(thread_);
525
526 Float a_float(&scope, runtime_->newFloat(7.0));
527 Object a(&scope, runBuiltin(METH(float, __float__), a_float));
528 EXPECT_TRUE(isFloatEqualsDouble(*a, 7.0));
529}
530
531TEST_F(FloatBuiltinsTest, DunderFloatWithFloatSubclassReturnsSameValue) {
532 HandleScope scope(thread_);
533
534 ASSERT_FALSE(runFromCStr(runtime_, R"(
535class FloatSub(float):
536 pass
537a = FloatSub(1.0).__float__())")
538 .isError());
539 Object a(&scope, mainModuleAt(runtime_, "a"));
540 EXPECT_TRUE(isFloatEqualsDouble(*a, 1.0));
541}
542
543TEST_F(FloatBuiltinsTest, DunderFloatWithNonFloatReturnsError) {
544 HandleScope scope(thread_);
545
546 Int i(&scope, runtime_->newInt(1));
547 Object i_res(&scope, runBuiltin(METH(float, __float__), i));
548 EXPECT_TRUE(raised(*i_res, LayoutId::kTypeError));
549}
550
551TEST_F(FloatBuiltinsTest, DunderGeWithFloatReturnsBool) {
552 HandleScope scope(thread_);
553 Object float0(&scope, runtime_->newFloat(1.7));
554 Object float1(&scope, runtime_->newFloat(0.2));
555 EXPECT_EQ(runBuiltin(METH(float, __ge__), float0, float1), Bool::trueObj());
556 EXPECT_EQ(runBuiltin(METH(float, __ge__), float0, float0), Bool::trueObj());
557 EXPECT_EQ(runBuiltin(METH(float, __ge__), float1, float0), Bool::falseObj());
558}
559
560TEST_F(FloatBuiltinsTest, DunderGeWithIntSelfNanReturnsFalse) {
561 HandleScope scope(thread_);
562 Object left(&scope, runtime_->newFloat(kDoubleNaN));
563 const uword digits[] = {0, 1};
564 Object right(&scope, runtime_->newLargeIntWithDigits(digits));
565 EXPECT_EQ(runBuiltin(METH(float, __ge__), left, right), Bool::falseObj());
566}
567
568TEST_F(FloatBuiltinsTest, DunderGeWithNonFloatReturnsNotImplemented) {
569 HandleScope scope(thread_);
570 Object left(&scope, runtime_->newFloat(0.0));
571 Object right(&scope, Str::empty());
572 EXPECT_TRUE(
573 runBuiltin(METH(float, __ge__), left, right).isNotImplementedType());
574}
575
576TEST_F(FloatBuiltinsTest, DunderGeWithSmallIntReturnsBool) {
577 HandleScope scope(thread_);
578 Object float0(&scope, runtime_->newFloat(5.0));
579 Object int0(&scope, runtime_->newInt(4));
580 Object int1(&scope, runtime_->newInt(5));
581 Object int2(&scope, runtime_->newInt(6));
582 EXPECT_EQ(runBuiltin(METH(float, __ge__), float0, int0), Bool::trueObj());
583 EXPECT_EQ(runBuiltin(METH(float, __ge__), float0, int1), Bool::trueObj());
584 EXPECT_EQ(runBuiltin(METH(float, __ge__), float0, int2), Bool::falseObj());
585}
586
587TEST_F(FloatBuiltinsTest, DunderGeWithSmallIntExactReturnsBool) {
588 HandleScope scope(thread_);
589 Object float0(&scope, runtime_->newFloat(44.));
590 Object int0(&scope, runtime_->newInt(44));
591 EXPECT_EQ(runBuiltin(METH(float, __ge__), float0, int0), Bool::trueObj());
592 Object float1(&scope, runtime_->newFloat(-3.));
593 Object int1(&scope, runtime_->newInt(1));
594 EXPECT_EQ(runBuiltin(METH(float, __ge__), float1, int1), Bool::falseObj());
595
596 Object float2(&scope, runtime_->newFloat(0x20000000000000));
597 Object int2(&scope, runtime_->newInt(0x20000000000000));
598 EXPECT_EQ(runBuiltin(METH(float, __ge__), float2, int2), Bool::trueObj());
599}
600
601TEST_F(FloatBuiltinsTest, DunderGeWithSmallIntInexactReturnsBool) {
602 HandleScope scope(thread_);
603 Object float0(&scope,
604 runtime_->newFloat(static_cast<double>(0x20000000000001)));
605 Object int0(&scope, runtime_->newInt(0x20000000000001));
606 EXPECT_EQ(runBuiltin(METH(float, __ge__), float0, int0), Bool::falseObj());
607 Object float1(&scope,
608 runtime_->newFloat(static_cast<double>(0x20000000000003)));
609 Object int1(&scope, runtime_->newInt(0x20000000000003));
610 EXPECT_EQ(runBuiltin(METH(float, __ge__), float1, int1), Bool::trueObj());
611 Object float2(&scope,
612 runtime_->newFloat(static_cast<double>(0x100000000000011)));
613 Object int2(&scope, runtime_->newInt(0x100000000000011));
614 EXPECT_EQ(runBuiltin(METH(float, __ge__), float2, int2), Bool::falseObj());
615}
616
617TEST_F(FloatBuiltinsTest, DunderGeWithLargeIntDifferingSignReturnsBool) {
618 HandleScope scope(thread_);
619 Object float0(&scope, runtime_->newFloat(-1.0));
620 const uword digits0[] = {0, 1};
621 Object int0(&scope, runtime_->newLargeIntWithDigits(digits0));
622 EXPECT_EQ(runBuiltin(METH(float, __ge__), float0, int0), Bool::falseObj());
623 Object float1(&scope, runtime_->newFloat(1.0));
624 const uword digits1[] = {0, kMaxUword};
625 Object int1(&scope, runtime_->newLargeIntWithDigits(digits1));
626 EXPECT_EQ(runBuiltin(METH(float, __ge__), float1, int1), Bool::trueObj());
627}
628
629TEST_F(FloatBuiltinsTest, DunderGeWithLargeIntExactEqualsReturnsTrue) {
630 HandleScope scope(thread_);
631 Object float0(&scope, runtime_->newFloat(std::strtod("0x1p64", nullptr)));
632 const uword digits[] = {0, 1};
633 Object int0(&scope, runtime_->newLargeIntWithDigits(digits));
634 EXPECT_EQ(runBuiltin(METH(float, __ge__), float0, int0), Bool::trueObj());
635}
636
637TEST_F(FloatBuiltinsTest, DunderGeWithLargeIntRoundingDownReturnsFalse) {
638 HandleScope scope(thread_);
639 Object float0(&scope, runtime_->newFloat(std::strtod("0x1p64", nullptr)));
640 const uword digits[] = {1, 1};
641 Object int0(&scope, runtime_->newLargeIntWithDigits(digits));
642 ASSERT_EQ(Float::cast(runBuiltin(METH(int, __float__), int0)).value(),
643 Float::cast(*float0).value());
644 EXPECT_EQ(runBuiltin(METH(float, __ge__), float0, int0), Bool::falseObj());
645}
646
647TEST_F(FloatBuiltinsTest, DunderGeWithLargeIntRoundingUpReturnsTrue) {
648 HandleScope scope(thread_);
649 Object float0(&scope, runtime_->newFloat(std::strtod("0x1p64", nullptr)));
650 const uword digits[] = {kMaxUword, 0};
651 Object int0(&scope, runtime_->newLargeIntWithDigits(digits));
652 ASSERT_EQ(Float::cast(runBuiltin(METH(int, __float__), int0)).value(),
653 Float::cast(*float0).value());
654 EXPECT_EQ(runBuiltin(METH(float, __ge__), float0, int0), Bool::trueObj());
655}
656
657TEST_F(FloatBuiltinsTest, DunderGeWithIntSubclassReturnsBool) {
658 HandleScope scope(thread_);
659 ASSERT_FALSE(runFromCStr(runtime_, R"(
660class C(int): pass
661zero = C()
662one = C(1)
663two = C(2)
664)")
665 .isError());
666 Object self(&scope, runtime_->newFloat(1.0));
667 Object zero(&scope, mainModuleAt(runtime_, "zero"));
668 Object one(&scope, mainModuleAt(runtime_, "one"));
669 Object two(&scope, mainModuleAt(runtime_, "two"));
670 EXPECT_EQ(runBuiltin(METH(float, __ge__), self, zero), Bool::trueObj());
671 EXPECT_EQ(runBuiltin(METH(float, __ge__), self, one), Bool::trueObj());
672 EXPECT_EQ(runBuiltin(METH(float, __ge__), self, two), Bool::falseObj());
673}
674
675TEST_F(FloatBuiltinsTest, DunderGtWithFloatReturnsBool) {
676 HandleScope scope(thread_);
677 Object float0(&scope, runtime_->newFloat(8.3));
678 Object float1(&scope, runtime_->newFloat(1.7));
679 EXPECT_EQ(runBuiltin(METH(float, __gt__), float0, float1), Bool::trueObj());
680 EXPECT_EQ(runBuiltin(METH(float, __gt__), float0, float0), Bool::falseObj());
681 EXPECT_EQ(runBuiltin(METH(float, __gt__), float1, float0), Bool::falseObj());
682}
683
684TEST_F(FloatBuiltinsTest, DunderGtWithIntSelfNanReturnsFalse) {
685 HandleScope scope(thread_);
686 Object left(&scope, runtime_->newFloat(kDoubleNaN));
687 const uword digits[] = {0, 1};
688 Object right(&scope, runtime_->newLargeIntWithDigits(digits));
689 EXPECT_EQ(runBuiltin(METH(float, __gt__), left, right), Bool::falseObj());
690}
691
692TEST_F(FloatBuiltinsTest, DunderGtWithNonFloatReturnsNotImplemented) {
693 HandleScope scope(thread_);
694 Object left(&scope, runtime_->newFloat(0.0));
695 Object right(&scope, Str::empty());
696 EXPECT_TRUE(
697 runBuiltin(METH(float, __gt__), left, right).isNotImplementedType());
698}
699
700TEST_F(FloatBuiltinsTest, DunderGtWithSmallIntReturnsBool) {
701 HandleScope scope(thread_);
702 Object float0(&scope, runtime_->newFloat(5.0));
703 Object int0(&scope, runtime_->newInt(4));
704 Object int1(&scope, runtime_->newInt(5));
705 EXPECT_EQ(runBuiltin(METH(float, __gt__), float0, int0), Bool::trueObj());
706 EXPECT_EQ(runBuiltin(METH(float, __gt__), float0, int1), Bool::falseObj());
707}
708
709TEST_F(FloatBuiltinsTest, DunderGtWithIntSubclassReturnsBool) {
710 HandleScope scope(thread_);
711 ASSERT_FALSE(runFromCStr(runtime_, R"(
712class C(int): pass
713zero = C()
714one = C(1)
715two = C(2)
716)")
717 .isError());
718 Object self(&scope, runtime_->newFloat(1.0));
719 Object zero(&scope, mainModuleAt(runtime_, "zero"));
720 Object one(&scope, mainModuleAt(runtime_, "one"));
721 Object two(&scope, mainModuleAt(runtime_, "two"));
722 EXPECT_EQ(runBuiltin(METH(float, __gt__), self, zero), Bool::trueObj());
723 EXPECT_EQ(runBuiltin(METH(float, __gt__), self, one), Bool::falseObj());
724 EXPECT_EQ(runBuiltin(METH(float, __gt__), self, two), Bool::falseObj());
725}
726
727TEST_F(FloatBuiltinsTest, DunderIntWithInfinityRaisesOverflowError) {
728 HandleScope scope(thread_);
729 Object input_obj(&scope,
730 runtime_->newFloat(std::numeric_limits<double>::infinity()));
731 Object result_obj(&scope, runBuiltin(METH(float, __int__), input_obj));
732 EXPECT_TRUE(raisedWithStr(*result_obj, LayoutId::kOverflowError,
733 "cannot convert float infinity to integer"));
734}
735
736TEST_F(FloatBuiltinsTest, DunderIntWithNaNRaisesOverflowError) {
737 HandleScope scope(thread_);
738 Object input_obj(&scope, runtime_->newFloat(kDoubleNaN));
739 Object result_obj(&scope, runBuiltin(METH(float, __int__), input_obj));
740 EXPECT_TRUE(raisedWithStr(*result_obj, LayoutId::kValueError,
741 "cannot convert float NaN to integer"));
742}
743
744TEST_F(FloatBuiltinsTest, DunderIntWithZeroReturnsSmallInt) {
745 HandleScope scope(thread_);
746 Object input_obj(&scope, runtime_->newFloat(0.0));
747 Object result_obj(&scope, runBuiltin(METH(float, __int__), input_obj));
748 ASSERT_TRUE(result_obj.isSmallInt());
749 SmallInt result(&scope, *result_obj);
750 EXPECT_EQ(result.value(), 0);
751}
752
753TEST_F(
754 FloatBuiltinsTest,
755 DunderIntWithNegativeNumOfGreatestMagnitudeFitInWordReturnsLargeIntOfSingleWord) {
756 HandleScope scope(thread_);
757 double input_value = std::strtod("-0x1.0000000000000p+63", nullptr);
758 Object input_obj(&scope, runtime_->newFloat(input_value));
759 Object result_obj(&scope, runBuiltin(METH(float, __int__), input_obj));
760 ASSERT_TRUE(result_obj.isLargeInt());
761 LargeInt result(&scope, *result_obj);
762 EXPECT_TRUE(result.isNegative());
763 const uword expected_digits[] = {uword{0x8000000000000000}};
764 EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
765}
766
767TEST_F(FloatBuiltinsTest, DunderIntWithSmallIntMinValueReturnsSmallInt) {
768 HandleScope scope(thread_);
769 double input_value = double{SmallInt::kMinValue};
770 // Make sure that the converted double value can fit in SmallInt if
771 // it gets converted back to word.
772 EXPECT_EQ(static_cast<word>(input_value), SmallInt::kMinValue);
773 Object input_obj(&scope, runtime_->newFloat(input_value));
774 Object result_obj(&scope, runBuiltin(METH(float, __int__), input_obj));
775 EXPECT_TRUE(result_obj.isSmallInt());
776 SmallInt result(&scope, *result_obj);
777 EXPECT_EQ(result.value(), static_cast<word>(input_value));
778}
779
780TEST_F(FloatBuiltinsTest,
781 DunderIntWithValueLessThanSmallIntMinValueReturnsLargeInt) {
782 HandleScope scope(thread_);
783 // Due to the truncation error, static_cast<double>(SmallInt::kMinValue - i)
784 // == SmallInt::kMinValue for i ranging from 0 to 512.
785 ASSERT_EQ(static_cast<word>(static_cast<double>(SmallInt::kMinValue - 512)),
786 SmallInt::kMinValue);
787 ASSERT_LT(static_cast<word>(static_cast<double>(SmallInt::kMinValue - 513)),
788 SmallInt::kMinValue - 1);
789 double input_value = static_cast<double>(SmallInt::kMinValue) - 513;
790 Object input_obj(&scope, runtime_->newFloat(input_value));
791 Object result_obj(&scope, runBuiltin(METH(float, __int__), input_obj));
792 EXPECT_TRUE(result_obj.isLargeInt());
793}
794
795TEST_F(FloatBuiltinsTest, DunderIntWithSmallIntMaxValueReturnsSmallInt) {
796 HandleScope scope(thread_);
797 // Due to the truncation error, static_cast<double>(SmallInt::kMaxValue) -i)
798 // == SmallInt::kMaxValue + 1 for i ranging from 0 to 255, which makes them
799 // not fit in SmallInt.
800 ASSERT_EQ(static_cast<word>(static_cast<double>(SmallInt::kMaxValue - 255)),
801 SmallInt::kMaxValue + 1);
802 double input_value = static_cast<double>(SmallInt::kMaxValue - 256);
803 Object input_obj(&scope, runtime_->newFloat(input_value));
804 Object result_obj(&scope, runBuiltin(METH(float, __int__), input_obj));
805 EXPECT_TRUE(result_obj.isSmallInt());
806 SmallInt result(&scope, *result_obj);
807 EXPECT_EQ(result.value(), static_cast<word>(input_value));
808}
809
810TEST_F(FloatBuiltinsTest,
811 DunderIntWithValueGreaterThanSmallIntMaxValueReturnsLargeInt) {
812 HandleScope scope(thread_);
813 // Due to the truncation error, converting MaxValue to double strictly
814 // increases the value.
815 ASSERT_GT(static_cast<word>(static_cast<double>(SmallInt::kMaxValue)),
816 SmallInt::kMaxValue);
817 // Therefore, this is the smallest double greater than kMaxValue.
818 double input_value = static_cast<double>(SmallInt::kMaxValue);
819 Object input_obj(&scope, runtime_->newFloat(input_value));
820 Object result_obj(&scope, runBuiltin(METH(float, __int__), input_obj));
821 EXPECT_TRUE(result_obj.isLargeInt());
822}
823
824TEST_F(FloatBuiltinsTest, DunderIntWithLargePositiveDoubleReturnsLargeInt) {
825 HandleScope scope(thread_);
826 double input_value = std::strtod("0x1.29ef685b3f6fbp+84", nullptr);
827 Object input_obj(&scope, runtime_->newFloat(input_value));
828 Object result_obj(&scope, runBuiltin(METH(float, __int__), input_obj));
829 ASSERT_TRUE(result_obj.isLargeInt());
830 LargeInt result(&scope, *result_obj);
831 EXPECT_TRUE(result.isPositive());
832 const uword expected_digits[] = {0x85b3f6fb00000000, 0x129ef6};
833 EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
834}
835
836TEST_F(FloatBuiltinsTest, DunderIntWithLargeNegativeDoubleReturnsLargeInt) {
837 HandleScope scope(thread_);
838 double input_value = std::strtod("-0x1.29ef685b3f6fbp+84", nullptr);
839 Object input_obj(&scope, runtime_->newFloat(input_value));
840 Object result_obj(&scope, runBuiltin(METH(float, __int__), input_obj));
841 ASSERT_TRUE(result_obj.isLargeInt());
842 LargeInt result(&scope, *result_obj);
843 EXPECT_TRUE(result.isNegative());
844 // Represented as a two's complement, so 1 is added only to the lowest digit
845 // as long as it doesn't creat a carry.
846 const uword expected_digits[] = {~uword{0x85b3f6fb00000000} + 1,
847 ~uword{0x129ef6}};
848 EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
849}
850
851TEST_F(FloatBuiltinsTest, DunderLeWithFloatReturnsBool) {
852 HandleScope scope(thread_);
853 Object float0(&scope, runtime_->newFloat(13.1));
854 Object float1(&scope, runtime_->newFloat(9.4));
855 EXPECT_EQ(runBuiltin(METH(float, __le__), float0, float1), Bool::falseObj());
856 EXPECT_EQ(runBuiltin(METH(float, __le__), float0, float0), Bool::trueObj());
857 EXPECT_EQ(runBuiltin(METH(float, __le__), float1, float0), Bool::trueObj());
858}
859
860TEST_F(FloatBuiltinsTest, DunderLeWithIntSelfNanReturnsFalse) {
861 HandleScope scope(thread_);
862 Object left(&scope, runtime_->newFloat(kDoubleNaN));
863 const uword digits[] = {0, 1};
864 Object right(&scope, runtime_->newLargeIntWithDigits(digits));
865 EXPECT_EQ(runBuiltin(METH(float, __le__), left, right), Bool::falseObj());
866}
867
868TEST_F(FloatBuiltinsTest, DunderLeWithNonFloatReturnsNotImplemented) {
869 HandleScope scope(thread_);
870 Object left(&scope, runtime_->newFloat(0.0));
871 Object right(&scope, Str::empty());
872 EXPECT_TRUE(
873 runBuiltin(METH(float, __le__), left, right).isNotImplementedType());
874}
875
876TEST_F(FloatBuiltinsTest, DunderLeWithSmallIntReturnsBool) {
877 HandleScope scope(thread_);
878 Object float0(&scope, runtime_->newFloat(4.0));
879 Object int0(&scope, runtime_->newInt(4));
880 Object int1(&scope, runtime_->newInt(3));
881 EXPECT_EQ(runBuiltin(METH(float, __le__), float0, int0), Bool::trueObj());
882 EXPECT_EQ(runBuiltin(METH(float, __le__), float0, int1), Bool::falseObj());
883}
884
885TEST_F(FloatBuiltinsTest, DunderLeWithBoolReturnsBool) {
886 HandleScope scope(thread_);
887 Object float0(&scope, runtime_->newFloat(1.0));
888 Object b_false(&scope, Bool::falseObj());
889 Object b_true(&scope, Bool::trueObj());
890 EXPECT_EQ(runBuiltin(METH(float, __le__), float0, b_false), Bool::falseObj());
891 EXPECT_EQ(runBuiltin(METH(float, __le__), float0, b_true), Bool::trueObj());
892}
893
894TEST_F(FloatBuiltinsTest, DunderLeWithIntSubclassReturnsBool) {
895 HandleScope scope(thread_);
896 ASSERT_FALSE(runFromCStr(runtime_, R"(
897class C(int): pass
898zero = C()
899one = C(1)
900two = C(2)
901)")
902 .isError());
903 Object self(&scope, runtime_->newFloat(1.0));
904 Object zero(&scope, mainModuleAt(runtime_, "zero"));
905 Object one(&scope, mainModuleAt(runtime_, "one"));
906 Object two(&scope, mainModuleAt(runtime_, "two"));
907 EXPECT_EQ(runBuiltin(METH(float, __le__), self, zero), Bool::falseObj());
908 EXPECT_EQ(runBuiltin(METH(float, __le__), self, one), Bool::trueObj());
909 EXPECT_EQ(runBuiltin(METH(float, __le__), self, two), Bool::trueObj());
910}
911
912TEST_F(FloatBuiltinsTest, DunderLtWithFloatReturnsBool) {
913 HandleScope scope(thread_);
914 Object float0(&scope, runtime_->newFloat(-7.3));
915 Object float1(&scope, runtime_->newFloat(1.25));
916 EXPECT_EQ(runBuiltin(METH(float, __lt__), float0, float1), Bool::trueObj());
917 EXPECT_EQ(runBuiltin(METH(float, __lt__), float0, float0), Bool::falseObj());
918 EXPECT_EQ(runBuiltin(METH(float, __lt__), float1, float0), Bool::falseObj());
919}
920
921TEST_F(FloatBuiltinsTest, DunderLtWithIntSelfNanReturnsFalse) {
922 HandleScope scope(thread_);
923 Object left(&scope, runtime_->newFloat(kDoubleNaN));
924 const uword digits[] = {0, 1};
925 Object right(&scope, runtime_->newLargeIntWithDigits(digits));
926 EXPECT_EQ(runBuiltin(METH(float, __lt__), left, right), Bool::falseObj());
927}
928
929TEST_F(FloatBuiltinsTest, DunderLtWithNonFloatReturnsNotImplemented) {
930 HandleScope scope(thread_);
931 Object left(&scope, runtime_->newFloat(0.0));
932 Object right(&scope, Str::empty());
933 EXPECT_TRUE(
934 runBuiltin(METH(float, __lt__), left, right).isNotImplementedType());
935}
936
937TEST_F(FloatBuiltinsTest, DunderLtWithSmallIntReturnsBool) {
938 HandleScope scope(thread_);
939 Object float0(&scope, runtime_->newFloat(4.5));
940 Object int0(&scope, runtime_->newInt(4));
941 Object int1(&scope, runtime_->newInt(5));
942 EXPECT_EQ(runBuiltin(METH(float, __lt__), float0, int0), Bool::falseObj());
943 EXPECT_EQ(runBuiltin(METH(float, __lt__), float0, int1), Bool::trueObj());
944}
945
946TEST_F(FloatBuiltinsTest, DunderLtWithSmallIntExactReturnsBool) {
947 HandleScope scope(thread_);
948 Object float0(&scope, runtime_->newFloat(44.));
949 Object int0(&scope, runtime_->newInt(44));
950 EXPECT_EQ(runBuiltin(METH(float, __lt__), float0, int0), Bool::falseObj());
951 Object float1(&scope, runtime_->newFloat(-3.));
952 Object int1(&scope, runtime_->newInt(1));
953 EXPECT_EQ(runBuiltin(METH(float, __lt__), float1, int1), Bool::trueObj());
954
955 Object float2(&scope, runtime_->newFloat(0x20000000000000));
956 Object int2(&scope, runtime_->newInt(0x20000000000000));
957 EXPECT_EQ(runBuiltin(METH(float, __lt__), float2, int2), Bool::falseObj());
958}
959
960TEST_F(FloatBuiltinsTest, DunderLtWithSmallIntInexactReturnsBool) {
961 HandleScope scope(thread_);
962 Object float0(&scope,
963 runtime_->newFloat(static_cast<double>(0x20000000000001)));
964 Object int0(&scope, runtime_->newInt(0x20000000000001));
965 EXPECT_EQ(runBuiltin(METH(float, __lt__), float0, int0), Bool::trueObj());
966 Object float1(&scope,
967 runtime_->newFloat(static_cast<double>(0x20000000000003)));
968 Object int1(&scope, runtime_->newInt(0x20000000000003));
969 EXPECT_EQ(runBuiltin(METH(float, __lt__), float1, int1), Bool::falseObj());
970 Object float2(&scope,
971 runtime_->newFloat(static_cast<double>(0x100000000000011)));
972 Object int2(&scope, runtime_->newInt(0x100000000000011));
973 EXPECT_EQ(runBuiltin(METH(float, __lt__), float2, int2), Bool::trueObj());
974}
975
976TEST_F(FloatBuiltinsTest, DunderLtWithLargeIntDifferingSignReturnsBool) {
977 HandleScope scope(thread_);
978 Object float0(&scope, runtime_->newFloat(-1.0));
979 const uword digits0[] = {0, 1};
980 Object int0(&scope, runtime_->newLargeIntWithDigits(digits0));
981 EXPECT_EQ(runBuiltin(METH(float, __lt__), float0, int0), Bool::trueObj());
982 Object float1(&scope, runtime_->newFloat(1.0));
983 const uword digits1[] = {0, kMaxUword};
984 Object int1(&scope, runtime_->newLargeIntWithDigits(digits1));
985 EXPECT_EQ(runBuiltin(METH(float, __lt__), float1, int1), Bool::falseObj());
986}
987
988TEST_F(FloatBuiltinsTest, DunderLtWithLargeIntExactEqualsReturnsFalse) {
989 HandleScope scope(thread_);
990 Object float0(&scope, runtime_->newFloat(std::strtod("0x1p64", nullptr)));
991 const uword digits[] = {0, 1};
992 Object int0(&scope, runtime_->newLargeIntWithDigits(digits));
993 EXPECT_EQ(runBuiltin(METH(float, __lt__), float0, int0), Bool::falseObj());
994}
995
996TEST_F(FloatBuiltinsTest, DunderLtWithLargeIntRoundingDownReturnsTrue) {
997 HandleScope scope(thread_);
998 Object float0(&scope, runtime_->newFloat(std::strtod("0x1p64", nullptr)));
999 const uword digits[] = {1, 1};
1000 Object int0(&scope, runtime_->newLargeIntWithDigits(digits));
1001 ASSERT_EQ(Float::cast(runBuiltin(METH(int, __float__), int0)).value(),
1002 Float::cast(*float0).value());
1003 EXPECT_EQ(runBuiltin(METH(float, __lt__), float0, int0), Bool::trueObj());
1004}
1005
1006TEST_F(FloatBuiltinsTest, DunderLtWithLargeIntRoundingUpReturnsFalse) {
1007 HandleScope scope(thread_);
1008 Object float0(&scope, runtime_->newFloat(std::strtod("0x1p64", nullptr)));
1009 const uword digits[] = {kMaxUword, 0};
1010 Object int0(&scope, runtime_->newLargeIntWithDigits(digits));
1011 ASSERT_EQ(Float::cast(runBuiltin(METH(int, __float__), int0)).value(),
1012 Float::cast(*float0).value());
1013 EXPECT_EQ(runBuiltin(METH(float, __lt__), float0, int0), Bool::falseObj());
1014}
1015
1016TEST_F(FloatBuiltinsTest, DunderLtWithIntSubclassReturnsBool) {
1017 HandleScope scope(thread_);
1018 ASSERT_FALSE(runFromCStr(runtime_, R"(
1019class C(int): pass
1020zero = C()
1021one = C(1)
1022two = C(2)
1023)")
1024 .isError());
1025 Object self(&scope, runtime_->newFloat(1.0));
1026 Object zero(&scope, mainModuleAt(runtime_, "zero"));
1027 Object one(&scope, mainModuleAt(runtime_, "one"));
1028 Object two(&scope, mainModuleAt(runtime_, "two"));
1029 EXPECT_EQ(runBuiltin(METH(float, __lt__), self, zero), Bool::falseObj());
1030 EXPECT_EQ(runBuiltin(METH(float, __lt__), self, one), Bool::falseObj());
1031 EXPECT_EQ(runBuiltin(METH(float, __lt__), self, two), Bool::trueObj());
1032}
1033
1034} // namespace testing
1035} // namespace py