runtime/int-builtins-test.cpp (2,716 lines of code) (raw):
// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
#include "int-builtins.h"
#include <cmath>
#include <limits>
#include "gtest/gtest.h"
#include "builtins.h"
#include "handles.h"
#include "objects.h"
#include "runtime.h"
#include "test-utils.h"
#include "type-builtins.h"
namespace py {
namespace testing {
using BoolBuiltinsTest = RuntimeFixture;
using IntBuiltinsTest = RuntimeFixture;
using LargeIntBuiltinsTest = RuntimeFixture;
TEST_F(IntBuiltinsTest, BuiltinBases) {
HandleScope scope(thread_);
Type integer(&scope, runtime_->typeAt(LayoutId::kInt));
EXPECT_EQ(integer.builtinBase(), LayoutId::kInt);
Type small_int(&scope, runtime_->typeAt(LayoutId::kSmallInt));
EXPECT_EQ(small_int.builtinBase(), LayoutId::kInt);
Type large_int(&scope, runtime_->typeAt(LayoutId::kLargeInt));
EXPECT_EQ(large_int.builtinBase(), LayoutId::kInt);
Type boolean(&scope, runtime_->typeAt(LayoutId::kBool));
EXPECT_EQ(boolean.builtinBase(), LayoutId::kInt);
}
TEST_F(IntBuiltinsTest, CompareSmallIntEq) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
a = 1
b = 2
a_eq_b = a == b
a_eq_a = a == a
b_eq_b = b == b
)")
.isError());
Object a_eq_b(&scope, mainModuleAt(runtime_, "a_eq_b"));
EXPECT_EQ(*a_eq_b, Bool::falseObj());
Object a_eq_a(&scope, mainModuleAt(runtime_, "a_eq_a"));
EXPECT_EQ(*a_eq_a, Bool::trueObj());
Object b_eq_b(&scope, mainModuleAt(runtime_, "b_eq_b"));
EXPECT_EQ(*b_eq_b, Bool::trueObj());
}
TEST_F(IntBuiltinsTest, CompareSmallIntGe) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
a = 1
b = 2
a_ge_a = a >= a
a_ge_b = a >= b
b_ge_a = b >= a
b_ge_b = b >= b
)")
.isError());
Object a_ge_a(&scope, mainModuleAt(runtime_, "a_ge_a"));
EXPECT_EQ(*a_ge_a, Bool::trueObj());
Object a_ge_b(&scope, mainModuleAt(runtime_, "a_ge_b"));
EXPECT_EQ(*a_ge_b, Bool::falseObj());
Object b_ge_a(&scope, mainModuleAt(runtime_, "b_ge_a"));
EXPECT_EQ(*b_ge_a, Bool::trueObj());
Object b_ge_b(&scope, mainModuleAt(runtime_, "b_ge_b"));
EXPECT_EQ(*b_ge_b, Bool::trueObj());
}
TEST_F(IntBuiltinsTest, CompareSmallIntGt) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
a = 1
b = 2
a_gt_a = a > a
a_gt_b = a > b
b_gt_a = b > a
b_gt_b = b > b
)")
.isError());
Object a_gt_a(&scope, mainModuleAt(runtime_, "a_gt_a"));
EXPECT_EQ(*a_gt_a, Bool::falseObj());
Object a_gt_b(&scope, mainModuleAt(runtime_, "a_gt_b"));
EXPECT_EQ(*a_gt_b, Bool::falseObj());
Object b_gt_a(&scope, mainModuleAt(runtime_, "b_gt_a"));
EXPECT_EQ(*b_gt_a, Bool::trueObj());
Object b_gt_b(&scope, mainModuleAt(runtime_, "b_gt_b"));
EXPECT_EQ(*b_gt_b, Bool::falseObj());
}
TEST_F(IntBuiltinsTest, CompareSmallIntLe) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
a = 1
b = 2
a_le_a = a <= a
a_le_b = a <= b
b_le_a = b <= a
b_le_b = b <= b
)")
.isError());
Object a_le_a(&scope, mainModuleAt(runtime_, "a_le_a"));
EXPECT_EQ(*a_le_a, Bool::trueObj());
Object a_le_b(&scope, mainModuleAt(runtime_, "a_le_b"));
EXPECT_EQ(*a_le_b, Bool::trueObj());
Object b_le_a(&scope, mainModuleAt(runtime_, "b_le_a"));
EXPECT_EQ(*b_le_a, Bool::falseObj());
Object b_le_b(&scope, mainModuleAt(runtime_, "b_le_b"));
EXPECT_EQ(*b_le_b, Bool::trueObj());
}
TEST_F(IntBuiltinsTest, CompareSmallIntLt) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
a = 1
b = 2
a_lt_a = a < a
a_lt_b = a < b
b_lt_a = b < a
b_lt_b = b < b
)")
.isError());
Object a_lt_a(&scope, mainModuleAt(runtime_, "a_lt_a"));
EXPECT_EQ(*a_lt_a, Bool::falseObj());
Object a_lt_b(&scope, mainModuleAt(runtime_, "a_lt_b"));
EXPECT_EQ(*a_lt_b, Bool::trueObj());
Object b_lt_a(&scope, mainModuleAt(runtime_, "b_lt_a"));
EXPECT_EQ(*b_lt_a, Bool::falseObj());
Object b_lt_b(&scope, mainModuleAt(runtime_, "b_lt_b"));
EXPECT_EQ(*b_lt_b, Bool::falseObj());
}
TEST_F(IntBuiltinsTest, CompareSmallIntNe) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
a = 1
b = 2
a_ne_b = a != b
a_ne_a = a != a
b_ne_b = b != b
)")
.isError());
Object a_ne_b(&scope, mainModuleAt(runtime_, "a_ne_b"));
EXPECT_EQ(*a_ne_b, Bool::trueObj());
Object a_ne_a(&scope, mainModuleAt(runtime_, "a_ne_a"));
EXPECT_EQ(*a_ne_a, Bool::falseObj());
Object b_ne_b(&scope, mainModuleAt(runtime_, "b_ne_b"));
EXPECT_EQ(*b_ne_b, Bool::falseObj());
}
TEST_F(IntBuiltinsTest, CompareOpSmallInt) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
a = 1
b = 2
c = 1
a_lt_b = a < b
a_le_b = a <= b
a_eq_b = a == b
a_ge_b = a >= b
a_gt_b = a > b
a_is_c = a is c
a_is_not_c = a is not c
)")
.isError());
Object a_lt_b(&scope, mainModuleAt(runtime_, "a_lt_b"));
EXPECT_EQ(*a_lt_b, Bool::trueObj());
Object a_le_b(&scope, mainModuleAt(runtime_, "a_le_b"));
EXPECT_EQ(*a_le_b, Bool::trueObj());
Object a_eq_b(&scope, mainModuleAt(runtime_, "a_eq_b"));
EXPECT_EQ(*a_eq_b, Bool::falseObj());
Object a_ge_b(&scope, mainModuleAt(runtime_, "a_ge_b"));
EXPECT_EQ(*a_ge_b, Bool::falseObj());
Object a_gt_b(&scope, mainModuleAt(runtime_, "a_gt_b"));
EXPECT_EQ(*a_gt_b, Bool::falseObj());
Object a_is_c(&scope, mainModuleAt(runtime_, "a_is_c"));
EXPECT_EQ(*a_is_c, Bool::trueObj());
Object a_is_not_c(&scope, mainModuleAt(runtime_, "a_is_not_c"));
EXPECT_EQ(*a_is_not_c, Bool::falseObj());
}
TEST_F(IntBuiltinsTest, UnaryPositiveSmallInt) {
HandleScope scope(thread_);
const char* src = R"(
pos = 123
plus_pos = +pos
neg = -123
plus_neg = +neg
)";
ASSERT_FALSE(runFromCStr(runtime_, src).isError());
Object plus_pos(&scope, mainModuleAt(runtime_, "plus_pos"));
EXPECT_TRUE(isIntEqualsWord(*plus_pos, 123));
Object plus_neg(&scope, mainModuleAt(runtime_, "plus_neg"));
EXPECT_TRUE(isIntEqualsWord(*plus_neg, -123));
}
TEST_F(IntBuiltinsTest, UnaryNegateSmallInt) {
HandleScope scope(thread_);
const char* src = R"(
pos = 123
minus_pos = -pos
neg = -123
minus_neg = -neg
)";
ASSERT_FALSE(runFromCStr(runtime_, src).isError());
Object minus_pos(&scope, mainModuleAt(runtime_, "minus_pos"));
EXPECT_TRUE(isIntEqualsWord(*minus_pos, -123));
Object minus_neg(&scope, mainModuleAt(runtime_, "minus_neg"));
EXPECT_TRUE(isIntEqualsWord(*minus_neg, 123));
}
TEST_F(IntBuiltinsTest, TruthyIntPos) {
HandleScope scope(thread_);
Int one(&scope, SmallInt::fromWord(1));
EXPECT_EQ(runBuiltin(METH(int, __bool__), one), Bool::trueObj());
}
TEST_F(IntBuiltinsTest, TruthyIntZero) {
HandleScope scope(thread_);
Int zero(&scope, SmallInt::fromWord(0));
EXPECT_EQ(runBuiltin(METH(int, __bool__), zero), Bool::falseObj());
}
TEST_F(IntBuiltinsTest, InplaceAdd) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
a = 1
a += 0
b = a
a += 2
)")
.isError());
Object a(&scope, mainModuleAt(runtime_, "a"));
Object b(&scope, mainModuleAt(runtime_, "b"));
EXPECT_TRUE(isIntEqualsWord(*a, 3));
EXPECT_TRUE(isIntEqualsWord(*b, 1));
}
TEST_F(IntBuiltinsTest, InplaceMultiply) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
a = 5
a *= 1
b = a
a *= 2
)")
.isError());
Object a(&scope, mainModuleAt(runtime_, "a"));
Object b(&scope, mainModuleAt(runtime_, "b"));
EXPECT_TRUE(isIntEqualsWord(*a, 10));
EXPECT_TRUE(isIntEqualsWord(*b, 5));
}
TEST_F(IntBuiltinsTest, InplaceFloordiv) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
a = 5
a //= 1
b = a
a //= 2
)")
.isError());
Object a(&scope, mainModuleAt(runtime_, "a"));
Object b(&scope, mainModuleAt(runtime_, "b"));
EXPECT_TRUE(isIntEqualsWord(*a, 2));
EXPECT_TRUE(isIntEqualsWord(*b, 5));
}
TEST_F(IntBuiltinsTest, InplaceModulo) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
a = 10
a %= 7
b = a
a %= 2
)")
.isError());
Object a(&scope, mainModuleAt(runtime_, "a"));
Object b(&scope, mainModuleAt(runtime_, "b"));
EXPECT_TRUE(isIntEqualsWord(*a, 1));
EXPECT_TRUE(isIntEqualsWord(*b, 3));
}
TEST_F(IntBuiltinsTest, InplaceSub) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
a = 10
a -= 0
b = a
a -= 7
)")
.isError());
Object a(&scope, mainModuleAt(runtime_, "a"));
Object b(&scope, mainModuleAt(runtime_, "b"));
EXPECT_TRUE(isIntEqualsWord(*a, 3));
EXPECT_TRUE(isIntEqualsWord(*b, 10));
}
TEST_F(IntBuiltinsTest, InplaceXor) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
a = 0xFE
a ^= 0
b = a
a ^= 0x03
)")
.isError());
Object a(&scope, mainModuleAt(runtime_, "a"));
Object b(&scope, mainModuleAt(runtime_, "b"));
EXPECT_TRUE(isIntEqualsWord(*a, 0xFD));
EXPECT_TRUE(isIntEqualsWord(*b, 0xFE));
}
TEST_F(IntBuiltinsTest, DunderAbsWithBoolFalseReturnsZero) {
HandleScope scope(thread_);
Int self(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, __abs__), self));
EXPECT_EQ(result, SmallInt::fromWord(0));
}
TEST_F(IntBuiltinsTest, DunderAbsWithBoolTrueReturnsOne) {
HandleScope scope(thread_);
Int self(&scope, Bool::trueObj());
Object result(&scope, runBuiltin(METH(int, __abs__), self));
EXPECT_EQ(result, SmallInt::fromWord(1));
}
TEST_F(IntBuiltinsTest, DunderAbsWithPositiveIntReturnsInt) {
HandleScope scope(thread_);
Int self(&scope, runtime_->newInt(1234));
Object result(&scope, runBuiltin(METH(int, __abs__), self));
EXPECT_TRUE(isIntEqualsWord(*result, 1234));
}
TEST_F(IntBuiltinsTest, DunderAbsWithNegativeIntReturnsInt) {
HandleScope scope(thread_);
const uword digits[] = {0x154a0071b091fb7e, 0x9661bb54b4e68c59};
Int self(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __abs__), self));
const uword expected_digits[] = {0xeab5ff8e4f6e0482, 0x699e44ab4b1973a6};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderAbsWithIntSubclassReturnsInt) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
class X(int): pass
neg = X(-42)
pos = X(42)
zero = X()
)")
.isError());
Object neg(&scope, mainModuleAt(runtime_, "neg"));
Object pos(&scope, mainModuleAt(runtime_, "pos"));
Object zero(&scope, mainModuleAt(runtime_, "zero"));
EXPECT_EQ(runBuiltin(METH(int, __abs__), neg), SmallInt::fromWord(42));
EXPECT_EQ(runBuiltin(METH(int, __abs__), pos), SmallInt::fromWord(42));
EXPECT_EQ(runBuiltin(METH(int, __abs__), zero), SmallInt::fromWord(0));
}
TEST_F(IntBuiltinsTest, DunderAddWithSmallIntsReturnsSmallInt) {
HandleScope scope(thread_);
Int left(&scope, SmallInt::fromWord(42));
Int right(&scope, SmallInt::fromWord(-7));
Object result(&scope, runBuiltin(METH(int, __add__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, 35));
}
TEST_F(IntBuiltinsTest, DunderAddWithSmallIntsOverflowReturnsLargeInt) {
HandleScope scope(thread_);
Int max_small_int(&scope, SmallInt::fromWord(RawSmallInt::kMaxValue));
Int one(&scope, SmallInt::fromWord(1));
Object result(&scope, runBuiltin(METH(int, __add__), max_small_int, one));
EXPECT_TRUE(isIntEqualsWord(*result, RawSmallInt::kMaxValue + 1));
}
TEST_F(IntBuiltinsTest, DunderAddWithLargeInts) {
HandleScope scope(thread_);
const uword digits_left[] = {0xfedcba0987654321, 0x1234567890abcdef};
Int left(&scope, runtime_->newLargeIntWithDigits(digits_left));
const uword digits_right[] = {0x9876543210abcdef, 0xfedcba0123456789};
Int right(&scope, runtime_->newLargeIntWithDigits(digits_right));
Object result(&scope, runBuiltin(METH(int, __add__), left, right));
const uword expected_digits[] = {0x97530e3b98111110, 0x11111079b3f13579};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderAddWithPositiveLargeIntsCarrying) {
HandleScope scope(thread_);
const uword digits_left[] = {kMaxUword, kMaxUword, 0};
Int left(&scope, runtime_->newLargeIntWithDigits(digits_left));
Int right(&scope, runtime_->newInt(1));
Object result(&scope, runBuiltin(METH(int, __add__), left, right));
const uword expected_digits[] = {0, 0, 1};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderAddWithNegativeLargeIntsCarrying) {
HandleScope scope(thread_);
Int left(&scope, runtime_->newInt(-1));
// The smallest negative number representable with 2 digits.
const uword digits_right[] = {0, static_cast<uword>(kMinWord)};
Int right(&scope, runtime_->newLargeIntWithDigits(digits_right));
Object result(&scope, runBuiltin(METH(int, __add__), left, right));
const uword expected_digits[] = {kMaxUword, kMaxWord, kMaxUword};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderAndWithSmallIntsReturnsSmallInt) {
HandleScope scope(thread_);
Int left(&scope, SmallInt::fromWord(0x15)); // 0b010101
Int right(&scope, SmallInt::fromWord(0x38)); // 0b111000
Object result(&scope, runBuiltin(METH(int, __and__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, 0x10)); // 0b10000
}
TEST_F(IntBuiltinsTest, DunderAndWithLargeIntsReturnsLargeInt) {
HandleScope scope(thread_);
const uword digits_left[] = {0x0f, 0x30, 0x1};
Int left(&scope, runtime_->newLargeIntWithDigits(digits_left));
const uword digits_right[] = {0x03, 0xf0, 0x2, 7};
Int right(&scope, runtime_->newLargeIntWithDigits(digits_right));
Object result(&scope, runBuiltin(METH(int, __and__), left, right));
const uword expected_digits[] = {0x03, 0x30};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderAndWithNonIntReturnsNotImplemented) {
HandleScope scope(thread_);
const uword digits[] = {1, 2};
Int left(&scope, runtime_->newLargeIntWithDigits(digits));
Object right(&scope, Str::empty());
Object result(&scope, runBuiltin(METH(int, __and__), left, right));
EXPECT_TRUE(result.isNotImplementedType());
}
TEST_F(IntBuiltinsTest, DunderAndWithInvalidArgumentLeftRaisesException) {
HandleScope scope(thread_);
Object left(&scope, Str::empty());
const uword digits[] = {1, 2};
LargeInt right(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __and__), left, right));
EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
}
TEST_F(IntBuiltinsTest, DunderAndWithIntSubclassReturnsInt) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
class X(int): pass
left = X(0b0011)
right = X(0b0101)
)")
.isError());
Object left(&scope, mainModuleAt(runtime_, "left"));
Object right(&scope, mainModuleAt(runtime_, "right"));
Object result(&scope, runBuiltin(METH(int, __and__), left, right));
EXPECT_EQ(result, SmallInt::fromWord(1)); // 0b0001
}
TEST_F(IntBuiltinsTest, DunderCeilAliasesDunderInt) {
HandleScope scope(thread_);
Type type(&scope, moduleAtByCStr(runtime_, "builtins", "int"));
Object ceil_name(&scope, Runtime::internStrFromCStr(thread_, "__ceil__"));
Object ceil_obj(&scope, typeAt(type, ceil_name));
ASSERT_TRUE(ceil_obj.isFunction());
Function ceil(&scope, *ceil_obj);
Object dint_name(&scope, Runtime::internStrFromCStr(thread_, "__int__"));
Object dint_obj(&scope, typeAt(type, dint_name));
ASSERT_TRUE(dint_obj.isFunction());
Function dint(&scope, *ceil_obj);
EXPECT_EQ(Code::cast(ceil.code()).code(), Code::cast(dint.code()).code());
EXPECT_EQ(ceil.entry(), dint.entry());
EXPECT_EQ(ceil.entryKw(), dint.entryKw());
EXPECT_EQ(ceil.entryEx(), dint.entryEx());
}
TEST_F(IntBuiltinsTest, DunderFloorAliasesDunderInt) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Type type(&scope, moduleAtByCStr(runtime_, "builtins", "int"));
Object floor_name(&scope, Runtime::internStrFromCStr(thread_, "__floor__"));
Object floor_obj(&scope, typeAt(type, floor_name));
ASSERT_TRUE(floor_obj.isFunction());
Function floor(&scope, *floor_obj);
Object dint_name(&scope, Runtime::internStrFromCStr(thread_, "__int__"));
Object dint_obj(&scope, typeAt(type, dint_name));
ASSERT_TRUE(dint_obj.isFunction());
Function dint(&scope, *floor_obj);
EXPECT_EQ(Code::cast(floor.code()).code(), Code::cast(dint.code()).code());
EXPECT_EQ(floor.entry(), dint.entry());
EXPECT_EQ(floor.entryKw(), dint.entryKw());
EXPECT_EQ(floor.entryEx(), dint.entryEx());
}
TEST_F(IntBuiltinsTest, DunderLshiftWithBoolsTrueFalseReturnsSmallInt) {
HandleScope scope(thread_);
Object left(&scope, Bool::trueObj());
Object right(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, __lshift__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, 1));
}
TEST_F(IntBuiltinsTest, DunderLshiftWithBoolsFalseTrueReturnsSmallInt) {
HandleScope scope(thread_);
Object left(&scope, Bool::falseObj());
Object right(&scope, Bool::trueObj());
Object result(&scope, runBuiltin(METH(int, __lshift__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, 0));
}
TEST_F(IntBuiltinsTest, DunderLshiftWithBoolSmallIntReturnsLargeInt) {
HandleScope scope(thread_);
Object left(&scope, Bool::trueObj());
Object right(&scope, runtime_->newInt(kBitsPerWord));
Object result(&scope, runBuiltin(METH(int, __lshift__), left, right));
const uword expected_digits[] = {0, 1};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderLshiftWithSmallIntsReturnsSmallInt) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(0xd)); // 0b1101
Object right(&scope, runtime_->newInt(3));
Object result(&scope, runBuiltin(METH(int, __lshift__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, 0x68)); // 0b1101000
}
TEST_F(IntBuiltinsTest, DunderLshiftWithNegativeSmallIntReturnsSmallInt) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(-2));
Object right(&scope, runtime_->newInt(1));
Object result(&scope, runBuiltin(METH(int, __lshift__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, -4));
}
TEST_F(IntBuiltinsTest, DunderLshiftWithZeroReturnsZero) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(0));
const uword digits[] = {1, 2, 3, 4};
Object right(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __lshift__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, 0));
}
TEST_F(IntBuiltinsTest, DunderLshiftWithBigSmallIntReturnsSmallInt) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(RawSmallInt::kMaxValue >> 1));
Object right(&scope, runtime_->newInt(1));
Object result(&scope, runBuiltin(METH(int, __lshift__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, RawSmallInt::kMaxValue - 1));
}
TEST_F(IntBuiltinsTest, DunderLshiftWithBigNegativeSmallIntReturnsSmallInt) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(RawSmallInt::kMinValue >> 1));
Object right(&scope, runtime_->newInt(1));
Object result(&scope, runBuiltin(METH(int, __lshift__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, RawSmallInt::kMinValue));
}
TEST_F(IntBuiltinsTest, DunderLshiftWithSmallIntsReturnsLargeInt) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(4));
Object right(&scope, runtime_->newInt(kBitsPerWord - 4));
Object result_obj(&scope, runBuiltin(METH(int, __lshift__), left, right));
ASSERT_TRUE(result_obj.isLargeInt());
LargeInt result(&scope, *result_obj);
EXPECT_EQ(result.numDigits(), 1);
EXPECT_EQ(result.digitAt(0), uword{1} << (kBitsPerWord - 2));
}
TEST_F(IntBuiltinsTest, DunderLshiftWithSmallIntsNegativeReturnsLargeInt) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(-4));
Object right(&scope, runtime_->newInt(kBitsPerWord - 3));
Object result(&scope, runBuiltin(METH(int, __lshift__), left, right));
const uword expected_digits[] = {static_cast<uword>(-4)
<< (kBitsPerWord - 3)};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderLshiftWithSmallIntOverflowReturnsLargeInt) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(4));
Object right(&scope, runtime_->newInt(kBitsPerWord - 3));
Object result(&scope, runBuiltin(METH(int, __lshift__), left, right));
const uword expected_digits[] = {kHighbitUword, 0};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest,
DunderLshiftWithNegativeSmallIntOverflowReturnsLargeInt) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(-4));
Object right(&scope, runtime_->newInt(kBitsPerWord - 2));
Object result(&scope, runBuiltin(METH(int, __lshift__), left, right));
const uword expected_digits[] = {0, kMaxUword};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderLshiftWithLargeIntReturnsLargeInt) {
HandleScope scope(thread_);
const uword digits[] = {1, 1};
Object left(&scope, runtime_->newLargeIntWithDigits(digits));
Object right(&scope, runtime_->newInt(2 * kBitsPerWord + 2));
Object result(&scope, runBuiltin(METH(int, __lshift__), left, right));
const uword expected_digits[] = {0, 0, 4, 4};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderLshiftWithNegativeLargeIntReturnsLargeInt) {
HandleScope scope(thread_);
const uword digits[] = {kMaxUword - 1, kMaxUword - 1};
Object left(&scope, runtime_->newLargeIntWithDigits(digits));
Object right(&scope, runtime_->newInt(2 * kBitsPerWord + 2));
Object result(&scope, runBuiltin(METH(int, __lshift__), left, right));
const uword expected_digits[] = {0, 0, kMaxUword - 7, kMaxUword - 4};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderLshiftWithLargeIntWholeWordReturnsLargeInt) {
HandleScope scope(thread_);
const uword digits[] = {0xfe84754526de453c, 0x47e8218b97f94763};
Object left(&scope, runtime_->newLargeIntWithDigits(digits));
Object right(&scope, runtime_->newInt(kBitsPerWord * 2));
Object result(&scope, runBuiltin(METH(int, __lshift__), left, right));
const uword expected_digits[] = {0, 0, 0xfe84754526de453c,
0x47e8218b97f94763};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderLshiftWithNegativeShiftAmountRaiseValueError) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(0));
Object right(&scope, runtime_->newInt(-1));
Object result(&scope, runBuiltin(METH(int, __lshift__), left, right));
EXPECT_TRUE(
raisedWithStr(*result, LayoutId::kValueError, "negative shift count"));
}
TEST_F(IntBuiltinsTest, DunderLshiftWithNonIntSelfRaisesTypeError) {
HandleScope scope(thread_);
Object left(&scope, Str::empty());
Object right(&scope, runtime_->newInt(0));
Object result(&scope, runBuiltin(METH(int, __lshift__), left, right));
EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
}
TEST_F(IntBuiltinsTest, DunderLshiftWithNonIntReturnsNotImplemented) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(0));
Object right(&scope, Str::empty());
Object result(&scope, runBuiltin(METH(int, __lshift__), left, right));
EXPECT_TRUE(result.isNotImplementedType());
}
TEST_F(IntBuiltinsTest, DunderLshiftWithIntSubclassReturnsInt) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
class X(int): pass
left = X(0b1101)
right = X(3)
)")
.isError());
Object left(&scope, mainModuleAt(runtime_, "left"));
Object right(&scope, mainModuleAt(runtime_, "right"));
Object result(&scope, runBuiltin(METH(int, __lshift__), left, right));
EXPECT_EQ(result, SmallInt::fromWord(0x68)); // 0b1101000
}
TEST_F(IntBuiltinsTest, DunderModWithSmallIntReturnsInt) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(-9876));
Object right(&scope, runtime_->newInt(123));
Object result(&scope, runBuiltin(METH(int, __mod__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, 87));
}
TEST_F(IntBuiltinsTest, DunderModWithZeroRaisesZeroDivisionError) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(2));
Object right(&scope, runtime_->newInt(0));
Object result(&scope, runBuiltin(METH(int, __mod__), left, right));
EXPECT_TRUE(raisedWithStr(*result, LayoutId::kZeroDivisionError,
"integer division or modulo by zero"));
}
TEST_F(IntBuiltinsTest, DunderModWithNonIntSelfRaisesTypeError) {
HandleScope scope(thread_);
Object left(&scope, Str::empty());
Object right(&scope, runtime_->newInt(1));
Object result(&scope, runBuiltin(METH(int, __mod__), left, right));
EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
}
TEST_F(IntBuiltinsTest, DunderModWithNontIntReturnsNotImplemented) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(1));
Object right(&scope, Str::empty());
Object result(&scope, runBuiltin(METH(int, __mod__), left, right));
EXPECT_TRUE(result.isNotImplementedType());
}
TEST_F(IntBuiltinsTest, DunderMulWithSmallIntsReturnsSmallInt) {
HandleScope scope(thread_);
Int left(&scope, runtime_->newInt(13));
Int right(&scope, runtime_->newInt(-3));
Object result(&scope, runBuiltin(METH(int, __mul__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, -39));
}
TEST_F(IntBuiltinsTest, DunderMulWithSmallIntsReturnsSingleDigitLargeInt) {
HandleScope scope(thread_);
Int left(&scope, RawSmallInt::fromWord(RawSmallInt::kMaxValue));
Int right(&scope, RawSmallInt::fromWord(2));
Object result(&scope, runBuiltin(METH(int, __mul__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, RawSmallInt::kMaxValue * 2));
}
TEST_F(IntBuiltinsTest, DunderMulWithSmallIntsReturnsLargeInt) {
HandleScope scope(thread_);
Int num(&scope, RawSmallInt::fromWord(RawSmallInt::kMaxValue));
Object result(&scope, runBuiltin(METH(int, __mul__), num, num));
const uword expected_digits[] = {0x8000000000000001, 0xfffffffffffffff};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderMulWithSmallIntLargeIntReturnsLargeInt) {
HandleScope scope(thread_);
Int left(&scope, RawSmallInt::fromWord(-3));
const uword digits[] = {0xa1b2c3d4e5f67890, 0xaabbccddeeff};
Int right(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __mul__), left, right));
const uword expected_digits[] = {0x1ae7b4814e1c9650, 0xfffdffcc99663301};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderMulWithZeroReturnsSmallInt) {
HandleScope scope(thread_);
const uword digits[] = {0, 1};
Int left(&scope, runtime_->newLargeIntWithDigits(digits));
Int right(&scope, RawSmallInt::fromWord(0));
Object result(&scope, runBuiltin(METH(int, __mul__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, 0));
}
TEST_F(IntBuiltinsTest, DunderMulWithPositiveLargeIntsReturnsLargeInt) {
HandleScope scope(thread_);
const uword digits_left[] = {0xfedcba0987654321, 0x1234567890abcdef};
Int left(&scope, runtime_->newLargeIntWithDigits(digits_left));
const uword digits_right[] = {0x0123456789abcdef, 0xfedcba9876543210, 0};
Int right(&scope, runtime_->newLargeIntWithDigits(digits_right));
Object result(&scope, runBuiltin(METH(int, __mul__), left, right));
const uword expected_digits[] = {0x2236d928fe5618cf, 0xaa6c87569f0ec6a4,
0x213cff7595234949, 0x121fa00acd77d743};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderMulWithMaxPositiveLargeIntsReturnsLargeInt) {
HandleScope scope(thread_);
const uword digits[] = {kMaxUword, 0};
Int num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __mul__), num, num));
const uword expected_digits[] = {1, kMaxUword - 1, 0};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderMulWithNegativeLargeIntsReturnsLargeInt) {
HandleScope scope(thread_);
// Smallest negative number representable with 2 digits.
const uword digits[] = {0, static_cast<uword>(kMinWord)};
Int num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __mul__), num, num));
const uword expected_digits[] = {0, 0, 0, static_cast<uword>(kMinWord) >> 1};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderMulWithNegativePositiveLargeIntsReturnsLargeInt) {
HandleScope scope(thread_);
const uword digits_left[] = {0xada6d35d8ef7c790};
Int left(&scope, runtime_->newLargeIntWithDigits(digits_left));
const uword digits_right[] = {0x3ff2ca02c44fbb1c, 0x5873a2744317c09a};
Int right(&scope, runtime_->newLargeIntWithDigits(digits_right));
Object result(&scope, runBuiltin(METH(int, __mul__), left, right));
const uword expected_digits[] = {0x6d80780b775003c0, 0xb46184fc0839baa0,
0xe38c265747f0661f};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderMulWithPositiveNegativeLargeIntsReturnsLargeInt) {
HandleScope scope(thread_);
const uword digits_left[] = {0x3ff2ca02c44fbb1c, 0x5873a2744317c09a};
Int left(&scope, runtime_->newLargeIntWithDigits(digits_left));
const uword digits_right[] = {0xada6d35d8ef7c790};
Int right(&scope, runtime_->newLargeIntWithDigits(digits_right));
Object result(&scope, runBuiltin(METH(int, __mul__), left, right));
const uword expected_digits[] = {0x6d80780b775003c0, 0xb46184fc0839baa0,
0xe38c265747f0661f};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderMulWithNonIntSelfRaisesTypeError) {
HandleScope scope(thread_);
Str str(&scope, Str::empty());
Int right(&scope, runtime_->newInt(1));
Object result(&scope, runBuiltin(METH(int, __mul__), str, right));
ASSERT_TRUE(raised(*result, LayoutId::kTypeError));
}
TEST_F(IntBuiltinsTest, DunderMulWithNonIntRightReturnsNotImplemented) {
HandleScope scope(thread_);
Int left(&scope, runtime_->newInt(1));
Str str(&scope, Str::empty());
Object result(&scope, runBuiltin(METH(int, __mul__), left, str));
ASSERT_TRUE(result.isNotImplementedType());
}
TEST_F(IntBuiltinsTest, DunderOrWithSmallIntsReturnsSmallInt) {
HandleScope scope(thread_);
Int left(&scope, SmallInt::fromWord(0x15)); // 0b010101
Int right(&scope, SmallInt::fromWord(0x38)); // 0b111000
Object result(&scope, runBuiltin(METH(int, __or__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, 0x3D)); // 0b111101
}
TEST_F(IntBuiltinsTest, DunderOrWithLargeIntsReturnsLargeInt) {
HandleScope scope(thread_);
const uword digits_left[] = {0x0C, 0xB0, 0xCAFE};
Int left(&scope, runtime_->newLargeIntWithDigits(digits_left));
const uword digits_right[] = {0x03, 0xD0};
Int right(&scope, runtime_->newLargeIntWithDigits(digits_right));
Object result(&scope, runBuiltin(METH(int, __or__), left, right));
const uword expected_digits[] = {0x0F, 0xF0, 0xCAFE};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderOrWithNonIntReturnsNotImplemented) {
HandleScope scope(thread_);
const uword digits[] = {1, 2};
Int left(&scope, runtime_->newLargeIntWithDigits(digits));
Object right(&scope, Str::empty());
Object result(&scope, runBuiltin(METH(int, __or__), left, right));
EXPECT_TRUE(result.isNotImplementedType());
}
TEST_F(IntBuiltinsTest, DunderOrWithInvalidArgumentLeftRaisesException) {
HandleScope scope(thread_);
Object left(&scope, Str::empty());
const uword digits[] = {1, 2};
LargeInt right(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __or__), left, right));
EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
}
TEST_F(IntBuiltinsTest, DunderOrWithIntSubclassReturnsInt) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
class X(int): pass
left = X(0b0011)
right = X(0b0101)
)")
.isError());
Object left(&scope, mainModuleAt(runtime_, "left"));
Object right(&scope, mainModuleAt(runtime_, "right"));
Object result(&scope, runBuiltin(METH(int, __or__), left, right));
EXPECT_EQ(result, SmallInt::fromWord(7)); // 0b0111
}
TEST_F(IntBuiltinsTest, BinaryAddSmallInt) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
a = 2
b = 1
c = a + b
)")
.isError());
Object c(&scope, mainModuleAt(runtime_, "c"));
EXPECT_TRUE(isIntEqualsWord(*c, 3));
}
TEST_F(IntBuiltinsTest, BitLength) {
HandleScope scope(thread_);
// (0).bit_length() == 0
Object num(&scope, SmallInt::fromWord(0));
Object bit_length(&scope, runBuiltin(METH(int, bit_length), num));
EXPECT_TRUE(isIntEqualsWord(*bit_length, 0));
// (1).bit_length() == 1
num = SmallInt::fromWord(1);
Object bit_length1(&scope, runBuiltin(METH(int, bit_length), num));
EXPECT_TRUE(isIntEqualsWord(*bit_length1, 1));
// (-1).bit_length() == 1
num = SmallInt::fromWord(1);
Object bit_length2(&scope, runBuiltin(METH(int, bit_length), num));
EXPECT_TRUE(isIntEqualsWord(*bit_length2, 1));
// (SmallInt::kMaxValue).bit_length() == 62
num = SmallInt::fromWord(RawSmallInt::kMaxValue);
Object bit_length3(&scope, runBuiltin(METH(int, bit_length), num));
EXPECT_TRUE(isIntEqualsWord(*bit_length3, 62));
// (SmallInt::kMinValue).bit_length() == 63
num = SmallInt::fromWord(RawSmallInt::kMinValue);
Object bit_length4(&scope, runBuiltin(METH(int, bit_length), num));
EXPECT_TRUE(isIntEqualsWord(*bit_length4, 63));
// (kMaxInt64).bit_length() == 63
num = runtime_->newInt(kMaxInt64);
Object bit_length5(&scope, runBuiltin(METH(int, bit_length), num));
EXPECT_TRUE(isIntEqualsWord(*bit_length5, 63));
// (kMinInt64).bit_length() == 64
num = runtime_->newInt(kMinInt64);
Object bit_length6(&scope, runBuiltin(METH(int, bit_length), num));
EXPECT_TRUE(isIntEqualsWord(*bit_length6, 64));
uword digits[] = {0, kMaxInt32};
num = runtime_->newLargeIntWithDigits(digits);
Object bit_length7(&scope, runBuiltin(METH(int, bit_length), num));
// 31 bits for kMaxInt32 + 64 bits
EXPECT_TRUE(isIntEqualsWord(*bit_length7, 95));
// (kMinInt64 * 4).bit_length() == 66
uword digits2[] = {0, kMaxUword - 1}; // kMaxUword - 1 == -2
num = runtime_->newLargeIntWithDigits(digits2);
Object bit_length8(&scope, runBuiltin(METH(int, bit_length), num));
EXPECT_TRUE(isIntEqualsWord(*bit_length8, 66));
// (kMinInt64 * 4 + 3).bit_length() == 65
uword digits3[] = {3, kMaxUword - 1}; // kMaxUword - 1 == -2
num = runtime_->newLargeIntWithDigits(digits3);
Object bit_length9(&scope, runBuiltin(METH(int, bit_length), num));
EXPECT_TRUE(isIntEqualsWord(*bit_length9, 65));
}
TEST_F(IntBuiltinsTest, CompareLargeIntEq) {
HandleScope scope(thread_);
Object a(&scope, runtime_->newInt(RawSmallInt::kMaxValue + 1));
Object b(&scope, runtime_->newInt(RawSmallInt::kMinValue - 1));
Object zero(&scope, SmallInt::fromWord(0));
ASSERT_TRUE(a.isLargeInt());
ASSERT_TRUE(b.isLargeInt());
Object cmp_1(&scope, runBuiltin(METH(int, __eq__), a, b));
ASSERT_TRUE(cmp_1.isBool());
EXPECT_EQ(*cmp_1, Bool::falseObj());
Object cmp_2(&scope, runBuiltin(METH(int, __eq__), a, zero));
ASSERT_TRUE(cmp_2.isBool());
EXPECT_EQ(*cmp_2, Bool::falseObj());
Object cmp_3(&scope, runBuiltin(METH(int, __eq__), a, a));
ASSERT_TRUE(cmp_3.isBool());
EXPECT_EQ(*cmp_3, Bool::trueObj());
Object cmp_4(&scope, runBuiltin(METH(int, __eq__), b, a));
ASSERT_TRUE(cmp_4.isBool());
EXPECT_EQ(*cmp_4, Bool::falseObj());
Object cmp_5(&scope, runBuiltin(METH(int, __eq__), b, zero));
ASSERT_TRUE(cmp_5.isBool());
EXPECT_EQ(*cmp_5, Bool::falseObj());
Object cmp_6(&scope, runBuiltin(METH(int, __eq__), b, b));
ASSERT_TRUE(cmp_6.isBool());
EXPECT_EQ(*cmp_6, Bool::trueObj());
}
TEST_F(IntBuiltinsTest, CompareLargeIntNe) {
HandleScope scope(thread_);
Object a(&scope, runtime_->newInt(RawSmallInt::kMaxValue + 1));
Object b(&scope, runtime_->newInt(RawSmallInt::kMinValue - 1));
Object zero(&scope, SmallInt::fromWord(0));
ASSERT_TRUE(a.isLargeInt());
ASSERT_TRUE(b.isLargeInt());
Object cmp_1(&scope, runBuiltin(METH(int, __ne__), a, b));
ASSERT_TRUE(cmp_1.isBool());
EXPECT_EQ(*cmp_1, Bool::trueObj());
Object cmp_2(&scope, runBuiltin(METH(int, __ne__), a, zero));
ASSERT_TRUE(cmp_2.isBool());
EXPECT_EQ(*cmp_2, Bool::trueObj());
Object cmp_3(&scope, runBuiltin(METH(int, __ne__), a, a));
ASSERT_TRUE(cmp_3.isBool());
EXPECT_EQ(*cmp_3, Bool::falseObj());
Object cmp_4(&scope, runBuiltin(METH(int, __ne__), b, a));
ASSERT_TRUE(cmp_4.isBool());
EXPECT_EQ(*cmp_4, Bool::trueObj());
Object cmp_5(&scope, runBuiltin(METH(int, __ne__), b, zero));
ASSERT_TRUE(cmp_5.isBool());
EXPECT_EQ(*cmp_5, Bool::trueObj());
Object cmp_6(&scope, runBuiltin(METH(int, __ne__), b, b));
ASSERT_TRUE(cmp_6.isBool());
EXPECT_EQ(*cmp_6, Bool::falseObj());
}
TEST_F(IntBuiltinsTest, DunderFloatWithBoolReturnsFloat) {
HandleScope scope(thread_);
Object a(&scope, Bool::trueObj());
Object a_float(&scope, runBuiltin(METH(int, __float__), a));
EXPECT_TRUE(isFloatEqualsDouble(*a_float, 1.0));
Object b(&scope, Bool::falseObj());
Object b_float(&scope, runBuiltin(METH(int, __float__), b));
EXPECT_TRUE(isFloatEqualsDouble(*b_float, 0.0));
}
TEST_F(IntBuiltinsTest, DunderFloatWithSmallIntReturnsFloat) {
HandleScope scope(thread_);
Int num(&scope, RawSmallInt::fromWord(-7));
Object result(&scope, runBuiltin(METH(int, __float__), num));
EXPECT_TRUE(isFloatEqualsDouble(*result, -7.0));
}
TEST_F(IntBuiltinsTest, DunderFloatWithOneDigitLargeIntReturnsFloat) {
HandleScope scope(thread_);
const uword digits[] = {static_cast<uword>(kMinWord)};
Int num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __float__), num));
EXPECT_TRUE(isFloatEqualsDouble(*result, double{kMinWord}));
}
TEST_F(IntBuiltinsTest, DunderFloatWithLargeIntReturnsFloat) {
HandleScope scope(thread_);
const uword digits[] = {0x85b3f6fb0496ac6f, 0x129ef6};
Int num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __float__), num));
EXPECT_TRUE(isFloatEqualsDouble(
*result, std::strtod("0x1.29ef685b3f6fbp+84", nullptr)));
}
TEST_F(IntBuiltinsTest, DunderFloatWithNegativeLargeIntReturnsFloat) {
HandleScope scope(thread_);
const uword digits[] = {0x937822557f9bad3f, 0xb31911a86c86a071};
Int num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __float__), num));
EXPECT_TRUE(isFloatEqualsDouble(
*result, std::strtod("-0x1.339bb95e4de58p+126", nullptr)));
}
TEST_F(IntBuiltinsTest,
DunderFloatWithNegativeLargeIntMagnitudeComputationCarriesReturnsFloat) {
HandleScope scope(thread_);
const uword digits[] = {1, 0, 0, 0xfffedcc000000000};
Int num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __float__), num));
EXPECT_TRUE(
isFloatEqualsDouble(*result, std::strtod("-0x1.234p240", nullptr)));
}
TEST_F(IntBuiltinsTest, DunderFloatWithLargeIntRoundedDownReturnsFloat) {
HandleScope scope(thread_);
// Produce a 1 so that all of the mantissa lies in the high digit but the bit
// triggering the rounding is in the low digit.
uword mantissa_high_bit = uword{1} << kDoubleMantissaBits;
const uword digits[] = {0, mantissa_high_bit};
Int num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __float__), num));
EXPECT_TRUE(isFloatEqualsDouble(*result, std::strtod("0x1.p116", nullptr)));
}
TEST_F(IntBuiltinsTest, DunderFloatWithLargeIntRoundedDownToEvenReturnsFloat) {
HandleScope scope(thread_);
const uword digits[] = {uword{1} << (kBitsPerWord - kDoubleMantissaBits - 1),
1};
Int num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __float__), num));
EXPECT_TRUE(isFloatEqualsDouble(*result, std::strtod("0x1.p64", nullptr)));
}
TEST_F(IntBuiltinsTest, DunderFloatWithLargeIntRoundedUpToEvenReturnsFloat) {
HandleScope scope(thread_);
uword mantissa_high_bit_plus_one = (uword{1} << kDoubleMantissaBits) + 1;
const uword digits[] = {kHighbitUword, mantissa_high_bit_plus_one};
Int num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __float__), num));
EXPECT_TRUE(isFloatEqualsDouble(
*result, std::strtod("0x1.0000000000002p116", nullptr)));
}
TEST_F(IntBuiltinsTest,
DunderFloatWithNegativeLargeIntRoundedDownToEvenReturnsFloat) {
HandleScope scope(thread_);
uword mantissa_high_bit = uword{1} << kDoubleMantissaBits;
const uword digits[] = {0, kHighbitUword, ~mantissa_high_bit};
Int num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __float__), num));
EXPECT_TRUE(isFloatEqualsDouble(*result, std::strtod("-0x1.p180", nullptr)));
}
TEST_F(IntBuiltinsTest,
DunderFloatWithNegativeLargeIntRoundedUpToEvenReturnsFloat) {
HandleScope scope(thread_);
uword mantissa_high_bit_plus_one = (uword{1} << kDoubleMantissaBits) | 1;
const uword digits[] = {0, kHighbitUword, ~mantissa_high_bit_plus_one};
Int num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __float__), num));
EXPECT_TRUE(isFloatEqualsDouble(
*result, std::strtod("-0x1.0000000000002p180", nullptr)));
}
TEST_F(IntBuiltinsTest,
DunderFloatWithLargeIntRoundedUpIncreasingExponentReturnsFloat) {
HandleScope scope(thread_);
uword mantissa_all_one = (uword{1} << (kDoubleMantissaBits + 1)) - 1;
const uword digits[] = {kHighbitUword, mantissa_all_one};
Int num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __float__), num));
EXPECT_TRUE(isFloatEqualsDouble(*result, std::strtod("0x1.p117", nullptr)));
}
static RawObject largestIntBeforeFloatOverflow(Runtime* runtime) {
int exponent_bits = kBitsPerDouble - kDoubleMantissaBits - 1;
word max_unbiased_exponent = (1 << (exponent_bits - 1)) - 1;
CHECK((max_unbiased_exponent + 1) % kBitsPerWord == 0,
"assuming max exponent position matches highest bit in digit");
// Note: Need an extra digit for the sign.
word num_digits = (max_unbiased_exponent + 1) / kBitsPerWord + 1;
std::unique_ptr<uword[]> digits(new uword[num_digits]);
for (word i = 0; i < num_digits - 1; i++) {
digits[i] = kMaxUword;
}
// Set the bit immediately below the mantissa to zero to avoid rounding up.
digits[num_digits - 2] &= ~(1 << (kBitsPerWord - kDoubleMantissaBits - 2));
digits[num_digits - 1] = 0;
return runtime->newLargeIntWithDigits(View<uword>(digits.get(), num_digits));
}
TEST_F(IntBuiltinsTest,
DunderFloatLargestPossibleLargeIntBeforeOverflowReturnsFloat) {
HandleScope scope(thread_);
Int num(&scope, largestIntBeforeFloatOverflow(runtime_));
Object result(&scope, runBuiltin(METH(int, __float__), num));
ASSERT_TRUE(result.isFloat());
EXPECT_TRUE(isFloatEqualsDouble(*result, std::numeric_limits<double>::max()));
}
TEST_F(IntBuiltinsTest, DunderFloatOverflowRaisesOverflowError) {
HandleScope scope(thread_);
// Add 1 to the largest number that is still convertible to float.
Int num0(&scope, largestIntBeforeFloatOverflow(runtime_));
Int one(&scope, runtime_->newInt(1));
Int num1(&scope, runBuiltin(METH(int, __add__), num0, one));
Object result(&scope, runBuiltin(METH(int, __float__), num1));
EXPECT_TRUE(raised(*result, LayoutId::kOverflowError));
}
TEST_F(IntBuiltinsTest, DunderFloatWithNonIntReturnsError) {
HandleScope scope(thread_);
Object none(&scope, NoneType::object());
Object result(&scope, runBuiltin(METH(int, __int__), none));
EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
}
TEST_F(IntBuiltinsTest, DunderFloordivWithSmallIntReturnsInt) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(42));
Object right(&scope, runtime_->newInt(9));
Object result(&scope, runBuiltin(METH(int, __floordiv__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, 4));
}
TEST_F(IntBuiltinsTest, DunderFloordivWithZeroRaisesZeroDivisionError) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(2));
Object right(&scope, runtime_->newInt(0));
Object result(&scope, runBuiltin(METH(int, __floordiv__), left, right));
EXPECT_TRUE(raisedWithStr(*result, LayoutId::kZeroDivisionError,
"integer division or modulo by zero"));
}
TEST_F(IntBuiltinsTest, DunderFloordivWithNonIntSelfRaisesTypeError) {
HandleScope scope(thread_);
Object left(&scope, Str::empty());
Object right(&scope, runtime_->newInt(1));
Object result(&scope, runBuiltin(METH(int, __floordiv__), left, right));
EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
}
TEST_F(IntBuiltinsTest, DunderFloordivWithNontIntReturnsNotImplemented) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(1));
Object right(&scope, Str::empty());
Object result(&scope, runBuiltin(METH(int, __floordiv__), left, right));
EXPECT_TRUE(result.isNotImplementedType());
}
TEST_F(LargeIntBuiltinsTest, TruthyLargeInt) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
value = 46116860184273879030000000
)")
.isError());
HandleScope scope(thread_);
Object value(&scope, mainModuleAt(runtime_, "value"));
EXPECT_EQ(runBuiltin(METH(int, __bool__), value), Bool::trueObj());
}
TEST_F(IntBuiltinsTest, CompareLargeIntGe) {
HandleScope scope(thread_);
Object a(&scope, runtime_->newInt(RawSmallInt::kMaxValue + 1));
Object b(&scope, runtime_->newInt(RawSmallInt::kMinValue - 1));
Object zero(&scope, SmallInt::fromWord(0));
ASSERT_TRUE(a.isLargeInt());
ASSERT_TRUE(b.isLargeInt());
Object cmp_1(&scope, runBuiltin(METH(int, __ge__), a, b));
ASSERT_TRUE(cmp_1.isBool());
EXPECT_EQ(*cmp_1, Bool::trueObj());
Object cmp_2(&scope, runBuiltin(METH(int, __ge__), a, zero));
ASSERT_TRUE(cmp_2.isBool());
EXPECT_EQ(*cmp_2, Bool::trueObj());
Object cmp_3(&scope, runBuiltin(METH(int, __ge__), a, a));
ASSERT_TRUE(cmp_3.isBool());
EXPECT_EQ(*cmp_3, Bool::trueObj());
Object cmp_4(&scope, runBuiltin(METH(int, __ge__), b, a));
ASSERT_TRUE(cmp_4.isBool());
EXPECT_EQ(*cmp_4, Bool::falseObj());
Object cmp_5(&scope, runBuiltin(METH(int, __ge__), b, zero));
ASSERT_TRUE(cmp_5.isBool());
EXPECT_EQ(*cmp_5, Bool::falseObj());
Object cmp_6(&scope, runBuiltin(METH(int, __ge__), b, b));
ASSERT_TRUE(cmp_6.isBool());
EXPECT_EQ(*cmp_6, Bool::trueObj());
}
TEST_F(IntBuiltinsTest, CompareLargeIntLe) {
HandleScope scope(thread_);
Object a(&scope, runtime_->newInt(RawSmallInt::kMaxValue + 1));
Object b(&scope, runtime_->newInt(RawSmallInt::kMinValue - 1));
Object zero(&scope, SmallInt::fromWord(0));
ASSERT_TRUE(a.isLargeInt());
ASSERT_TRUE(b.isLargeInt());
Object cmp_1(&scope, runBuiltin(METH(int, __le__), a, b));
ASSERT_TRUE(cmp_1.isBool());
EXPECT_EQ(*cmp_1, Bool::falseObj());
Object cmp_2(&scope, runBuiltin(METH(int, __le__), a, zero));
ASSERT_TRUE(cmp_2.isBool());
EXPECT_EQ(*cmp_2, Bool::falseObj());
Object cmp_3(&scope, runBuiltin(METH(int, __le__), a, a));
ASSERT_TRUE(cmp_3.isBool());
EXPECT_EQ(*cmp_3, Bool::trueObj());
Object cmp_4(&scope, runBuiltin(METH(int, __le__), b, a));
ASSERT_TRUE(cmp_4.isBool());
EXPECT_EQ(*cmp_4, Bool::trueObj());
Object cmp_5(&scope, runBuiltin(METH(int, __le__), b, zero));
ASSERT_TRUE(cmp_5.isBool());
EXPECT_EQ(*cmp_5, Bool::trueObj());
Object cmp_6(&scope, runBuiltin(METH(int, __le__), b, b));
ASSERT_TRUE(cmp_6.isBool());
EXPECT_EQ(*cmp_6, Bool::trueObj());
}
TEST_F(IntBuiltinsTest, CompareLargeIntGt) {
HandleScope scope(thread_);
Object a(&scope, runtime_->newInt(RawSmallInt::kMaxValue + 1));
Object b(&scope, runtime_->newInt(RawSmallInt::kMinValue - 1));
Object zero(&scope, SmallInt::fromWord(0));
ASSERT_TRUE(a.isLargeInt());
ASSERT_TRUE(b.isLargeInt());
Object cmp_1(&scope, runBuiltin(METH(int, __gt__), a, b));
ASSERT_TRUE(cmp_1.isBool());
EXPECT_EQ(*cmp_1, Bool::trueObj());
Object cmp_2(&scope, runBuiltin(METH(int, __gt__), a, zero));
ASSERT_TRUE(cmp_2.isBool());
EXPECT_EQ(*cmp_2, Bool::trueObj());
Object cmp_3(&scope, runBuiltin(METH(int, __gt__), a, a));
ASSERT_TRUE(cmp_3.isBool());
EXPECT_EQ(*cmp_3, Bool::falseObj());
Object cmp_4(&scope, runBuiltin(METH(int, __gt__), b, a));
ASSERT_TRUE(cmp_4.isBool());
EXPECT_EQ(*cmp_4, Bool::falseObj());
Object cmp_5(&scope, runBuiltin(METH(int, __gt__), b, zero));
ASSERT_TRUE(cmp_5.isBool());
EXPECT_EQ(*cmp_5, Bool::falseObj());
Object cmp_6(&scope, runBuiltin(METH(int, __gt__), b, b));
ASSERT_TRUE(cmp_6.isBool());
EXPECT_EQ(*cmp_6, Bool::falseObj());
}
TEST_F(IntBuiltinsTest, CompareLargeIntLt) {
HandleScope scope(thread_);
Object a(&scope, runtime_->newInt(RawSmallInt::kMaxValue + 1));
Object b(&scope, runtime_->newInt(RawSmallInt::kMinValue - 1));
Object zero(&scope, SmallInt::fromWord(0));
ASSERT_TRUE(a.isLargeInt());
ASSERT_TRUE(b.isLargeInt());
Object cmp_1(&scope, runBuiltin(METH(int, __lt__), a, b));
ASSERT_TRUE(cmp_1.isBool());
EXPECT_EQ(*cmp_1, Bool::falseObj());
Object cmp_2(&scope, runBuiltin(METH(int, __lt__), a, zero));
ASSERT_TRUE(cmp_2.isBool());
EXPECT_EQ(*cmp_2, Bool::falseObj());
Object cmp_3(&scope, runBuiltin(METH(int, __lt__), a, a));
ASSERT_TRUE(cmp_3.isBool());
EXPECT_EQ(*cmp_3, Bool::falseObj());
Object cmp_4(&scope, runBuiltin(METH(int, __lt__), b, a));
ASSERT_TRUE(cmp_4.isBool());
EXPECT_EQ(*cmp_4, Bool::trueObj());
Object cmp_5(&scope, runBuiltin(METH(int, __lt__), b, zero));
ASSERT_TRUE(cmp_5.isBool());
EXPECT_EQ(*cmp_5, Bool::trueObj());
Object cmp_6(&scope, runBuiltin(METH(int, __lt__), b, b));
ASSERT_TRUE(cmp_6.isBool());
EXPECT_EQ(*cmp_6, Bool::falseObj());
}
TEST_F(IntBuiltinsTest, DunderIndexAliasesDunderInt) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Type type(&scope, moduleAtByCStr(runtime_, "builtins", "int"));
Object index_name(&scope, Runtime::internStrFromCStr(thread_, "__index__"));
Object index_obj(&scope, typeAt(type, index_name));
ASSERT_TRUE(index_obj.isFunction());
Function index(&scope, *index_obj);
Object dint_name(&scope, Runtime::internStrFromCStr(thread_, "__int__"));
Object dint_obj(&scope, typeAt(type, dint_name));
ASSERT_TRUE(dint_obj.isFunction());
Function dint(&scope, *index_obj);
EXPECT_EQ(Code::cast(index.code()).code(), Code::cast(dint.code()).code());
EXPECT_EQ(index.entry(), dint.entry());
EXPECT_EQ(index.entryKw(), dint.entryKw());
EXPECT_EQ(index.entryEx(), dint.entryEx());
}
TEST_F(IntBuiltinsTest, DunderIntWithBoolFalseReturnsZero) {
HandleScope scope(thread_);
Object self(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, __int__), self));
EXPECT_EQ(result, SmallInt::fromWord(0));
}
TEST_F(IntBuiltinsTest, DunderIntWithBoolTrueReturnsOne) {
HandleScope scope(thread_);
Object self(&scope, Bool::trueObj());
Object result(&scope, runBuiltin(METH(int, __int__), self));
EXPECT_EQ(result, SmallInt::fromWord(1));
}
TEST_F(IntBuiltinsTest, DunderIntWithSmallIntReturnsSame) {
HandleScope scope(thread_);
Object self(&scope, RawSmallInt::fromWord(7));
Object result(&scope, runBuiltin(METH(int, __int__), self));
EXPECT_EQ(self, result);
}
TEST_F(IntBuiltinsTest, DunderIntReturnsSameValue) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
a = (7).__int__()
b = int.__int__(7)
)")
.isError());
Object a(&scope, mainModuleAt(runtime_, "a"));
Object b(&scope, mainModuleAt(runtime_, "b"));
EXPECT_TRUE(isIntEqualsWord(*a, 7));
EXPECT_TRUE(isIntEqualsWord(*b, 7));
Str str(&scope, runtime_->newStrFromCStr("python"));
Object res(&scope, runBuiltin(METH(int, __int__), str));
EXPECT_TRUE(res.isError());
}
TEST_F(IntBuiltinsTest, DunderInvertWithBoolTrueReturnsSmallInt) {
HandleScope scope(thread_);
Object num(&scope, Bool::trueObj());
Object result(&scope, runBuiltin(METH(int, __invert__), num));
ASSERT_TRUE(result.isSmallInt());
EXPECT_TRUE(isIntEqualsWord(*result, -2));
}
TEST_F(IntBuiltinsTest, DunderInvertWithBoolFalseReturnsSmallInt) {
HandleScope scope(thread_);
Object num(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, __invert__), num));
ASSERT_TRUE(result.isSmallInt());
EXPECT_TRUE(isIntEqualsWord(*result, -1));
}
TEST_F(IntBuiltinsTest, DunderInvertWithSmallIntReturnsSmallInt) {
HandleScope scope(thread_);
Object num(&scope, SmallInt::fromWord(-224466));
Object result(&scope, runBuiltin(METH(int, __invert__), num));
ASSERT_TRUE(result.isSmallInt());
EXPECT_TRUE(isIntEqualsWord(*result, 224465));
}
TEST_F(IntBuiltinsTest, DunderInvertWithLargeIntReturnsLargeInt) {
HandleScope scope(thread_);
const uword num_digits[] = {0x6c5bfcb426758496, 0xda8bdbe69c009bc5, 0};
Object num(&scope, runtime_->newLargeIntWithDigits(num_digits));
Object result_obj(&scope, runBuiltin(METH(int, __invert__), num));
ASSERT_TRUE(result_obj.isLargeInt());
Int result(&scope, *result_obj);
const uword expected_digits[] = {0x93a4034bd98a7b69, 0x2574241963ff643a,
kMaxUword};
Int expected(&scope, runtime_->newLargeIntWithDigits(expected_digits));
EXPECT_EQ(expected.compare(*result), 0);
}
TEST_F(IntBuiltinsTest, DunderBoolOnBool) {
HandleScope scope(thread_);
Object true_obj(&scope, Bool::trueObj());
EXPECT_EQ(runBuiltin(METH(int, __bool__), true_obj), Bool::trueObj());
Object false_obj(&scope, Bool::falseObj());
EXPECT_EQ(runBuiltin(METH(int, __bool__), false_obj), Bool::falseObj());
}
TEST_F(IntBuiltinsTest, DunderDivmodWithBoolsReturnsTuple) {
HandleScope scope(thread_);
Object left(&scope, Bool::trueObj());
Object right(&scope, Bool::trueObj());
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
EXPECT_TRUE(isIntEqualsWord(result.at(0), 1));
EXPECT_TRUE(isIntEqualsWord(result.at(1), 0));
}
TEST_F(IntBuiltinsTest, DunderDivmodWithSmallIntReturnsTuple) {
HandleScope scope(thread_);
Object left(&scope, RawSmallInt::fromWord(4321));
Object right(&scope, RawSmallInt::fromWord(17));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
EXPECT_TRUE(isIntEqualsWord(result.at(0), 254));
EXPECT_TRUE(isIntEqualsWord(result.at(1), 3));
}
TEST_F(IntBuiltinsTest,
DunderDivmodWithSmallIntNegativeDividendNegativeDivisorReturnsTuple) {
HandleScope scope(thread_);
Object left(&scope, RawSmallInt::fromWord(-987654321));
Object right(&scope, RawSmallInt::fromWord(-654));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
EXPECT_TRUE(isIntEqualsWord(result.at(0), 1510174));
EXPECT_TRUE(isIntEqualsWord(result.at(1), -525));
}
TEST_F(IntBuiltinsTest, DunderDivmodWithSmallIntNegativeDividendReturnsTuple) {
HandleScope scope(thread_);
Object left(&scope, RawSmallInt::fromWord(-123456789));
Object right(&scope, RawSmallInt::fromWord(456));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
EXPECT_TRUE(isIntEqualsWord(result.at(0), -270739));
EXPECT_TRUE(isIntEqualsWord(result.at(1), 195));
}
TEST_F(IntBuiltinsTest,
DunderDivmodWithSmallIntNegativeDividendNoRemainderReturnsTuple) {
HandleScope scope(thread_);
Object left(&scope, RawSmallInt::fromWord(-94222222181));
Object right(&scope, RawSmallInt::fromWord(53));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
EXPECT_TRUE(isIntEqualsWord(result.at(0), -1777777777));
EXPECT_TRUE(isIntEqualsWord(result.at(1), 0));
}
TEST_F(IntBuiltinsTest, DunderDivmodWithSmallIntNegativeDivisorReturnsTuple) {
HandleScope scope(thread_);
Object left(&scope, RawSmallInt::fromWord(111222333));
Object right(&scope, RawSmallInt::fromWord(-444));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
EXPECT_TRUE(isIntEqualsWord(result.at(0), -250501));
EXPECT_TRUE(isIntEqualsWord(result.at(1), -111));
}
TEST_F(IntBuiltinsTest,
DunderDivmodWithSmallIntNegativeDivisorNoRemainderReturnsTuple) {
HandleScope scope(thread_);
Object left(&scope, RawSmallInt::fromWord(94222222181));
Object right(&scope, RawSmallInt::fromWord(-53));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
EXPECT_TRUE(isIntEqualsWord(result.at(0), -1777777777));
EXPECT_TRUE(isIntEqualsWord(result.at(1), 0));
}
TEST_F(IntBuiltinsTest,
DunderDivmodWithSmallIntAndDivisorMinusOneReturnsTuple) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(kMinWord));
Object right(&scope, runtime_->newInt(-1));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
const uword expected_digits[] = {kHighbitUword, 0};
EXPECT_TRUE(isIntEqualsDigits(result.at(0), expected_digits));
EXPECT_TRUE(isIntEqualsWord(result.at(1), 0));
}
TEST_F(IntBuiltinsTest,
DunderDivmodWithLargeIntAndDivisorMinusOneReturnsTuple) {
HandleScope scope(thread_);
const uword digits[] = {0, kHighbitUword};
Object left(&scope, runtime_->newLargeIntWithDigits(digits));
Object right(&scope, runtime_->newInt(-1));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
const uword expected_digits[] = {0, kHighbitUword, 0};
EXPECT_TRUE(isIntEqualsDigits(result.at(0), expected_digits));
EXPECT_TRUE(isIntEqualsWord(result.at(1), 0));
}
TEST_F(IntBuiltinsTest, DunderDivmodWithSingleDigitDivisorReturnsTuple) {
HandleScope scope(thread_);
const uword digits[] = {0x4a23475557e990d0, 0x56c1275a8b41bed9};
Object left(&scope, runtime_->newLargeIntWithDigits(digits));
Object right(&scope, runtime_->newInt(77));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
const uword expected_digits[] = {0x79cb7c896c08a31, 0x1206e39b2042db3};
EXPECT_TRUE(isIntEqualsDigits(result.at(0), expected_digits));
EXPECT_TRUE(isIntEqualsWord(result.at(1), 19));
}
TEST_F(IntBuiltinsTest, DunderDivmodWithBoolDivisorReturnsTuple) {
HandleScope scope(thread_);
const uword digits[] = {0x4a23475557e990d0, 0x56c1275a8b41bed9};
Object left(&scope, runtime_->newLargeIntWithDigits(digits));
Object right(&scope, Bool::trueObj());
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
const uword expected_digits[] = {0x4a23475557e990d0, 0x56c1275a8b41bed9};
EXPECT_TRUE(isIntEqualsDigits(result.at(0), expected_digits));
EXPECT_TRUE(isIntEqualsWord(result.at(1), 0));
}
TEST_F(IntBuiltinsTest,
DunderDivmodWithSingleDigitNegativeDivisorReturnsTuple) {
HandleScope scope(thread_);
const uword digits[] = {0x6d73444a30629c55, 0x2c4ab2d4de16e2ef};
Object left(&scope, runtime_->newLargeIntWithDigits(digits));
Object right(&scope, runtime_->newInt(-87654));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
const uword expected_digits[] = {0x334af489352d60f6, 0xffffdee26dff7ad9};
EXPECT_TRUE(isIntEqualsDigits(result.at(0), expected_digits));
EXPECT_TRUE(isIntEqualsWord(result.at(1), -7591));
}
TEST_F(IntBuiltinsTest,
DunderDivmodWithSingleDigitNegativeDivisorNoRemainderReturnsTuple) {
HandleScope scope(thread_);
const uword digits[] = {0x6d73444a30629c55, 0x2c4ab2d4de16e2ef};
Object left(&scope, runtime_->newLargeIntWithDigits(digits));
Object right(&scope, runtime_->newInt(-5));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
const uword expected_digits[] = {0x83b5bf245cb913ef, 0xf72442a239fb6c36};
EXPECT_TRUE(isIntEqualsDigits(result.at(0), expected_digits));
EXPECT_TRUE(isIntEqualsWord(result.at(1), 0));
}
TEST_F(IntBuiltinsTest,
DunderDivmodWithSingleDigitDivisorNegativeDividendReturnsTuple) {
HandleScope scope(thread_);
const uword digits[] = {0x94472249c23c1189, 0xffe0519aab10d602};
Object left(&scope, runtime_->newLargeIntWithDigits(digits));
Object right(&scope, runtime_->newInt(12345));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
const uword expected_digits[] = {0x5b96544c9be595f3, 0xffffff57d046e6d2};
EXPECT_TRUE(isIntEqualsDigits(result.at(0), expected_digits));
EXPECT_TRUE(isIntEqualsWord(result.at(1), 7790));
}
TEST_F(
IntBuiltinsTest,
DunderDivmodWithSingleDigitDivisorNegativeDividendNoRemainderReturnsTuple) {
HandleScope scope(thread_);
const uword digits[] = {0x94472249c23c1189, 0xffe0519aab10d602};
Object left(&scope, runtime_->newLargeIntWithDigits(digits));
Object right(&scope, runtime_->newInt(5));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
const uword expected_digits[] = {0x50db06db8d3f36b5, 0xfff9a9ebbbd02acd};
EXPECT_TRUE(isIntEqualsDigits(result.at(0), expected_digits));
EXPECT_TRUE(isIntEqualsWord(result.at(1), 0));
}
TEST_F(IntBuiltinsTest,
DunderDivmodWithSingleDigitNegativeDivisorNegativeDividendReturnsTuple) {
HandleScope scope(thread_);
const uword digits[] = {0x91a950df92c04492, 0xd60eebbadb89de2f};
Object left(&scope, runtime_->newLargeIntWithDigits(digits));
Object right(&scope, runtime_->newInt(-1117392329));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
const uword expected_digits[] = {0x6aaebd022be4f5c, 0xa1368e9f};
EXPECT_TRUE(isIntEqualsDigits(result.at(0), expected_digits));
EXPECT_TRUE(isIntEqualsWord(result.at(1), -108249138));
}
TEST_F(IntBuiltinsTest,
DunderDivmodWithJustNotASingleDigitDivisorReturnsTuple) {
HandleScope scope(thread_);
const uword digits[] = {0xaaa, 3};
Object left(&scope, runtime_->newLargeIntWithDigits(digits));
Object right(&scope, runtime_->newInt(-0x100000000));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
EXPECT_TRUE(isIntEqualsWord(result.at(0), -12884901889));
EXPECT_TRUE(isIntEqualsWord(result.at(1), -4294964566));
}
TEST_F(IntBuiltinsTest, DunderDivmodWithBiggerDivisorReturnsTuple) {
HandleScope scope(thread_);
const uword digits_left[] = {0x575420c5052ae9c6};
Object left(&scope, runtime_->newLargeIntWithDigits(digits_left));
const uword digits_right[] = {0x383b89d9e2bb74f5, 0x1234};
Object right(&scope, runtime_->newLargeIntWithDigits(digits_right));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
EXPECT_TRUE(isIntEqualsWord(result.at(0), 0));
// The algorithm should take a shortcut and return the dividend unchanged.
EXPECT_EQ(result.at(1), left);
}
TEST_F(IntBuiltinsTest,
DunderDivmodWithNegativeDividendBiggerDivisorReturnsTuple) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(-55));
const uword digits[] = {0, 1};
Object right(&scope, runtime_->newLargeIntWithDigits(digits));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
EXPECT_TRUE(isIntEqualsWord(result.at(0), -1));
const uword expected_digits[] = {~uword{54}, 0};
EXPECT_TRUE(isIntEqualsDigits(result.at(1), expected_digits));
}
TEST_F(IntBuiltinsTest,
DunderDivmodWithDividendBiggerNegativeDivisorReturnsTuple) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(55));
const uword digits[] = {0, kHighbitUword};
Object right(&scope, runtime_->newLargeIntWithDigits(digits));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
EXPECT_TRUE(isIntEqualsWord(result.at(0), -1));
const uword expected_digits[] = {55, kHighbitUword};
EXPECT_TRUE(isIntEqualsDigits(result.at(1), expected_digits));
}
TEST_F(IntBuiltinsTest,
DunderDivmodWithNegativeDividendBiggerNegativeDivisorReturnsTuple) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(-55));
const uword digits[] = {0, kMaxUword};
Object right(&scope, runtime_->newLargeIntWithDigits(digits));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
EXPECT_TRUE(isIntEqualsWord(result.at(0), 0));
EXPECT_TRUE(isIntEqualsWord(result.at(1), -55));
}
TEST_F(IntBuiltinsTest, DunderDivmodWithLargeIntReturnsTuple) {
HandleScope scope(thread_);
const uword digits_left[] = {0x383b89d9e2bb74f5, 0x410f8dceb8660505,
0x383b1ab8d7938f4b, 0x87108b9b45b43d};
Object left(&scope, runtime_->newLargeIntWithDigits(digits_left));
const uword digits_right[] = {0x975420c5052ae9c6, 0x3bcd71afac71b2e4};
Object right(&scope, runtime_->newLargeIntWithDigits(digits_right));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
const uword expected_digits1[] = {0x4015dc39ddfb7863, 0x2422dc41b36a89e};
EXPECT_TRUE(isIntEqualsDigits(result.at(0), expected_digits1));
const uword expected_digits2[] = {0x58023143a26c3d63, 0x290c5dcb84cbb46f};
EXPECT_TRUE(isIntEqualsDigits(result.at(1), expected_digits2));
}
TEST_F(IntBuiltinsTest, DunderDivmodWithLargeIntPowerOfTwoReturnsTuple) {
HandleScope scope(thread_);
const uword digits_left[] = {0xee31ba892c71000e, 0x7175d128f7c2574a};
Object left(&scope, runtime_->newLargeIntWithDigits(digits_left));
const uword digits_right[] = {0, 1};
Object right(&scope, runtime_->newLargeIntWithDigits(digits_right));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
EXPECT_TRUE(isIntEqualsWord(result.at(0), 0x7175d128f7c2574a));
const uword expected_digits[] = {0xee31ba892c71000e, 0};
EXPECT_TRUE(isIntEqualsDigits(result.at(1), expected_digits));
}
TEST_F(IntBuiltinsTest,
DunderDivmodWithZeroDividendBiggerNegativeDivisorReturnsTuple) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(0));
const uword digits[] = {0, 1};
Object right(&scope, runtime_->newLargeIntWithDigits(digits));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
EXPECT_TRUE(isIntEqualsWord(result.at(0), 0));
EXPECT_TRUE(isIntEqualsWord(result.at(1), 0));
}
TEST_F(IntBuiltinsTest, DunderDivmodWithLargeIntNegativeDividendReturnsTuple) {
HandleScope scope(thread_);
const uword digits_left[] = {0x72a8be6d697d55c0, 0x9d95978dc878d9ae,
0xae86bef7900edb79};
Object left(&scope, runtime_->newLargeIntWithDigits(digits_left));
const uword digits_right[] = {0x9893b50147995ab1, 0x73537a3bc36c3a0e};
Object right(&scope, runtime_->newLargeIntWithDigits(digits_right));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
const uword expected_digits1[] = {0x4b2538374030ad53, 0xffffffffffffffff};
EXPECT_TRUE(isIntEqualsDigits(result.at(0), expected_digits1));
const uword expected_digits2[] = {0x2f13a2c4f4b515d, 0x38ab976c676089ea};
EXPECT_TRUE(isIntEqualsDigits(result.at(1), expected_digits2));
}
TEST_F(IntBuiltinsTest, DunderDivmodWithLargeIntNegativeDivisorReturnsTuple) {
HandleScope scope(thread_);
const uword digits_left[] = {0x11000235a5b61b48, 0x54cb34ee1cde8d78,
0x2ac801d0ae5dcf65};
Object left(&scope, runtime_->newLargeIntWithDigits(digits_left));
const uword digits_right[] = {0xfb2879c8be1e7dda, 0xf8101cf6608d0f6a};
Object right(&scope, runtime_->newLargeIntWithDigits(digits_right));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
const uword expected_digits1[] = {0x9c248b8175e4f19f, 0xfffffffffffffffa};
EXPECT_TRUE(isIntEqualsDigits(result.at(0), expected_digits1));
const uword expected_digits2[] = {0xdc2e58062423b6e2, 0xfa5dd4db30c9589e};
EXPECT_TRUE(isIntEqualsDigits(result.at(1), expected_digits2));
}
TEST_F(IntBuiltinsTest,
DunderDivmodWithLargeIntNegativeDividendNegativeDivisorReturnsTuple) {
HandleScope scope(thread_);
const uword digits_left[] = {0xc4b749b3bc2eb7e0, 0x74e4cc72dc8a2e9b,
0x46bb00bd468a1799, 0xc29ae4e0ae05134};
Object left(&scope, runtime_->newLargeIntWithDigits(digits_left));
const uword digits_right[] = {0x839c30dba1685693, 0xad0140cf78eaee70,
0xd77ec3cef0613585};
Object right(&scope, runtime_->newLargeIntWithDigits(digits_right));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
const uword expected_digits1[] = {0xb320ce53675ba5b0};
EXPECT_TRUE(isIntEqualsDigits(result.at(0), expected_digits1));
const uword expected_digits2[] = {0xfbf66d17996573d0, 0xfb57b237e188be27,
0xe9d7473ac0f6b873};
EXPECT_TRUE(isIntEqualsDigits(result.at(1), expected_digits2));
}
TEST_F(IntBuiltinsTest,
DunderDivmodWithLargeIntTriggeringNegateBugReturnsTuple) {
HandleScope scope(thread_);
const uword digits[] = {1, 0, 1};
Object left(&scope, runtime_->newLargeIntWithDigits(digits));
Object right(&scope, runtime_->newInt(-5));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
const uword expected_digits[] = {0xcccccccccccccccc, 0xcccccccccccccccc};
EXPECT_TRUE(isIntEqualsDigits(result.at(0), expected_digits));
EXPECT_TRUE(isIntEqualsWord(result.at(1), -3));
}
TEST_F(IntBuiltinsTest, DunderDivmodReturnsMinWordPlusOneModulo) {
HandleScope scope(thread_);
const uword left_digits[] = {1, 1};
Object left(&scope, runtime_->newLargeIntWithDigits(left_digits));
const uword right_digits[] = {static_cast<uword>(kMinWord)};
Object right(&scope, runtime_->newLargeIntWithDigits(right_digits));
Object result_obj(&scope, runBuiltin(METH(int, __divmod__), left, right));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
EXPECT_TRUE(isIntEqualsWord(result.at(0), -3));
const uword expected_digits[] = {static_cast<uword>(kMinWord) + 1};
EXPECT_TRUE(isIntEqualsDigits(result.at(1), expected_digits));
}
TEST_F(IntBuiltinsTest, DunderDivmodWithZeroRaisesZeroDivisionError) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(2));
Object right(&scope, runtime_->newInt(0));
Object result(&scope, runBuiltin(METH(int, __divmod__), left, right));
EXPECT_TRUE(raisedWithStr(*result, LayoutId::kZeroDivisionError,
"integer division or modulo by zero"));
}
TEST_F(IntBuiltinsTest, DunderDivmodWithNonIntSelfRaisesTypeError) {
HandleScope scope(thread_);
Object left(&scope, Str::empty());
Object right(&scope, runtime_->newInt(1));
Object result(&scope, runBuiltin(METH(int, __divmod__), left, right));
EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
}
TEST_F(IntBuiltinsTest, DunderDivmodWithNontIntReturnsNotImplemented) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(1));
Object right(&scope, Str::empty());
Object result(&scope, runBuiltin(METH(int, __divmod__), left, right));
EXPECT_TRUE(result.isNotImplementedType());
}
TEST_F(IntBuiltinsTest, DunderEqOnBool) {
HandleScope scope(thread_);
Object true_obj(&scope, Bool::trueObj());
EXPECT_EQ(runBuiltin(METH(int, __eq__), true_obj, true_obj), Bool::trueObj());
Object false_obj(&scope, Bool::falseObj());
EXPECT_EQ(runBuiltin(METH(int, __eq__), true_obj, false_obj),
Bool::falseObj());
Object zero(&scope, SmallInt::fromWord(0));
EXPECT_EQ(runBuiltin(METH(int, __eq__), true_obj, zero), Bool::falseObj());
Object one(&scope, SmallInt::fromWord(1));
EXPECT_EQ(runBuiltin(METH(int, __eq__), true_obj, one), Bool::trueObj());
}
TEST_F(IntBuiltinsTest, DunderNeOnBool) {
HandleScope scope(thread_);
Object true_obj(&scope, Bool::trueObj());
EXPECT_EQ(runBuiltin(METH(int, __ne__), true_obj, true_obj),
Bool::falseObj());
Object false_obj(&scope, Bool::falseObj());
EXPECT_EQ(runBuiltin(METH(int, __ne__), true_obj, false_obj),
Bool::trueObj());
Object zero(&scope, SmallInt::fromWord(0));
EXPECT_EQ(runBuiltin(METH(int, __ne__), true_obj, zero), Bool::trueObj());
Object one(&scope, SmallInt::fromWord(1));
EXPECT_EQ(runBuiltin(METH(int, __ne__), true_obj, one), Bool::falseObj());
}
TEST_F(IntBuiltinsTest, DunderNegWithSmallIntReturnsSmallInt) {
HandleScope scope(thread_);
Object num(&scope, runtime_->newInt(42));
Object result(&scope, runBuiltin(METH(int, __neg__), num));
EXPECT_TRUE(isIntEqualsWord(*result, -42));
}
TEST_F(IntBuiltinsTest, DunderNegWithSmallIntReturnsLargeInt) {
HandleScope scope(thread_);
Object num(&scope, runtime_->newInt(RawSmallInt::kMinValue));
Object result(&scope, runBuiltin(METH(int, __neg__), num));
EXPECT_TRUE(isIntEqualsWord(*result, -RawSmallInt::kMinValue));
}
TEST_F(IntBuiltinsTest, DunderNegWithBoolFalseReturnsSmallInt) {
HandleScope scope(thread_);
Object value(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, __neg__), value));
EXPECT_TRUE(isIntEqualsWord(*result, 0));
}
TEST_F(IntBuiltinsTest, DunderNegWithBoolTrueReturnsSmallInt) {
HandleScope scope(thread_);
Object value(&scope, Bool::trueObj());
Object result(&scope, runBuiltin(METH(int, __neg__), value));
EXPECT_TRUE(isIntEqualsWord(*result, -1));
}
TEST_F(IntBuiltinsTest, DunderNegWithLargeIntReturnsSmallInt) {
HandleScope scope(thread_);
Object num(&scope, runtime_->newInt(-RawSmallInt::kMinValue));
EXPECT_TRUE(num.isLargeInt());
Object result(&scope, runBuiltin(METH(int, __neg__), num));
EXPECT_TRUE(isIntEqualsWord(*result, RawSmallInt::kMinValue));
}
TEST_F(IntBuiltinsTest, DunderNegWithLargeIntReturnsLargeInt) {
HandleScope scope(thread_);
const uword digits[] = {0xad7721b1763aff22, 0x2afce48517f151b2};
Object num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __neg__), num));
const uword expected_digits[] = {0x5288de4e89c500de, 0xd5031b7ae80eae4d};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderNegWithLargeIntCarriesReturnsLargeInt) {
HandleScope scope(thread_);
const uword digits[] = {0, 0xfffffff000000000};
Object num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __neg__), num));
const uword expected_digits[] = {0, 0x1000000000};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderNegWithLargeIntOverflowsReturnsLargeInt) {
HandleScope scope(thread_);
const uword digits[] = {0, kHighbitUword};
Object num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __neg__), num));
const uword expected_digits[] = {0, kHighbitUword, 0};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderNegWithLargeIntShrinksReturnsLargeInt) {
HandleScope scope(thread_);
const uword digits[] = {kHighbitUword, 0};
Object num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __neg__), num));
const uword expected_digits[] = {kHighbitUword};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderNegWithLargeIntNoShrinksReturnsLargeInt) {
HandleScope scope(thread_);
const uword digits[] = {1, kHighbitUword, 0};
Object num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __neg__), num));
const uword expected_digits[] = {kMaxUword, kHighbitUword - 1, kMaxUword};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderPosAliasesDunderInt) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Type type(&scope, moduleAtByCStr(runtime_, "builtins", "int"));
Object pos_name(&scope, Runtime::internStrFromCStr(thread_, "__pos__"));
Object pos_obj(&scope, typeAt(type, pos_name));
ASSERT_TRUE(pos_obj.isFunction());
Function pos(&scope, *pos_obj);
Object dint_name(&scope, Runtime::internStrFromCStr(thread_, "__int__"));
Object dint_obj(&scope, typeAt(type, dint_name));
ASSERT_TRUE(dint_obj.isFunction());
Function dint(&scope, *pos_obj);
EXPECT_EQ(Code::cast(pos.code()).code(), Code::cast(dint.code()).code());
EXPECT_EQ(pos.entry(), dint.entry());
EXPECT_EQ(pos.entryKw(), dint.entryKw());
EXPECT_EQ(pos.entryEx(), dint.entryEx());
}
TEST_F(IntBuiltinsTest, DunderLtOnBool) {
HandleScope scope(thread_);
Object true_obj(&scope, Bool::trueObj());
Object false_obj(&scope, Bool::falseObj());
EXPECT_EQ(runBuiltin(METH(int, __lt__), true_obj, false_obj),
Bool::falseObj());
EXPECT_EQ(runBuiltin(METH(int, __lt__), false_obj, true_obj),
Bool::trueObj());
Object one(&scope, SmallInt::fromWord(1));
EXPECT_EQ(runBuiltin(METH(int, __lt__), false_obj, one), Bool::trueObj());
Object minus_one(&scope, SmallInt::fromWord(-1));
EXPECT_EQ(runBuiltin(METH(int, __lt__), false_obj, minus_one),
Bool::falseObj());
}
TEST_F(IntBuiltinsTest, DunderGeOnBool) {
HandleScope scope(thread_);
Object true_obj(&scope, Bool::trueObj());
Object false_obj(&scope, Bool::falseObj());
EXPECT_EQ(runBuiltin(METH(int, __ge__), true_obj, false_obj),
Bool::trueObj());
EXPECT_EQ(runBuiltin(METH(int, __ge__), false_obj, true_obj),
Bool::falseObj());
Object one(&scope, SmallInt::fromWord(1));
EXPECT_EQ(runBuiltin(METH(int, __ge__), false_obj, one), Bool::falseObj());
Object minus_one(&scope, SmallInt::fromWord(-1));
EXPECT_EQ(runBuiltin(METH(int, __ge__), false_obj, minus_one),
Bool::trueObj());
}
TEST_F(IntBuiltinsTest, DunderGtOnBool) {
HandleScope scope(thread_);
Object true_obj(&scope, Bool::trueObj());
Object false_obj(&scope, Bool::falseObj());
EXPECT_EQ(runBuiltin(METH(int, __gt__), true_obj, false_obj),
Bool::trueObj());
EXPECT_EQ(runBuiltin(METH(int, __gt__), false_obj, true_obj),
Bool::falseObj());
Object one(&scope, SmallInt::fromWord(1));
EXPECT_EQ(runBuiltin(METH(int, __gt__), false_obj, one), Bool::falseObj());
Object minus_one(&scope, SmallInt::fromWord(-1));
EXPECT_EQ(runBuiltin(METH(int, __gt__), false_obj, minus_one),
Bool::trueObj());
}
TEST_F(IntBuiltinsTest, DunderLeOnBool) {
HandleScope scope(thread_);
Object true_obj(&scope, Bool::trueObj());
Object false_obj(&scope, Bool::falseObj());
EXPECT_EQ(runBuiltin(METH(int, __le__), true_obj, false_obj),
Bool::falseObj());
EXPECT_EQ(runBuiltin(METH(int, __le__), false_obj, true_obj),
Bool::trueObj());
Object one(&scope, SmallInt::fromWord(1));
EXPECT_EQ(runBuiltin(METH(int, __le__), false_obj, one), Bool::trueObj());
Object minus_one(&scope, SmallInt::fromWord(-1));
EXPECT_EQ(runBuiltin(METH(int, __le__), false_obj, minus_one),
Bool::falseObj());
}
TEST_F(IntBuiltinsTest, DunderRoundAliasesDunderInt) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Type type(&scope, moduleAtByCStr(runtime_, "builtins", "int"));
Object round_name(&scope, Runtime::internStrFromCStr(thread_, "__round__"));
Object round_obj(&scope, typeAt(type, round_name));
ASSERT_TRUE(round_obj.isFunction());
Function round(&scope, *round_obj);
Object dint_name(&scope, Runtime::internStrFromCStr(thread_, "__int__"));
Object dint_obj(&scope, typeAt(type, dint_name));
ASSERT_TRUE(dint_obj.isFunction());
Function dint(&scope, *round_obj);
EXPECT_EQ(Code::cast(round.code()).code(), Code::cast(dint.code()).code());
EXPECT_EQ(round.entry(), dint.entry());
EXPECT_EQ(round.entryKw(), dint.entryKw());
EXPECT_EQ(round.entryEx(), dint.entryEx());
}
TEST_F(IntBuiltinsTest, DunderTruncAliasesDunderInt) {
HandleScope scope(thread_);
Type type(&scope, moduleAtByCStr(runtime_, "builtins", "int"));
Object trunc_name(&scope, Runtime::internStrFromCStr(thread_, "__trunc__"));
Object trunc_obj(&scope, typeAt(type, trunc_name));
ASSERT_TRUE(trunc_obj.isFunction());
Function trunc(&scope, *trunc_obj);
Object dint_name(&scope, Runtime::internStrFromCStr(thread_, "__int__"));
Object dint_obj(&scope, typeAt(type, dint_name));
ASSERT_TRUE(dint_obj.isFunction());
Function dint(&scope, *trunc_obj);
EXPECT_EQ(Code::cast(trunc.code()).code(), Code::cast(dint.code()).code());
EXPECT_EQ(trunc.entry(), dint.entry());
EXPECT_EQ(trunc.entryKw(), dint.entryKw());
EXPECT_EQ(trunc.entryEx(), dint.entryEx());
}
TEST_F(IntBuiltinsTest, FromBytesWithLittleEndianReturnsLargeInt) {
HandleScope scope(thread_);
ASSERT_FALSE(
runFromCStr(runtime_, "result = int.__radd__(True, 41)").isError());
Object result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_TRUE(isIntEqualsWord(*result, 42));
}
TEST_F(IntBuiltinsTest, DunderRandWithSmallIntsReturnsSmallInt) {
HandleScope scope(thread_);
ASSERT_FALSE(
runFromCStr(runtime_, "result = int.__rand__(0x123456789, 0x987654321)")
.isError());
Object result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_TRUE(isIntEqualsWord(*result, 0x103454301));
}
TEST_F(IntBuiltinsTest, DunderReprWithZeroReturnsStr) {
HandleScope scope(thread_);
Object num(&scope, runtime_->newInt(0));
Object result(&scope, runBuiltin(METH(int, __repr__), num));
EXPECT_TRUE(isStrEqualsCStr(*result, "0"));
}
TEST_F(IntBuiltinsTest, DunderReprWithSmallIntReturnsStr) {
HandleScope scope(thread_);
Object num(&scope, runtime_->newInt(0xdeadbeef));
Object result(&scope, runBuiltin(METH(int, __repr__), num));
EXPECT_TRUE(isStrEqualsCStr(*result, "3735928559"));
}
TEST_F(IntBuiltinsTest, DunderReprWithSmallIntMaxReturnsStr) {
HandleScope scope(thread_);
Object num(&scope, runtime_->newInt(RawSmallInt::kMaxValue));
Object result(&scope, runBuiltin(METH(int, __repr__), num));
EXPECT_TRUE(isStrEqualsCStr(*result, "4611686018427387903"));
}
TEST_F(IntBuiltinsTest, DunderReprWithSmallIntMinReturnsStr) {
HandleScope scope(thread_);
Object num(&scope, runtime_->newInt(RawSmallInt::kMinValue));
Object result(&scope, runBuiltin(METH(int, __repr__), num));
EXPECT_TRUE(isStrEqualsCStr(*result, "-4611686018427387904"));
}
TEST_F(IntBuiltinsTest, DunderReprWithBoolFalseReturnsStr) {
HandleScope scope(thread_);
Object num(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, __repr__), num));
EXPECT_TRUE(isStrEqualsCStr(*result, "0"));
}
TEST_F(IntBuiltinsTest, DunderReprWithBoolTrueReturnsStr) {
HandleScope scope(thread_);
Object num(&scope, Bool::trueObj());
Object result(&scope, runBuiltin(METH(int, __repr__), num));
EXPECT_TRUE(isStrEqualsCStr(*result, "1"));
}
TEST_F(IntBuiltinsTest, DunderReprWithLargeIntOneDigitReturnsStr) {
HandleScope scope(thread_);
const uword digits[] = {0x7ab65f95e6775822};
Object num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __repr__), num));
EXPECT_TRUE(isStrEqualsCStr(*result, "8842360015809894434"));
}
TEST_F(IntBuiltinsTest, DunderReprWithLargeIntOneDigitMinReturnsStr) {
HandleScope scope(thread_);
const uword digits[] = {0x8000000000000000};
Object num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __repr__), num));
EXPECT_TRUE(isStrEqualsCStr(*result, "-9223372036854775808"));
}
TEST_F(IntBuiltinsTest, DunderReprWithLargeIntOneDigitMaxReturnsStr) {
HandleScope scope(thread_);
const uword digits[] = {0x7fffffffffffffff};
Object num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __repr__), num));
EXPECT_TRUE(isStrEqualsCStr(*result, "9223372036854775807"));
}
TEST_F(IntBuiltinsTest, DunderReprWithLargeIntReturnsStr) {
HandleScope scope(thread_);
const uword digits[] = {0x68ccbb7f61087fb7, 0x4081e2972fe52778};
Object num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __repr__), num));
EXPECT_TRUE(
isStrEqualsCStr(*result, "85744993827831399429103580491677204407"));
}
TEST_F(IntBuiltinsTest, DunderReprWithNegativeLargeIntReturnsStr) {
HandleScope scope(thread_);
const uword digits[] = {0x49618108301eff93, 0xc70a0c6e0731da35,
0x438a2278e8762294, 0xccf89b106c9b714d,
0xfa694d4cbdf0b0ba};
Object num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __repr__), num));
EXPECT_TRUE(
isStrEqualsCStr(*result,
"-4663013431296140509759060231428418933437027788588076073"
"3669209802197774863968523736917349564525"));
}
TEST_F(IntBuiltinsTest, DunderReprWithLargeIntManyZerosReturnsStr) {
HandleScope scope(thread_);
const uword digits[] = {0x6ea69b2000000000, 0xf374ff2873cd99de, 0x375c24};
Object num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __repr__), num));
EXPECT_TRUE(isStrEqualsCStr(
*result, "1234567890000000000000000000000000000000000000"));
}
TEST_F(IntBuiltinsTest, DunderReprWithLargeIntCarriesReturnsStr) {
HandleScope scope(thread_);
const uword digits[] = {kMaxUword, uword{kMaxWord}, kMaxUword};
Object num(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __repr__), num));
EXPECT_TRUE(
isStrEqualsCStr(*result, "-170141183460469231731687303715884105729"));
}
TEST_F(IntBuiltinsTest, DunderReprWithIntSubclassReturnsStr) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
class X(int): pass
num = X(0xdeadbeef)
)")
.isError());
Object num(&scope, mainModuleAt(runtime_, "num"));
Object result(&scope, runBuiltin(METH(int, __repr__), num));
EXPECT_TRUE(isStrEqualsCStr(*result, "3735928559"));
}
TEST_F(IntBuiltinsTest, DunderRdivmodWithSmallIntsReturnsTuple) {
HandleScope scope(thread_);
ASSERT_FALSE(
runFromCStr(runtime_, "result = int.__rdivmod__(3, 11)").isError());
Object result_obj(&scope, mainModuleAt(runtime_, "result"));
ASSERT_TRUE(result_obj.isTuple());
Tuple result(&scope, *result_obj);
ASSERT_EQ(result.length(), 2);
EXPECT_TRUE(isIntEqualsWord(result.at(0), 3));
EXPECT_TRUE(isIntEqualsWord(result.at(1), 2));
}
TEST_F(IntBuiltinsTest, DunderRfloordivWithSmallIntsReturnsSmallInt) {
HandleScope scope(thread_);
ASSERT_FALSE(
runFromCStr(runtime_, "result = int.__rfloordiv__(3, 11)").isError());
Object result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_TRUE(isIntEqualsWord(*result, 3));
}
TEST_F(IntBuiltinsTest, DunderRlshiftWithSmallIntsReturnsSmallInt) {
HandleScope scope(thread_);
ASSERT_FALSE(
runFromCStr(runtime_, "result = int.__rlshift__(3, -7)").isError());
Object result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_TRUE(isIntEqualsWord(*result, -56));
}
TEST_F(IntBuiltinsTest, DunderRmodWithSmallIntsReturnsSmallInt) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, "result = int.__rmod__(3, 11)").isError());
Object result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_TRUE(isIntEqualsWord(*result, 2));
}
TEST_F(IntBuiltinsTest, DunderRmulWithSmallIntsReturnsSmallInt) {
HandleScope scope(thread_);
ASSERT_FALSE(
runFromCStr(runtime_, "result = int.__rmul__(-321, 123)").isError());
Object result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_TRUE(isIntEqualsWord(*result, -39483));
}
TEST_F(IntBuiltinsTest, DunderRorWithSmallIntsReturnsSmallInt) {
HandleScope scope(thread_);
ASSERT_FALSE(
runFromCStr(runtime_, "result = int.__ror__(0x123456789, 0x987654321)")
.isError());
Object result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_TRUE(isIntEqualsWord(*result, 0x9a76567a9));
}
TEST_F(IntBuiltinsTest, DunderRpowWithSmallIntsReturnsSmallInt) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, "result = int.__rpow__(8, 2)").isError());
Object result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_TRUE(isIntEqualsWord(*result, 256));
}
TEST_F(IntBuiltinsTest, DunderRrshiftWithSmallIntsReturnsSmallInt) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, "result = int.__rrshift__(16, 0xf00ddead)")
.isError());
Object result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_TRUE(isIntEqualsWord(*result, 0xf00d));
}
TEST_F(IntBuiltinsTest, DunderRshiftWithBoolsReturnsSmallInt) {
HandleScope scope(thread_);
Object left(&scope, Bool::trueObj());
Object right(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, __rshift__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, 1));
}
TEST_F(IntBuiltinsTest, DunderRshiftWithSmallIntsReturnsSmallInt) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(-1234));
Object right(&scope, runtime_->newInt(3));
Object result(&scope, runBuiltin(METH(int, __rshift__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, -155));
}
TEST_F(IntBuiltinsTest, DunderRshiftWithOversizedAmountSmallIntReturnsZero) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(1));
Object right(&scope, runtime_->newInt(kBitsPerWord));
Object result(&scope, runBuiltin(METH(int, __rshift__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, 0));
}
TEST_F(IntBuiltinsTest, DunderRshiftWithOversizedAmountLargeIntReturnsZero) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(1));
const uword digits[] = {1, 2};
Object right(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __rshift__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, 0));
}
TEST_F(IntBuiltinsTest, DunderRshiftWithLargeIntOversizedAmountReturnsZero) {
HandleScope scope(thread_);
const uword digits[] = {1, 2};
Object left(&scope, runtime_->newLargeIntWithDigits(digits));
Object right(&scope, runtime_->newInt(kBitsPerWord * 3));
Object result(&scope, runBuiltin(METH(int, __rshift__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, 0));
}
TEST_F(IntBuiltinsTest, DunderRshiftWithLargeIntsReturnsLargeInt) {
HandleScope scope(thread_);
const uword digits[] = {0x188518dcaaa656f7, 0x7459da1092edebab,
0x692e3b38af8dcfbe};
Object left(&scope, runtime_->newLargeIntWithDigits(digits));
Object right(&scope, runtime_->newInt(83));
Object result(&scope, runBuiltin(METH(int, __rshift__), left, right));
const uword expected_digits[] = {0xb9f7ce8b3b42125d, 0xd25c76715f1};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderRshiftWithLargeIntWholeWordReturnsLargeInt) {
HandleScope scope(thread_);
const uword digits[] = {0x1c386fefbb1baf3d, 0x379bcaa886c98c13,
0xe0f6379843f98b29, 0};
Object left(&scope, runtime_->newLargeIntWithDigits(digits));
Object right(&scope, runtime_->newInt(kBitsPerWord * 2));
Object result(&scope, runBuiltin(METH(int, __rshift__), left, right));
const uword expected_digits[] = {0xe0f6379843f98b29, 0};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderRshiftWithLargeIntNegativeReturnsLargeInt) {
HandleScope scope(thread_);
const uword digits[] = {0x3190ff6fa83269bc, 0xe7a1689a33ca9ae6};
Object left(&scope, runtime_->newLargeIntWithDigits(digits));
Object right(&scope, runtime_->newInt(13));
Object result(&scope, runBuiltin(METH(int, __rshift__), left, right));
const uword expected_digits[] = {0xd7318c87fb7d4193, 0xffff3d0b44d19e54};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderRshiftWithNegativeShiftAmountRaisesValueError) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(1));
Object right(&scope, runtime_->newInt(-4));
Object result(&scope, runBuiltin(METH(int, __rshift__), left, right));
EXPECT_TRUE(
raisedWithStr(*result, LayoutId::kValueError, "negative shift count"));
}
TEST_F(IntBuiltinsTest, DunderRshiftWithNonIntSelfRaisesTypeError) {
HandleScope scope(thread_);
Object left(&scope, Str::empty());
Object right(&scope, runtime_->newInt(0));
Object result(&scope, runBuiltin(METH(int, __rshift__), left, right));
EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
}
TEST_F(IntBuiltinsTest, DunderRshiftWithNonIntReturnsNotImplemented) {
HandleScope scope(thread_);
Object left(&scope, runtime_->newInt(0));
Object right(&scope, Str::empty());
Object result(&scope, runBuiltin(METH(int, __rshift__), left, right));
EXPECT_TRUE(result.isNotImplementedType());
}
TEST_F(IntBuiltinsTest, DunderRshiftWithIntSubclassReturnsInt) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
class X(int): pass
left = X(-1234)
right = X(3)
)")
.isError());
Object left(&scope, mainModuleAt(runtime_, "left"));
Object right(&scope, mainModuleAt(runtime_, "right"));
Object result(&scope, runBuiltin(METH(int, __rshift__), left, right));
EXPECT_EQ(result, SmallInt::fromWord(-155));
}
TEST_F(IntBuiltinsTest, DunderStrAliasesDunderRepr) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Type type(&scope, moduleAtByCStr(runtime_, "builtins", "int"));
Object str_name(&scope, Runtime::internStrFromCStr(thread_, "__str__"));
Object str_obj(&scope, typeAt(type, str_name));
ASSERT_TRUE(str_obj.isFunction());
Function str(&scope, *str_obj);
Object repr_name(&scope, Runtime::internStrFromCStr(thread_, "__repr__"));
Object repr_obj(&scope, typeAt(type, repr_name));
ASSERT_TRUE(repr_obj.isFunction());
Function repr(&scope, *str_obj);
EXPECT_EQ(Code::cast(str.code()).code(), Code::cast(repr.code()).code());
EXPECT_EQ(str.entry(), repr.entry());
EXPECT_EQ(str.entryKw(), repr.entryKw());
EXPECT_EQ(str.entryEx(), repr.entryEx());
}
TEST_F(IntBuiltinsTest, DunderSubWithSmallIntsReturnsSmallInt) {
HandleScope scope(thread_);
Int left(&scope, SmallInt::fromWord(42));
Int right(&scope, SmallInt::fromWord(-7));
Object result(&scope, runBuiltin(METH(int, __sub__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, 49));
}
TEST_F(IntBuiltinsTest, DunderSubWithSmallIntsOverflowReturnsLargeInt) {
HandleScope scope(thread_);
Int min_small_int(&scope, SmallInt::fromWord(RawSmallInt::kMinValue));
Int one(&scope, SmallInt::fromWord(1));
Object result(&scope, runBuiltin(METH(int, __sub__), min_small_int, one));
EXPECT_TRUE(isIntEqualsWord(*result, RawSmallInt::kMinValue - 1));
}
TEST_F(IntBuiltinsTest, DunderSubWithLargeIntsReturnsLargeInt) {
HandleScope scope(thread_);
const uword digits_left[] = {0xfedcba0987654321, 0x1234567890abcdef};
Int left(&scope, runtime_->newLargeIntWithDigits(digits_left));
const uword digits_right[] = {0x9876543210abcdef, 0xfedcba0123456789};
Int right(&scope, runtime_->newLargeIntWithDigits(digits_right));
Object result(&scope, runBuiltin(METH(int, __sub__), left, right));
const uword expected_digits[] = {0x666665d776b97532, 0x13579c776d666666};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest,
DunderSubWithPositiveLargeIntsBorrowingReturnsLargeInt) {
HandleScope scope(thread_);
Int left(&scope, runtime_->newInt(1));
const uword digits_right[] = {kMaxUword, kMaxUword, 0};
Int right(&scope, runtime_->newLargeIntWithDigits(digits_right));
Object result(&scope, runBuiltin(METH(int, __sub__), left, right));
const uword expected_digits[] = {2, 0, kMaxUword};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest,
DunderSubWithNegativeLargeIntsBorrowingReturnsLargeInt) {
HandleScope scope(thread_);
// The smallest negative number representable with 2 digits.
const uword digits_left[] = {0, static_cast<uword>(kMinWord)};
Int left(&scope, runtime_->newLargeIntWithDigits(digits_left));
Int right(&scope, runtime_->newInt(1));
Object result(&scope, runBuiltin(METH(int, __sub__), left, right));
const uword expected_digits[] = {kMaxUword, uword{kMaxWord}, kMaxUword};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderSubWithNonIntSelfRaisesTypeError) {
HandleScope scope(thread_);
Str str(&scope, Str::empty());
Int right(&scope, runtime_->newInt(1));
Object result(&scope, runBuiltin(METH(int, __sub__), str, right));
EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
}
TEST_F(IntBuiltinsTest, DunderSubWithNonIntRightReturnsNotImplemented) {
HandleScope scope(thread_);
Int left(&scope, runtime_->newInt(1));
Str str(&scope, Str::empty());
Object result(&scope, runBuiltin(METH(int, __sub__), left, str));
EXPECT_TRUE(result.isNotImplementedType());
}
TEST_F(IntBuiltinsTest, DunderXorWithSmallIntsReturnsSmallInt) {
HandleScope scope(thread_);
Int left(&scope, SmallInt::fromWord(0x15)); // 0b010101
Int right(&scope, SmallInt::fromWord(0x38)); // 0b111000
Object result(&scope, runBuiltin(METH(int, __xor__), left, right));
EXPECT_TRUE(isIntEqualsWord(*result, 0x2D)); // 0b101101
}
TEST_F(IntBuiltinsTest, DunderXorWithLargeIntsReturnsLargeInt) {
HandleScope scope(thread_);
const uword digits_left[] = {0x0f, 0x30, 0xCAFE};
Int left(&scope, runtime_->newLargeIntWithDigits(digits_left));
const uword digits_right[] = {0x03, 0xf0};
Int right(&scope, runtime_->newLargeIntWithDigits(digits_right));
Object result(&scope, runBuiltin(METH(int, __xor__), left, right));
const uword expected_digits[] = {0x0C, 0xC0, 0xCAFE};
EXPECT_TRUE(isIntEqualsDigits(*result, expected_digits));
}
TEST_F(IntBuiltinsTest, DunderXorWithNonIntReturnsNotImplemented) {
HandleScope scope(thread_);
const uword digits[] = {1, 2};
Int left(&scope, runtime_->newLargeIntWithDigits(digits));
Object right(&scope, Str::empty());
Object result(&scope, runBuiltin(METH(int, __xor__), left, right));
EXPECT_TRUE(result.isNotImplementedType());
}
TEST_F(IntBuiltinsTest, DunderXorWithInvalidArgumentLeftRaisesException) {
HandleScope scope(thread_);
Object left(&scope, Str::empty());
const uword digits[] = {1, 2};
LargeInt right(&scope, runtime_->newLargeIntWithDigits(digits));
Object result(&scope, runBuiltin(METH(int, __xor__), left, right));
EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
}
TEST_F(IntBuiltinsTest, DunderXorWithIntSubclassReturnsInt) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
class X(int): pass
left = X(0b0011)
right = X(0b0101)
)")
.isError());
Object left(&scope, mainModuleAt(runtime_, "left"));
Object right(&scope, mainModuleAt(runtime_, "right"));
Object result(&scope, runBuiltin(METH(int, __xor__), left, right));
EXPECT_EQ(result, SmallInt::fromWord(6)); // 0b0110
}
TEST_F(IntBuiltinsTest, ToBytesWithByteorderLittleEndianReturnsBytes) {
HandleScope scope(thread_);
Int num(&scope, SmallInt::fromWord(42));
Int length(&scope, SmallInt::fromWord(3));
Str byteorder(&scope, runtime_->newStrFromCStr("little"));
Bool signed_obj(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, to_bytes), num, length, byteorder,
signed_obj));
const byte bytes[] = {42, 0, 0};
EXPECT_TRUE(isBytesEqualsBytes(result, bytes));
}
TEST_F(IntBuiltinsTest, ToBytesWithIntSubclassReturnsBytes) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
class X(int): pass
num = X(42)
length = X(3)
)")
.isError());
Object num(&scope, mainModuleAt(runtime_, "num"));
Object length(&scope, mainModuleAt(runtime_, "length"));
Object byteorder(&scope, runtime_->newStrFromCStr("little"));
Object signed_obj(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, to_bytes), num, length, byteorder,
signed_obj));
const byte bytes[] = {42, 0, 0};
EXPECT_TRUE(isBytesEqualsBytes(result, bytes));
}
TEST_F(IntBuiltinsTest, ToBytesWithByteorderBigEndianReturnsBytes) {
HandleScope scope(thread_);
Int num(&scope, SmallInt::fromWord(42));
Int length(&scope, SmallInt::fromWord(2));
Str byteorder(&scope, runtime_->newStrFromCStr("big"));
Bool signed_obj(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, to_bytes), num, length, byteorder,
signed_obj));
const byte bytes[] = {0, 42};
EXPECT_TRUE(isBytesEqualsBytes(result, bytes));
}
TEST_F(IntBuiltinsTest, ToBytesKwReturnsBytes) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
x0 = (0x1234).to_bytes(2, 'little')
x1 = (0x1234).to_bytes(2, 'little', signed=False)
x2 = (0x1234).to_bytes(2, 'little', signed=True)
x3 = (0x1234).to_bytes(2, byteorder='little')
x4 = (0x1234).to_bytes(length=2, byteorder='little')
x5 = (0x1234).to_bytes(2, byteorder='little', signed=False)
x6 = (0x1234).to_bytes(signed=False, byteorder='little', length=2)
)")
.isError());
const byte bytes[] = {0x34, 0x12};
for (const char* name : {"x0", "x1", "x2", "x3", "x4", "x5", "x6"}) {
Object x(&scope, mainModuleAt(runtime_, name));
EXPECT_TRUE(isBytesEqualsBytes(x, bytes)) << name;
}
}
TEST_F(IntBuiltinsTest, ToBytesKwWithNegativeNumberReturnsBytes) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
x0 = (-777).to_bytes(4, 'little', signed=True)
)")
.isError());
Object x(&scope, mainModuleAt(runtime_, "x0"));
const byte bytes[] = {0xf7, 0xfc, 0xff, 0xff};
EXPECT_TRUE(isBytesEqualsBytes(x, bytes));
}
TEST_F(IntBuiltinsTest, ToBytesWithSignedFalseReturnsBytes) {
HandleScope scope(thread_);
Str byteorder(&scope, runtime_->newStrFromCStr("little"));
// Test that the following numbers work fine with `signed=False` (they are the
// same numbers that are expected to overflow with `signed=True` in
// ToBytesWithSignedTrueOverflowRaisesOverflowError)
Int length_1(&scope, SmallInt::fromWord(1));
Int num_128(&scope, SmallInt::fromWord(128));
Bool signed_obj(&scope, Bool::falseObj());
Object result_128(&scope, runBuiltin(METH(int, to_bytes), num_128, length_1,
byteorder, signed_obj));
const byte bytes[] = {0x80};
EXPECT_TRUE(isBytesEqualsBytes(result_128, bytes));
Int length_2(&scope, SmallInt::fromWord(2));
Int num_32768(&scope, SmallInt::fromWord(32768));
Object result_32768(&scope, runBuiltin(METH(int, to_bytes), num_32768,
length_2, byteorder, signed_obj));
const byte bytes2[] = {0, 0x80};
EXPECT_TRUE(isBytesEqualsBytes(result_32768, bytes2));
Int length_8(&scope, SmallInt::fromWord(8));
const uword digits[] = {0x8000000000000000, 0};
Int num_min_word(&scope, runtime_->newLargeIntWithDigits(digits));
Object result_min_word(&scope, runBuiltin(METH(int, to_bytes), num_min_word,
length_8, byteorder, signed_obj));
const byte bytes3[] = {0, 0, 0, 0, 0, 0, 0, 0x80};
EXPECT_TRUE(isBytesEqualsBytes(result_min_word, bytes3));
}
TEST_F(IntBuiltinsTest, ToBytesWithLargeBufferByteorderBigEndianReturnsBytes) {
HandleScope scope(thread_);
// Test sign extension with zero when the buffer is larger than necessary.
Int num(&scope, SmallInt::fromWord(0xcafebabe));
Int length(&scope, SmallInt::fromWord(10));
Str byteorder(&scope, runtime_->newStrFromCStr("big"));
Bool signed_obj(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, to_bytes), num, length, byteorder,
signed_obj));
const byte bytes[] = {0, 0, 0, 0, 0, 0, 0xca, 0xfe, 0xba, 0xbe};
EXPECT_TRUE(isBytesEqualsBytes(result, bytes));
}
TEST_F(IntBuiltinsTest,
ToBytesWithLargeBufferByteorderLittleEndianReturnsBytes) {
HandleScope scope(thread_);
// Test sign extension with zero when the buffer is larger than necessary.
Int num(&scope, SmallInt::fromWord(0xcafebabe));
Int length(&scope, SmallInt::fromWord(10));
Str byteorder(&scope, runtime_->newStrFromCStr("little"));
Bool signed_obj(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, to_bytes), num, length, byteorder,
signed_obj));
const byte bytes[] = {0xbe, 0xba, 0xfe, 0xca, 0, 0, 0, 0, 0, 0};
EXPECT_TRUE(isBytesEqualsBytes(result, bytes));
}
TEST_F(IntBuiltinsTest, ToBytesWithSignedTrueReturnsBytes) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
result = (0x7fffffffffffffff).to_bytes(8, 'little', signed=True)
)")
.isError());
Object result(&scope, mainModuleAt(runtime_, "result"));
const byte bytes[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f};
EXPECT_TRUE(isBytesEqualsBytes(result, bytes));
ASSERT_FALSE(runFromCStr(runtime_, R"(
result_n_128 = (-128).to_bytes(1, 'little', signed=True)
)")
.isError());
Object result_n_128(&scope, mainModuleAt(runtime_, "result_n_128"));
const byte bytes2[] = {0x80};
EXPECT_TRUE(isBytesEqualsBytes(result_n_128, bytes2));
ASSERT_FALSE(runFromCStr(runtime_, R"(
result_n_32768 = (-32768).to_bytes(2, 'little', signed=True)
)")
.isError());
Object result_n_32768(&scope, mainModuleAt(runtime_, "result_n_32768"));
const byte bytes3[] = {0, 0x80};
EXPECT_TRUE(isBytesEqualsBytes(result_n_32768, bytes3));
ASSERT_FALSE(runFromCStr(runtime_, R"(
result_n_min_word = (-9223372036854775808).to_bytes(8, 'little', signed=True)
)")
.isError());
Object result_n_min_word(&scope, mainModuleAt(runtime_, "result_n_min_word"));
const byte bytes4[] = {0, 0, 0, 0, 0, 0, 0, 0x80};
EXPECT_TRUE(isBytesEqualsBytes(result_n_min_word, bytes4));
}
TEST_F(IntBuiltinsTest,
ToBytesWithNegativeNumberLargeBufferBigEndianReturnsBytes) {
HandleScope scope(thread_);
// test sign extension for negative number when buffer is larger than
// necessary.
ASSERT_FALSE(runFromCStr(runtime_, R"(
result = (-1024).to_bytes(7, 'big', signed=True)
)")
.isError());
Object result(&scope, mainModuleAt(runtime_, "result"));
const byte bytes[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0};
EXPECT_TRUE(isBytesEqualsBytes(result, bytes));
}
TEST_F(IntBuiltinsTest, ToBytesWithZeroLengthBigEndianReturnsEmptyBytes) {
HandleScope scope(thread_);
Int num(&scope, SmallInt::fromWord(0));
Int length(&scope, SmallInt::fromWord(0));
Str byteorder(&scope, runtime_->newStrFromCStr("big"));
Bool signed_obj(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, to_bytes), num, length, byteorder,
signed_obj));
ASSERT_TRUE(isBytesEqualsBytes(result, View<byte>(nullptr, 0)));
}
TEST_F(IntBuiltinsTest, ToBytesWithZeroLengthLittleEndianReturnsEmptyBytes) {
HandleScope scope(thread_);
Int num(&scope, SmallInt::fromWord(0));
Int length(&scope, SmallInt::fromWord(0));
Str byteorder(&scope, runtime_->newStrFromCStr("little"));
Bool signed_obj(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, to_bytes), num, length, byteorder,
signed_obj));
ASSERT_TRUE(isBytesEqualsBytes(result, View<byte>(nullptr, 0)));
}
TEST_F(IntBuiltinsTest, ToBytesWithSignedFalseRaisesOverflowError) {
HandleScope scope(thread_);
Int num(&scope, SmallInt::fromWord(256));
Int length(&scope, SmallInt::fromWord(1));
Str byteorder(&scope, runtime_->newStrFromCStr("little"));
Bool signed_obj(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, to_bytes), num, length, byteorder,
signed_obj));
EXPECT_TRUE(raised(*result, LayoutId::kOverflowError));
}
TEST_F(IntBuiltinsTest, ToBytesWithBigOverflowRaisesOverflowError) {
HandleScope scope(thread_);
const uword digits[] = {1, 2, 3};
Int num(&scope, runtime_->newLargeIntWithDigits(digits));
Int length(&scope, SmallInt::fromWord(13));
Str byteorder(&scope, runtime_->newStrFromCStr("little"));
Bool signed_obj(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, to_bytes), num, length, byteorder,
signed_obj));
EXPECT_TRUE(raised(*result, LayoutId::kOverflowError));
}
TEST_F(IntBuiltinsTest, ToBytesWithSignedTrueRaisesOverflowError) {
Thread* thread = Thread::current();
// Now check that signed=True with the same inputs triggers an error.
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
result = (128).to_bytes(1, 'little', signed=True)
)"),
LayoutId::kOverflowError,
"int too big to convert"));
thread->clearPendingException();
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
result = (32768).to_bytes(2, 'little', signed=True)
)"),
LayoutId::kOverflowError,
"int too big to convert"));
thread->clearPendingException();
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
result = (0x8000000000000000).to_bytes(8, 'little', signed=True)
)"),
LayoutId::kOverflowError,
"int too big to convert"));
}
TEST_F(IntBuiltinsTest, ToBytesWithNonIntRaisesTypeError) {
HandleScope scope(thread_);
Str str(&scope, runtime_->newStrFromCStr("not an int"));
Int length(&scope, SmallInt::fromWord(10));
Str byteorder(&scope, runtime_->newStrFromCStr("little"));
Bool signed_obj(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, to_bytes), str, length, byteorder,
signed_obj));
EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
}
TEST_F(IntBuiltinsTest, ToBytesWithInvalidLengthArgRaisesTypeError) {
HandleScope scope(thread_);
Int num(&scope, SmallInt::fromWord(42));
Str not_a_length(&scope, runtime_->newStrFromCStr("not a length"));
Str byteorder(&scope, runtime_->newStrFromCStr("little"));
Bool signed_obj(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, to_bytes), num, not_a_length,
byteorder, signed_obj));
EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
}
TEST_F(IntBuiltinsTest, ToBytesWithInvalidLengthArgRaisesValueError) {
HandleScope scope(thread_);
Int num(&scope, SmallInt::fromWord(42));
Int negative_length(&scope, SmallInt::fromWord(-3));
Str byteorder(&scope, runtime_->newStrFromCStr("little"));
Bool signed_obj(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, to_bytes), num, negative_length,
byteorder, signed_obj));
EXPECT_TRUE(raised(*result, LayoutId::kValueError));
}
TEST_F(IntBuiltinsTest, ToBytesWithInvalidLengthArgRaisesOverflowError) {
HandleScope scope(thread_);
Int num(&scope, SmallInt::fromWord(42));
const uword digits[] = {0, 1024};
Int huge_length(&scope, runtime_->newLargeIntWithDigits(digits));
Str byteorder(&scope, runtime_->newStrFromCStr("little"));
Bool signed_obj(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, to_bytes), num, huge_length,
byteorder, signed_obj));
EXPECT_TRUE(raised(*result, LayoutId::kOverflowError));
}
TEST_F(IntBuiltinsTest, ToBytesWithNegativeNumberRaisesOverflowError) {
HandleScope scope(thread_);
Int num(&scope, SmallInt::fromWord(-1));
Int length(&scope, SmallInt::fromWord(10));
Str byteorder(&scope, runtime_->newStrFromCStr("little"));
Bool signed_obj(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, to_bytes), num, length, byteorder,
signed_obj));
EXPECT_TRUE(raised(*result, LayoutId::kOverflowError));
}
TEST_F(IntBuiltinsTest, ToBytesWithInvalidByteorderStringRaisesValueError) {
HandleScope scope(thread_);
Int num(&scope, SmallInt::fromWord(42));
Int length(&scope, SmallInt::fromWord(3));
Str invalid_byteorder(&scope, runtime_->newStrFromCStr("hello"));
Bool signed_obj(&scope, Bool::falseObj());
Object result(&scope, runBuiltin(METH(int, to_bytes), num, length,
invalid_byteorder, signed_obj));
EXPECT_TRUE(raised(*result, LayoutId::kValueError));
}
TEST_F(IntBuiltinsTest, ToBytesWithInvalidByteorderTypeRaisesTypeError) {
HandleScope scope(thread_);
Int num(&scope, SmallInt::fromWord(42));
Int length(&scope, SmallInt::fromWord(3));
Bool signed_obj(&scope, Bool::falseObj());
Object result(&scope,
runBuiltin(METH(int, to_bytes), num, length, num, signed_obj));
EXPECT_TRUE(raised(*result, LayoutId::kTypeError));
}
TEST_F(BoolBuiltinsTest, NewFromNonZeroIntegerReturnsTrue) {
HandleScope scope(thread_);
Type type(&scope, runtime_->typeAt(LayoutId::kBool));
Int num(&scope, SmallInt::fromWord(2));
Bool result(&scope, runBuiltin(METH(bool, __new__), type, num));
EXPECT_TRUE(result.value());
}
TEST_F(BoolBuiltinsTest, NewFromZerorReturnsFalse) {
HandleScope scope(thread_);
Type type(&scope, runtime_->typeAt(LayoutId::kBool));
Int num(&scope, SmallInt::fromWord(0));
Bool result(&scope, runBuiltin(METH(bool, __new__), type, num));
EXPECT_FALSE(result.value());
}
TEST_F(BoolBuiltinsTest, NewFromTrueReturnsTrue) {
HandleScope scope(thread_);
Type type(&scope, runtime_->typeAt(LayoutId::kBool));
Object true_obj(&scope, Bool::trueObj());
Bool result(&scope, runBuiltin(METH(bool, __new__), type, true_obj));
EXPECT_TRUE(result.value());
}
TEST_F(BoolBuiltinsTest, NewFromFalseReturnsTrue) {
HandleScope scope(thread_);
Type type(&scope, runtime_->typeAt(LayoutId::kBool));
Object false_obj(&scope, Bool::falseObj());
Bool result(&scope, runBuiltin(METH(bool, __new__), type, false_obj));
EXPECT_FALSE(result.value());
}
TEST_F(BoolBuiltinsTest, NewFromNoneIsFalse) {
HandleScope scope(thread_);
Type type(&scope, runtime_->typeAt(LayoutId::kBool));
Object none(&scope, NoneType::object());
Bool result(&scope, runBuiltin(METH(bool, __new__), type, none));
EXPECT_FALSE(result.value());
}
TEST_F(BoolBuiltinsTest, NewFromUserDefinedType) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class Foo:
def __bool__(self):
return True
class Bar:
def __bool__(self):
return False
foo = Foo()
bar = Bar()
)")
.isError());
HandleScope scope(thread_);
Object foo(&scope, mainModuleAt(runtime_, "foo"));
Object bar(&scope, mainModuleAt(runtime_, "bar"));
{
Type type(&scope, runtime_->typeAt(LayoutId::kBool));
Bool result(&scope, runBuiltin(METH(bool, __new__), type, foo));
EXPECT_TRUE(result.value());
}
{
Type type(&scope, runtime_->typeAt(LayoutId::kBool));
Bool result(&scope, runBuiltin(METH(bool, __new__), type, bar));
EXPECT_FALSE(result.value());
}
}
TEST_F(IntBuiltinsTest, DunderTrueDivWithZeroLeftReturnsZero) {
HandleScope scope(thread_);
Int left(&scope, SmallInt::fromWord(0));
Int right(&scope, SmallInt::fromWord(17));
Object result(&scope, runBuiltin(METH(int, __truediv__), left, right));
ASSERT_TRUE(result.isFloat());
Float flt(&scope, *result);
EXPECT_EQ(flt.value(), 0.0);
}
TEST_F(IntBuiltinsTest, DunderTrueDivWithBoolFalseRaisesZeroDivisionError) {
HandleScope scope(thread_);
Object numerator(&scope, SmallInt::fromWord(10));
Object denominator(&scope, Bool::falseObj());
EXPECT_TRUE(
raisedWithStr(runBuiltin(METH(int, __truediv__), numerator, denominator),
LayoutId::kZeroDivisionError, "division by zero"));
}
TEST_F(IntBuiltinsTest, DunderTrueDivWithIntZeroRaisesZeroDivisionError) {
HandleScope scope(thread_);
Object numerator(&scope, SmallInt::fromWord(10));
Object denominator(&scope, SmallInt::fromWord(0));
EXPECT_TRUE(
raisedWithStr(runBuiltin(METH(int, __truediv__), numerator, denominator),
LayoutId::kZeroDivisionError, "division by zero"));
}
TEST_F(IntBuiltinsTest, DunderTrueDivWithFloatRightReturnsNotImplemented) {
HandleScope scope(thread_);
Object left(&scope, SmallInt::fromWord(100));
Object right(&scope, runtime_->newFloat(1.5));
Object result(&scope, runBuiltin(METH(int, __truediv__), left, right));
EXPECT_EQ(result, NotImplementedType::object());
}
TEST_F(IntBuiltinsTest, DunderTrueDivWithSmallIntsReturnsFloat) {
HandleScope scope(thread_);
Object num1(&scope, SmallInt::fromWord(6));
Object num2(&scope, SmallInt::fromWord(3));
Float result(&scope, runBuiltin(METH(int, __truediv__), num1, num2));
EXPECT_NEAR(result.value(), 2.0, DBL_EPSILON);
num1 = SmallInt::fromWord(7);
num2 = SmallInt::fromWord(3);
result = runBuiltin(METH(int, __truediv__), num1, num2);
EXPECT_NEAR(result.value(), 2.3333333333333335, DBL_EPSILON);
}
TEST_F(IntBuiltinsTest, ConjugateAliasesDunderInt) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Type type(&scope, moduleAtByCStr(runtime_, "builtins", "int"));
Object conjugate_name(&scope,
Runtime::internStrFromCStr(thread_, "conjugate"));
Object conjugate_obj(&scope, typeAt(type, conjugate_name));
ASSERT_TRUE(conjugate_obj.isFunction());
Function conjugate(&scope, *conjugate_obj);
Object dint_name(&scope, Runtime::internStrFromCStr(thread_, "__int__"));
Object dint_obj(&scope, typeAt(type, dint_name));
ASSERT_TRUE(dint_obj.isFunction());
Function dint(&scope, *conjugate_obj);
EXPECT_EQ(Code::cast(conjugate.code()).code(),
Code::cast(dint.code()).code());
EXPECT_EQ(conjugate.entry(), dint.entry());
EXPECT_EQ(conjugate.entryKw(), dint.entryKw());
EXPECT_EQ(conjugate.entryEx(), dint.entryEx());
}
TEST_F(IntBuiltinsTest, DenominatorReturnsOne) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, "result = (44).denominator").isError());
Object result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_TRUE(isIntEqualsWord(*result, 1));
}
TEST_F(IntBuiltinsTest, ImagReturnsZero) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, "result = (44).imag").isError());
Object result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_TRUE(isIntEqualsWord(*result, 0));
}
TEST_F(IntBuiltinsTest, NumeratorReturnsInt) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, "result = (44).numerator").isError());
Object result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_TRUE(isIntEqualsWord(*result, 44));
}
TEST_F(IntBuiltinsTest, RealReturnsInt) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, "result = (44).real").isError());
Object result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_TRUE(isIntEqualsWord(*result, 44));
}
TEST_F(IntBuiltinsTest, CompareWithBigNegativeNumber) {
ASSERT_FALSE(runFromCStr(runtime_, "a = -46116860184273879030000").isError());
HandleScope scope(thread_);
Int a(&scope, mainModuleAt(runtime_, "a"));
Int b(&scope, SmallInt::fromWord(SmallInt::kMinValue));
EXPECT_LT(a.compare(*b), 0);
EXPECT_GT(b.compare(*a), 0);
}
} // namespace testing
} // namespace py