runtime/bytes-builtins-test.cpp (1,579 lines of code) (raw):

// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) #include "bytes-builtins.h" #include "gtest/gtest.h" #include "builtins.h" #include "test-utils.h" namespace py { namespace testing { using BytesBuiltinsTest = RuntimeFixture; using BytesIteratorBuiltinsTest = RuntimeFixture; TEST_F(BytesBuiltinsTest, BuiltinBaseIsBytes) { HandleScope scope(thread_); Type bytes_type(&scope, runtime_->typeAt(LayoutId::kBytes)); EXPECT_EQ(bytes_type.builtinBase(), LayoutId::kBytes); } TEST_F(BytesBuiltinsTest, BytesIsValidUTF8ReturnsTrue) { EXPECT_TRUE(bytesIsValidUTF8(Bytes::empty())); HandleScope scope(thread_); const byte zeros_bytes[] = {0, 0, 0}; Bytes zeros(&scope, runtime_->newBytesWithAll(zeros_bytes)); EXPECT_TRUE(bytesIsValidUTF8(*zeros)); const byte test0[] = {'S', ':', 'a'}; EXPECT_TRUE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test0)))); const byte test1[] = {'S', ':', 0xC3, 0xA4}; EXPECT_TRUE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test1)))); const byte test2[] = {'S', ':', 0xE2, 0x88, 0x91}; EXPECT_TRUE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test2)))); const byte test3[] = {'S', ':', 0xF0, 0x9F, 0x90, 0x8D}; EXPECT_TRUE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test3)))); const byte test_misc[] = {0xEC, 0x95, 0x88, 0xEB, 0x85, 0x95, ' ', 0xEC, 0x84, 0xB8, 0xEC, 0x83, 0x81, 0}; EXPECT_TRUE( bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test_misc)))); const byte max_unicode[] = {0xF4, 0x8F, 0xBF, 0xBF}; EXPECT_TRUE( bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(max_unicode)))); const byte min_surrogate_minus_one[] = {0xED, 0x9F, 0xBF}; EXPECT_TRUE(bytesIsValidUTF8( Bytes::cast(runtime_->newBytesWithAll(min_surrogate_minus_one)))); const byte max_surrogate_plus_one[] = {0xEE, 0x80, 0x80}; EXPECT_TRUE(bytesIsValidUTF8( Bytes::cast(runtime_->newBytesWithAll(max_surrogate_plus_one)))); } TEST_F(BytesBuiltinsTest, BytesIsValidUTF8WithContinuationAfterValidCharReturnsFalse) { const byte test0[] = {0x80}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test0)))); const byte test1[] = {'a', 0xB3}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test1)))); const byte test2[] = {0xC3, 0xA4, 0xB3}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test2)))); const byte test3[] = {0xE2, 0x88, 0x91, 0xB3}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test3)))); const byte test4[] = {0xF0, 0x9F, 0x90, 0x8D, 0xB3}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test4)))); } TEST_F(BytesBuiltinsTest, BytesIsValidUTF8WithMissingContinuationReturnsFalse) { const byte test0[] = {0xC3}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test0)))); const byte test1[] = {0xC3, 0}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test1)))); const byte test2[] = {0xE2}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test2)))); const byte test3[] = {0xE2, 0}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test3)))); const byte test5[] = {0xE2, 0x88}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test5)))); const byte test4[] = {0xE2, 0, 0}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test4)))); const byte test6[] = {0xE2, 0x88, 0}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test6)))); const byte test7[] = {0xF0}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test7)))); const byte test8[] = {0xF0, 0}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test8)))); const byte test9[] = {0xF0, 0x9F}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test9)))); const byte test10[] = {0xF0, 0, 0}; EXPECT_FALSE( bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test10)))); const byte test11[] = {0xF0, 0x9F, 0}; EXPECT_FALSE( bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test11)))); const byte test12[] = {0xF0, 0x9F, 0x90}; EXPECT_FALSE( bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test12)))); const byte test13[] = {0xF0, 0, 0, 0}; EXPECT_FALSE( bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test13)))); const byte test14[] = {0xF0, 0x9F, 0x90, 0}; EXPECT_FALSE( bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test14)))); } TEST_F(BytesBuiltinsTest, BytesIsValidUTF8WithValueTooSmallForEncodingReturnsFalse) { const byte test0[] = {0xC0, 0x84}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test0)))); const byte test1[] = {0xE0, 0x80, 0x80}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test1)))); const byte test2[] = {0xE0, 0x9F, 0xBF}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test2)))); const byte test3[] = {0xF0, 0x80, 0x80, 0x80}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test3)))); const byte test4[] = {0xF0, 0x80, 0x9F, 0xBF}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test4)))); const byte test5[] = {0xF4, 0x90, 0x80, 0x80}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test5)))); const byte test6[] = {0xF7, 0xBF, 0xBF, 0xBF}; EXPECT_FALSE(bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(test6)))); } TEST_F(BytesBuiltinsTest, BytesIsValidUTF8WithSurrogateReturnsFalse) { const byte min_surrogate[] = {0xED, 0xA0, 0x80}; EXPECT_FALSE( bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(min_surrogate)))); const byte max_surrogate[] = {0xED, 0xBF, 0xBF}; EXPECT_FALSE( bytesIsValidUTF8(Bytes::cast(runtime_->newBytesWithAll(max_surrogate)))); } TEST_F(BytesBuiltinsTest, BytesIsValidStrWithSurrogateReturnsTrue) { const byte min_surrogate[] = {0xED, 0xA0, 0x80}; EXPECT_TRUE( bytesIsValidStr(Bytes::cast(runtime_->newBytesWithAll(min_surrogate)))); const byte max_surrogate[] = {0xED, 0xBF, 0xBF}; EXPECT_TRUE( bytesIsValidStr(Bytes::cast(runtime_->newBytesWithAll(max_surrogate)))); } TEST_F(BytesBuiltinsTest, BytesSubseqReturnsBytes) { HandleScope scope(thread_); View<byte> hello(reinterpret_cast<const byte*>("Hello world!"), 12); Bytes bytes(&scope, runtime_->newBytesWithAll(hello)); ASSERT_EQ(bytes.length(), 12); Bytes copy(&scope, bytesSubseq(thread_, bytes, 6, 5)); EXPECT_TRUE(isBytesEqualsCStr(copy, "world")); } TEST_F(BytesBuiltinsTest, FindWithSameBytesReturnsZero) { HandleScope scope(thread_); const byte haystack_bytes[] = {102, 55, 100, 74, 91, 118}; Bytes haystack(&scope, runtime_->newBytesWithAll(haystack_bytes)); word start = 0; word end = haystack.length(); word result = bytesFind(haystack, haystack.length(), haystack, haystack.length(), start, end); EXPECT_EQ(result, 0); } TEST_F(BytesBuiltinsTest, FindWithWideBoundsReturnsIndex) { HandleScope scope(thread_); const byte haystack_bytes[] = {102, 55, 100, 74, 91, 118}; const byte needle_bytes[] = {100, 74}; Bytes haystack(&scope, runtime_->newBytesWithAll(haystack_bytes)); Bytes needle(&scope, runtime_->newBytesWithAll(needle_bytes)); word start = -1000; word end = 123; word result = bytesFind(haystack, haystack.length(), needle, needle.length(), start, end); EXPECT_EQ(result, 2); } TEST_F(BytesBuiltinsTest, FindWithNegativeBoundsReturnsIndex) { HandleScope scope(thread_); const byte haystack_bytes[] = {102, 55, 100, 74, 91, 118}; const byte needle_bytes[] = {100, 74}; Bytes haystack(&scope, runtime_->newBytesWithAll(haystack_bytes)); Bytes needle(&scope, runtime_->newBytesWithAll(needle_bytes)); word start = -5; word end = -2; word result = bytesFind(haystack, haystack.length(), needle, needle.length(), start, end); EXPECT_EQ(result, 2); } TEST_F(BytesBuiltinsTest, FindWithEmptyReturnsAdjustedStart) { HandleScope scope(thread_); const byte haystack_bytes[] = {102, 55, 100, 74, 91, 118}; Bytes haystack(&scope, runtime_->newBytesWithAll(haystack_bytes)); Bytes needle(&scope, Bytes::empty()); word start = -3; word end = -1; word result = bytesFind(haystack, haystack.length(), needle, needle.length(), start, end); EXPECT_EQ(result, 3); } TEST_F(BytesBuiltinsTest, FindWithEndLessThanStartReturnsNegativeOne) { HandleScope scope(thread_); const byte haystack_bytes[] = {102, 55, 100, 74, 91, 118}; Bytes haystack(&scope, runtime_->newBytesWithAll(haystack_bytes)); Bytes needle(&scope, Bytes::empty()); word start = 3; word end = 2; word result = bytesFind(haystack, haystack.length(), needle, needle.length(), start, end); EXPECT_EQ(result, -1); } TEST_F(BytesBuiltinsTest, FindWithSingleCharReturnsFirstIndexInRange) { HandleScope scope(thread_); const byte haystack_bytes[] = {100, 55, 100, 74, 100, 118}; Bytes haystack(&scope, runtime_->newBytesWithAll(haystack_bytes)); Bytes needle(&scope, runtime_->newBytes(1, 100)); word start = 1; word end = haystack.length(); word result = bytesFind(haystack, haystack.length(), needle, needle.length(), start, end); EXPECT_EQ(result, 2); } TEST_F(BytesBuiltinsTest, RFindWithSameBytesReturnsZero) { HandleScope scope(thread_); const byte haystack_bytes[] = {102, 55, 100, 74, 91, 118}; Bytes haystack(&scope, runtime_->newBytesWithAll(haystack_bytes)); word start = 0; word end = haystack.length(); word result = bytesRFind(haystack, haystack.length(), haystack, haystack.length(), start, end); EXPECT_EQ(result, 0); } TEST_F(BytesBuiltinsTest, RFindWithWideBoundsReturnsIndex) { HandleScope scope(thread_); const byte haystack_bytes[] = {102, 55, 100, 74, 91, 118}; const byte needle_bytes[] = {100, 74}; Bytes haystack(&scope, runtime_->newBytesWithAll(haystack_bytes)); Bytes needle(&scope, runtime_->newBytesWithAll(needle_bytes)); word start = -1000; word end = 123; word result = bytesRFind(haystack, haystack.length(), needle, needle.length(), start, end); EXPECT_EQ(result, 2); } TEST_F(BytesBuiltinsTest, RFindWithNegativeBoundsReturnsIndex) { HandleScope scope(thread_); const byte haystack_bytes[] = {102, 55, 100, 74, 91, 118}; const byte needle_bytes[] = {100, 74}; Bytes haystack(&scope, runtime_->newBytesWithAll(haystack_bytes)); Bytes needle(&scope, runtime_->newBytesWithAll(needle_bytes)); word start = -5; word end = -2; word result = bytesRFind(haystack, haystack.length(), needle, needle.length(), start, end); EXPECT_EQ(result, 2); } TEST_F(BytesBuiltinsTest, RFindWithEmptyReturnsAdjustedEnd) { HandleScope scope(thread_); const byte haystack_bytes[] = {102, 55, 100, 74, 91, 118}; Bytes haystack(&scope, runtime_->newBytesWithAll(haystack_bytes)); Bytes needle(&scope, Bytes::empty()); word start = -3; word end = -1; word result = bytesRFind(haystack, haystack.length(), needle, needle.length(), start, end); EXPECT_EQ(result, 5); } TEST_F(BytesBuiltinsTest, RFindWithEndLessThanStartReturnsNegativeOne) { HandleScope scope(thread_); const byte haystack_bytes[] = {102, 55, 100, 74, 91, 118}; Bytes haystack(&scope, runtime_->newBytesWithAll(haystack_bytes)); Bytes needle(&scope, Bytes::empty()); word start = 3; word end = 2; word result = bytesRFind(haystack, haystack.length(), needle, needle.length(), start, end); EXPECT_EQ(result, -1); } TEST_F(BytesBuiltinsTest, RFindWithSingleCharReturnsLastIndexInRange) { HandleScope scope(thread_); const byte haystack_bytes[] = {100, 55, 100, 74, 100, 118}; Bytes haystack(&scope, runtime_->newBytesWithAll(haystack_bytes)); Bytes needle(&scope, runtime_->newBytes(1, 100)); word start = 0; word end = 4; word result = bytesRFind(haystack, haystack.length(), needle, needle.length(), start, end); EXPECT_EQ(result, 2); } TEST_F(BytesBuiltinsTest, DunderAddWithTooFewArgsRaisesTypeError) { EXPECT_TRUE(raisedWithStr( runFromCStr(runtime_, "bytes.__add__(b'')"), LayoutId::kTypeError, "'bytes.__add__' takes min 2 positional arguments but 1 given")); } TEST_F(BytesBuiltinsTest, DunderAddWithTooManyArgsRaisesTypeError) { EXPECT_TRUE(raisedWithStr( runFromCStr(runtime_, "bytes.__add__(b'', b'', b'')"), LayoutId::kTypeError, "'bytes.__add__' takes max 2 positional arguments but 3 given")); } TEST_F(BytesBuiltinsTest, DunderAddWithNonBytesSelfRaisesTypeError) { HandleScope scope(thread_); Object self(&scope, SmallInt::fromWord(0)); Object other(&scope, runtime_->newBytes(1, '1')); Object sum(&scope, runBuiltin(METH(bytes, __add__), self, other)); EXPECT_TRUE(raised(*sum, LayoutId::kTypeError)); } TEST_F(BytesBuiltinsTest, DunderAddWithNonBytesOtherRaisesTypeError) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(1, '1')); Object other(&scope, SmallInt::fromWord(2)); Object sum(&scope, runBuiltin(METH(bytes, __add__), self, other)); EXPECT_TRUE(raised(*sum, LayoutId::kTypeError)); } TEST_F(BytesBuiltinsTest, DunderAddWithBytesLikeOtherReturnsBytes) { Thread* thread = Thread::current(); HandleScope scope(thread); Object self(&scope, runtime_->newBytes(1, '1')); Bytearray other(&scope, runtime_->newBytearray()); const byte buf[] = {'2', '3'}; runtime_->bytearrayExtend(thread, other, buf); Object sum(&scope, runBuiltin(METH(bytes, __add__), self, other)); EXPECT_TRUE(isBytesEqualsCStr(sum, "123")); } TEST_F(BytesBuiltinsTest, DunderAddWithBytesSubclassReturnsBytes) { ASSERT_FALSE(runFromCStr(runtime_, R"( class Foo(bytes): pass self = Foo(b'abc') other = Foo(b'123') )") .isError()); HandleScope scope(thread_); Object self(&scope, mainModuleAt(runtime_, "self")); Object other(&scope, mainModuleAt(runtime_, "other")); Object sum(&scope, runBuiltin(METH(bytes, __add__), self, other)); EXPECT_TRUE(isBytesEqualsCStr(sum, "abc123")); } TEST_F(BytesBuiltinsTest, DunderAddWithTwoBytesReturnsConcatenatedBytes) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(1, '1')); Object other(&scope, runtime_->newBytes(2, '2')); Object sum(&scope, runBuiltin(METH(bytes, __add__), self, other)); EXPECT_TRUE(isBytesEqualsCStr(sum, "122")); } TEST_F(BytesBuiltinsTest, DunderEqWithTooFewArgsRaisesTypeError) { EXPECT_TRUE(raisedWithStr( runFromCStr(runtime_, "bytes.__eq__(b'')"), LayoutId::kTypeError, "'bytes.__eq__' takes min 2 positional arguments but 1 given")); } TEST_F(BytesBuiltinsTest, DunderEqWithTooManyArgsRaisesTypeError) { EXPECT_TRUE(raisedWithStr( runFromCStr(runtime_, "bytes.__eq__(b'', b'', b'')"), LayoutId::kTypeError, "'bytes.__eq__' takes max 2 positional arguments but 3 given")); } TEST_F(BytesBuiltinsTest, DunderEqWithNonBytesSelfRaisesTypeError) { HandleScope scope(thread_); Object self(&scope, SmallInt::fromWord(0)); Object other(&scope, runtime_->newBytes(1, 'a')); Object eq(&scope, runBuiltin(METH(bytes, __eq__), self, other)); EXPECT_TRUE(raised(*eq, LayoutId::kTypeError)); } TEST_F(BytesBuiltinsTest, DunderEqWithNonBytesOtherReturnsNotImplemented) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(1, 'a')); Object other(&scope, SmallInt::fromWord(0)); Object eq(&scope, runBuiltin(METH(bytes, __eq__), self, other)); EXPECT_TRUE(eq.isNotImplementedType()); } TEST_F(BytesBuiltinsTest, DunderEqWithBytesSubclassComparesBytes) { ASSERT_FALSE(runFromCStr(runtime_, R"( class Foo(bytes): pass self = Foo(b'123') other = Foo(b'123') )") .isError()); HandleScope scope(thread_); Object self(&scope, mainModuleAt(runtime_, "self")); Object other(&scope, mainModuleAt(runtime_, "other")); Object eq(&scope, runBuiltin(METH(bytes, __eq__), self, other)); EXPECT_EQ(eq, Bool::trueObj()); } TEST_F(BytesBuiltinsTest, DunderEqWithEqualBytesReturnsTrue) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(5, 'a')); Object other(&scope, runtime_->newBytes(5, 'a')); Object eq(&scope, runBuiltin(METH(bytes, __eq__), self, other)); ASSERT_TRUE(eq.isBool()); EXPECT_TRUE(Bool::cast(*eq).value()); } TEST_F(BytesBuiltinsTest, DunderEqWithDifferentLengthsReturnsFalse) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(1, 'a')); Object other(&scope, runtime_->newBytes(4, 'a')); Object eq(&scope, runBuiltin(METH(bytes, __eq__), self, other)); ASSERT_TRUE(eq.isBool()); EXPECT_FALSE(Bool::cast(*eq).value()); } TEST_F(BytesBuiltinsTest, DunderEqWithDifferentContentsReturnsFalse) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(3, 'a')); Object other(&scope, runtime_->newBytes(3, 'b')); Object eq(&scope, runBuiltin(METH(bytes, __eq__), self, other)); ASSERT_TRUE(eq.isBool()); EXPECT_FALSE(Bool::cast(*eq).value()); } TEST_F(BytesBuiltinsTest, DunderGeWithTooFewArgsRaisesTypeError) { EXPECT_TRUE(raisedWithStr( runFromCStr(runtime_, "bytes.__ge__(b'')"), LayoutId::kTypeError, "'bytes.__ge__' takes min 2 positional arguments but 1 given")); } TEST_F(BytesBuiltinsTest, DunderGeWithTooManyArgsRaisesTypeError) { EXPECT_TRUE(raisedWithStr( runFromCStr(runtime_, "bytes.__ge__(b'', b'', b'')"), LayoutId::kTypeError, "'bytes.__ge__' takes max 2 positional arguments but 3 given")); } TEST_F(BytesBuiltinsTest, DunderGeWithNonBytesSelfRaisesTypeError) { HandleScope scope(thread_); Object self(&scope, SmallInt::fromWord(0)); Object other(&scope, runtime_->newBytes(1, 'a')); Object ge(&scope, runBuiltin(METH(bytes, __ge__), self, other)); EXPECT_TRUE(raised(*ge, LayoutId::kTypeError)); } TEST_F(BytesBuiltinsTest, DunderGeWithNonBytesOtherReturnsNotImplemented) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(1, 'a')); Object other(&scope, SmallInt::fromWord(0)); Object ge(&scope, runBuiltin(METH(bytes, __ge__), self, other)); ASSERT_TRUE(ge.isNotImplementedType()); } TEST_F(BytesBuiltinsTest, DunderGeWithBytesSubclassComparesBytes) { ASSERT_FALSE(runFromCStr(runtime_, R"( class Foo(bytes): pass self = Foo(b'123') other = Foo(b'123') )") .isError()); HandleScope scope(thread_); Object self(&scope, mainModuleAt(runtime_, "self")); Object other(&scope, mainModuleAt(runtime_, "other")); Object ge(&scope, runBuiltin(METH(bytes, __ge__), self, other)); EXPECT_EQ(ge, Bool::trueObj()); } TEST_F(BytesBuiltinsTest, DunderGeWithEqualBytesReturnsTrue) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(5, 'a')); Object other(&scope, runtime_->newBytes(5, 'a')); Object ge(&scope, runBuiltin(METH(bytes, __ge__), self, other)); ASSERT_TRUE(ge.isBool()); EXPECT_TRUE(Bool::cast(*ge).value()); } TEST_F(BytesBuiltinsTest, DunderGeWithShorterOtherReturnsTrue) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(3, 'a')); Object other(&scope, runtime_->newBytes(2, 'a')); Object ge(&scope, runBuiltin(METH(bytes, __ge__), self, other)); ASSERT_TRUE(ge.isBool()); EXPECT_TRUE(Bool::cast(*ge).value()); } TEST_F(BytesBuiltinsTest, DunderGeWithLongerOtherReturnsFalse) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(3, 'a')); Object other(&scope, runtime_->newBytes(4, 'a')); Object ge(&scope, runBuiltin(METH(bytes, __ge__), self, other)); ASSERT_TRUE(ge.isBool()); EXPECT_FALSE(Bool::cast(*ge).value()); } TEST_F(BytesBuiltinsTest, DunderGeWithLexicographicallyEarlierOtherReturnsTrue) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(3, 'b')); Object other(&scope, runtime_->newBytes(3, 'a')); Object ge(&scope, runBuiltin(METH(bytes, __ge__), self, other)); ASSERT_TRUE(ge.isBool()); EXPECT_TRUE(Bool::cast(*ge).value()); } TEST_F(BytesBuiltinsTest, DunderGeWithLexicographicallyLaterOtherReturnsFalse) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(3, 'a')); Object other(&scope, runtime_->newBytes(3, 'b')); Object ge(&scope, runBuiltin(METH(bytes, __ge__), self, other)); ASSERT_TRUE(ge.isBool()); EXPECT_FALSE(Bool::cast(*ge).value()); } TEST_F(BytesBuiltinsTest, DunderGetitemWithTooFewArgsRaisesTypeError) { EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "bytes.__getitem__(b'')"), LayoutId::kTypeError, "'bytes.__getitem__' takes min 2 positional " "arguments but 1 given")); } TEST_F(BytesBuiltinsTest, DunderGetitemWithTooManyArgsRaisesTypeError) { EXPECT_TRUE( raisedWithStr(runFromCStr(runtime_, "bytes.__getitem__(b'', b'', b'')"), LayoutId::kTypeError, "'bytes.__getitem__' takes max 2 positional " "arguments but 3 given")); } TEST_F(BytesBuiltinsTest, DunderGetitemWithLargeIntRaisesIndexError) { EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "b''[2**64]"), LayoutId::kIndexError, "cannot fit 'int' into an index-sized integer")); } TEST_F(BytesBuiltinsTest, DunderGetitemWithIntGreaterOrEqualLenRaisesIndexError) { EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "b'abc'[3]"), LayoutId::kIndexError, "index out of range")); } TEST_F(BytesBuiltinsTest, DunderGetitemWithNegativeIntGreaterThanLenRaisesIndexError) { EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "b'abc'[-4]"), LayoutId::kIndexError, "index out of range")); } TEST_F(BytesBuiltinsTest, DunderGetitemWithNegativeIntIndexesFromEnd) { HandleScope scope(thread_); ASSERT_FALSE(runFromCStr(runtime_, "result = b'hello'[-5]").isError()); Object result(&scope, mainModuleAt(runtime_, "result")); EXPECT_TRUE(isIntEqualsWord(*result, 'h')); } TEST_F(BytesBuiltinsTest, DunderGetitemIndexesFromBeginning) { HandleScope scope(thread_); ASSERT_FALSE(runFromCStr(runtime_, "result = b'hello'[0]").isError()); Object result(&scope, mainModuleAt(runtime_, "result")); EXPECT_TRUE(isIntEqualsWord(*result, 'h')); } TEST_F(BytesBuiltinsTest, DunderGetitemWithSliceReturnsBytes) { HandleScope scope(thread_); ASSERT_FALSE(runFromCStr(runtime_, "result = b'hello world'[:3]").isError()); Object result(&scope, mainModuleAt(runtime_, "result")); EXPECT_TRUE(isBytesEqualsCStr(result, "hel")); } TEST_F(BytesBuiltinsTest, DunderGetitemWithSliceStepReturnsBytes) { HandleScope scope(thread_); ASSERT_FALSE( runFromCStr(runtime_, "result = b'hello world'[1:6:2]").isError()); Object result(&scope, mainModuleAt(runtime_, "result")); EXPECT_TRUE(isBytesEqualsCStr(result, "el ")); } TEST_F(BytesBuiltinsTest, DunderGetitemWithNonIndexOtherRaisesTypeError) { EXPECT_TRUE( raisedWithStr(runFromCStr(runtime_, "b''[1.5]"), LayoutId::kTypeError, "byte indices must be integers or slice, not float")); } TEST_F(BytesBuiltinsTest, DunderGtWithTooFewArgsRaisesTypeError) { EXPECT_TRUE(raisedWithStr( runFromCStr(runtime_, "bytes.__gt__(b'')"), LayoutId::kTypeError, "'bytes.__gt__' takes min 2 positional arguments but 1 given")); } TEST_F(BytesBuiltinsTest, DunderGtWithTooManyArgsRaisesTypeError) { EXPECT_TRUE(raisedWithStr( runFromCStr(runtime_, "bytes.__gt__(b'', b'', b'')"), LayoutId::kTypeError, "'bytes.__gt__' takes max 2 positional arguments but 3 given")); } TEST_F(BytesBuiltinsTest, DunderGtWithNonBytesSelfRaisesTypeError) { HandleScope scope(thread_); Object self(&scope, SmallInt::fromWord(0)); Object other(&scope, runtime_->newBytes(1, 'a')); Object gt(&scope, runBuiltin(METH(bytes, __gt__), self, other)); EXPECT_TRUE(raised(*gt, LayoutId::kTypeError)); } TEST_F(BytesBuiltinsTest, DunderGtWithNonBytesOtherReturnsNotImplemented) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(1, 'a')); Object other(&scope, SmallInt::fromWord(0)); Object gt(&scope, runBuiltin(METH(bytes, __gt__), self, other)); ASSERT_TRUE(gt.isNotImplementedType()); } TEST_F(BytesBuiltinsTest, DunderGtWithBytesSubclassComparesBytes) { ASSERT_FALSE(runFromCStr(runtime_, R"( class Foo(bytes): pass self = Foo(b'123') other = Foo(b'123') )") .isError()); HandleScope scope(thread_); Object self(&scope, mainModuleAt(runtime_, "self")); Object other(&scope, mainModuleAt(runtime_, "other")); Object gt(&scope, runBuiltin(METH(bytes, __gt__), self, other)); EXPECT_EQ(gt, Bool::falseObj()); } TEST_F(BytesBuiltinsTest, DunderGtWithEqualBytesReturnsFalse) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(5, 'a')); Object other(&scope, runtime_->newBytes(5, 'a')); Object gt(&scope, runBuiltin(METH(bytes, __gt__), self, other)); ASSERT_TRUE(gt.isBool()); EXPECT_FALSE(Bool::cast(*gt).value()); } TEST_F(BytesBuiltinsTest, DunderGtWithShorterOtherReturnsTrue) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(3, 'a')); Object other(&scope, runtime_->newBytes(2, 'a')); Object gt(&scope, runBuiltin(METH(bytes, __gt__), self, other)); ASSERT_TRUE(gt.isBool()); EXPECT_TRUE(Bool::cast(*gt).value()); } TEST_F(BytesBuiltinsTest, DunderGtWithLongerOtherReturnsFalse) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(3, 'a')); Object other(&scope, runtime_->newBytes(4, 'a')); Object gt(&scope, runBuiltin(METH(bytes, __gt__), self, other)); ASSERT_TRUE(gt.isBool()); EXPECT_FALSE(Bool::cast(*gt).value()); } TEST_F(BytesBuiltinsTest, DunderGtWithLexicographicallyEarlierOtherReturnsTrue) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(3, 'b')); Object other(&scope, runtime_->newBytes(3, 'a')); Object gt(&scope, runBuiltin(METH(bytes, __gt__), self, other)); ASSERT_TRUE(gt.isBool()); EXPECT_TRUE(Bool::cast(*gt).value()); } TEST_F(BytesBuiltinsTest, DunderGtWithLexicographicallyLaterOtherReturnsFalse) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(3, 'a')); Object other(&scope, runtime_->newBytes(3, 'b')); Object gt(&scope, runBuiltin(METH(bytes, __gt__), self, other)); ASSERT_TRUE(gt.isBool()); EXPECT_FALSE(Bool::cast(*gt).value()); } TEST_F(BytesBuiltinsTest, DunderHashReturnsSmallInt) { Thread* thread = Thread::current(); HandleScope scope(thread); const byte bytes[] = {'h', 'e', 'l', 'l', 'o', '\0'}; Bytes bytes_obj(&scope, runtime_->newBytesWithAll(bytes)); EXPECT_TRUE(runBuiltin(METH(bytes, __hash__), bytes_obj).isSmallInt()); } TEST_F(BytesBuiltinsTest, DunderHashSmallBytesReturnsSmallInt) { Thread* thread = Thread::current(); HandleScope scope(thread); const byte bytes[] = {'h'}; Bytes bytes_obj(&scope, runtime_->newBytesWithAll(bytes)); EXPECT_TRUE(runBuiltin(METH(bytes, __hash__), bytes_obj).isSmallInt()); } TEST_F(BytesBuiltinsTest, DunderHashWithEquivalentBytesReturnsSameHash) { Thread* thread = Thread::current(); HandleScope scope(thread); const byte bytes[] = {'h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd', '\0'}; Bytes bytes_obj1(&scope, runtime_->newBytesWithAll(bytes)); Bytes bytes_obj2(&scope, runtime_->newBytesWithAll(bytes)); EXPECT_NE(*bytes_obj1, *bytes_obj2); Object result1(&scope, runBuiltin(METH(bytes, __hash__), bytes_obj1)); Object result2(&scope, runBuiltin(METH(bytes, __hash__), bytes_obj2)); EXPECT_TRUE(result1.isSmallInt()); EXPECT_TRUE(result2.isSmallInt()); EXPECT_EQ(*result1, *result2); } TEST_F(BytesBuiltinsTest, DunderHashWithBytesSubclassReturnsSameHash) { HandleScope scope(thread_); ASSERT_FALSE(runFromCStr(runtime_, R"( class C(bytes): pass i0 = C(b"abc") i1 = b"abc" )") .isError()); Object i0(&scope, mainModuleAt(runtime_, "i0")); Object i1(&scope, mainModuleAt(runtime_, "i1")); Object result0(&scope, runBuiltin(METH(bytes, __hash__), i0)); Object result1(&scope, runBuiltin(METH(bytes, __hash__), i1)); EXPECT_TRUE(result0.isSmallInt()); EXPECT_TRUE(result1.isSmallInt()); EXPECT_EQ(result0, result1); } TEST_F(BytesBuiltinsTest, DunderIterReturnsBytesIterator) { HandleScope scope(thread_); Object self(&scope, Bytes::empty()); Object result(&scope, runBuiltin(METH(bytes, __iter__), self)); EXPECT_TRUE(result.isBytesIterator()); } TEST_F(BytesBuiltinsTest, DunderLeWithTooFewArgsRaisesTypeError) { EXPECT_TRUE(raisedWithStr( runFromCStr(runtime_, "bytes.__le__(b'')"), LayoutId::kTypeError, "'bytes.__le__' takes min 2 positional arguments but 1 given")); } TEST_F(BytesBuiltinsTest, DunderLeWithTooManyArgsRaisesTypeError) { EXPECT_TRUE(raisedWithStr( runFromCStr(runtime_, "bytes.__le__(b'', b'', b'')"), LayoutId::kTypeError, "'bytes.__le__' takes max 2 positional arguments but 3 given")); } TEST_F(BytesBuiltinsTest, DunderLeWithNonBytesSelfRaisesTypeError) { HandleScope scope(thread_); Object self(&scope, SmallInt::fromWord(0)); Object other(&scope, runtime_->newBytes(1, 'a')); Object le(&scope, runBuiltin(METH(bytes, __le__), self, other)); EXPECT_TRUE(raised(*le, LayoutId::kTypeError)); } TEST_F(BytesBuiltinsTest, DunderLeWithNonBytesOtherReturnsNotImplemented) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(1, 'a')); Object other(&scope, SmallInt::fromWord(0)); Object le(&scope, runBuiltin(METH(bytes, __le__), self, other)); ASSERT_TRUE(le.isNotImplementedType()); } TEST_F(BytesBuiltinsTest, DunderLeWithBytesSubclassComparesBytes) { ASSERT_FALSE(runFromCStr(runtime_, R"( class Foo(bytes): pass self = Foo(b'123') other = Foo(b'123') )") .isError()); HandleScope scope(thread_); Object self(&scope, mainModuleAt(runtime_, "self")); Object other(&scope, mainModuleAt(runtime_, "other")); Object le(&scope, runBuiltin(METH(bytes, __le__), self, other)); EXPECT_EQ(le, Bool::trueObj()); } TEST_F(BytesBuiltinsTest, DunderLeWithEqualBytesReturnsTrue) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(5, 'a')); Object other(&scope, runtime_->newBytes(5, 'a')); Object le(&scope, runBuiltin(METH(bytes, __le__), self, other)); ASSERT_TRUE(le.isBool()); EXPECT_TRUE(Bool::cast(*le).value()); } TEST_F(BytesBuiltinsTest, DunderLeWithShorterOtherReturnsFalse) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(3, 'a')); Object other(&scope, runtime_->newBytes(2, 'a')); Object le(&scope, runBuiltin(METH(bytes, __le__), self, other)); ASSERT_TRUE(le.isBool()); EXPECT_FALSE(Bool::cast(*le).value()); } TEST_F(BytesBuiltinsTest, DunderLeWithLongerOtherReturnsTrue) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(3, 'a')); Object other(&scope, runtime_->newBytes(4, 'a')); Object le(&scope, runBuiltin(METH(bytes, __le__), self, other)); ASSERT_TRUE(le.isBool()); EXPECT_TRUE(Bool::cast(*le).value()); } TEST_F(BytesBuiltinsTest, DunderLeWithLexicographicallyEarlierOtherReturnsFalse) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(3, 'b')); Object other(&scope, runtime_->newBytes(3, 'a')); Object le(&scope, runBuiltin(METH(bytes, __le__), self, other)); ASSERT_TRUE(le.isBool()); EXPECT_FALSE(Bool::cast(*le).value()); } TEST_F(BytesBuiltinsTest, DunderLeWithLexicographicallyLaterOtherReturnsTrue) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(3, 'a')); Object other(&scope, runtime_->newBytes(3, 'b')); Object le(&scope, runBuiltin(METH(bytes, __le__), self, other)); ASSERT_TRUE(le.isBool()); EXPECT_TRUE(Bool::cast(*le).value()); } TEST_F(BytesBuiltinsTest, DunderLenWithTooFewArgsRaisesTypeError) { EXPECT_TRUE(raisedWithStr( runFromCStr(runtime_, "bytes.__len__()"), LayoutId::kTypeError, "'bytes.__len__' takes min 1 positional arguments but 0 given")); } TEST_F(BytesBuiltinsTest, DunderLenWithTooManyArgsRaisesTypeError) { EXPECT_TRUE(raisedWithStr( runFromCStr(runtime_, "bytes.__len__(b'', b'')"), LayoutId::kTypeError, "'bytes.__len__' takes max 1 positional arguments but 2 given")); } TEST_F(BytesBuiltinsTest, DunderLenWithNonBytesSelfRaisesTypeError) { HandleScope scope(thread_); Object self(&scope, SmallInt::fromWord(0)); Object len(&scope, runBuiltin(METH(bytes, __len__), self)); EXPECT_TRUE(raised(*len, LayoutId::kTypeError)); } TEST_F(BytesBuiltinsTest, DunderLenWithEmptyBytesReturnsZero) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytesWithAll(View<byte>(nullptr, 0))); Object len(&scope, runBuiltin(METH(bytes, __len__), self)); EXPECT_EQ(len, SmallInt::fromWord(0)); } TEST_F(BytesBuiltinsTest, DunderLenWithNonEmptyBytesReturnsLength) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(4, 'a')); Object len(&scope, runBuiltin(METH(bytes, __len__), self)); EXPECT_EQ(len, SmallInt::fromWord(4)); } TEST_F(BytesBuiltinsTest, DunderLenWithBytesSubclassReturnsLength) { ASSERT_FALSE(runFromCStr(runtime_, R"( class Foo(bytes): pass self = Foo(b"1234567890") )") .isError()); HandleScope scope(thread_); Object self(&scope, mainModuleAt(runtime_, "self")); Object len(&scope, runBuiltin(METH(bytes, __len__), self)); EXPECT_EQ(len, SmallInt::fromWord(10)); } TEST_F(BytesBuiltinsTest, DunderLtWithTooFewArgsRaisesTypeError) { EXPECT_TRUE(raisedWithStr( runFromCStr(runtime_, "bytes.__lt__(b'')"), LayoutId::kTypeError, "'bytes.__lt__' takes min 2 positional arguments but 1 given")); } TEST_F(BytesBuiltinsTest, DunderLtWithTooManyArgsRaisesTypeError) { EXPECT_TRUE(raisedWithStr( runFromCStr(runtime_, "bytes.__lt__(b'', b'', b'')"), LayoutId::kTypeError, "'bytes.__lt__' takes max 2 positional arguments but 3 given")); } TEST_F(BytesBuiltinsTest, DunderLtWithNonBytesSelfRaisesTypeError) { HandleScope scope(thread_); Object self(&scope, SmallInt::fromWord(0)); Object other(&scope, runtime_->newBytes(1, 'a')); Object lt(&scope, runBuiltin(METH(bytes, __lt__), self, other)); EXPECT_TRUE(raised(*lt, LayoutId::kTypeError)); } TEST_F(BytesBuiltinsTest, DunderLtWithNonBytesOtherReturnsNotImplemented) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(1, 'a')); Object other(&scope, SmallInt::fromWord(0)); Object lt(&scope, runBuiltin(METH(bytes, __lt__), self, other)); ASSERT_TRUE(lt.isNotImplementedType()); } TEST_F(BytesBuiltinsTest, DunderLtWithBytesSubclassComparesBytes) { ASSERT_FALSE(runFromCStr(runtime_, R"( class Foo(bytes): pass self = Foo(b'123') other = Foo(b'123') )") .isError()); HandleScope scope(thread_); Object self(&scope, mainModuleAt(runtime_, "self")); Object other(&scope, mainModuleAt(runtime_, "other")); Object lt(&scope, runBuiltin(METH(bytes, __lt__), self, other)); EXPECT_EQ(lt, Bool::falseObj()); } TEST_F(BytesBuiltinsTest, DunderLtWithEqualBytesReturnsFalse) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(5, 'a')); Object other(&scope, runtime_->newBytes(5, 'a')); Object lt(&scope, runBuiltin(METH(bytes, __lt__), self, other)); ASSERT_TRUE(lt.isBool()); EXPECT_FALSE(Bool::cast(*lt).value()); } TEST_F(BytesBuiltinsTest, DunderLtWithShorterOtherReturnsFalse) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(3, 'a')); Object other(&scope, runtime_->newBytes(2, 'a')); Object lt(&scope, runBuiltin(METH(bytes, __lt__), self, other)); ASSERT_TRUE(lt.isBool()); EXPECT_FALSE(Bool::cast(*lt).value()); } TEST_F(BytesBuiltinsTest, DunderLtWithLongerOtherReturnsTrue) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(3, 'a')); Object other(&scope, runtime_->newBytes(4, 'a')); Object lt(&scope, runBuiltin(METH(bytes, __lt__), self, other)); ASSERT_TRUE(lt.isBool()); EXPECT_TRUE(Bool::cast(*lt).value()); } TEST_F(BytesBuiltinsTest, DunderLtWithLexicographicallyEarlierOtherReturnsFalse) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(3, 'b')); Object other(&scope, runtime_->newBytes(3, 'a')); Object lt(&scope, runBuiltin(METH(bytes, __lt__), self, other)); ASSERT_TRUE(lt.isBool()); EXPECT_FALSE(Bool::cast(*lt).value()); } TEST_F(BytesBuiltinsTest, DunderLtWithLexicographicallyLaterOtherReturnsTrue) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(3, 'a')); Object other(&scope, runtime_->newBytes(3, 'b')); Object lt(&scope, runBuiltin(METH(bytes, __lt__), self, other)); ASSERT_TRUE(lt.isBool()); EXPECT_TRUE(Bool::cast(*lt).value()); } TEST_F(BytesBuiltinsTest, DunderMulWithNonIntRaisesTypeError) { HandleScope scope(thread_); Object self(&scope, Bytes::empty()); Object count(&scope, runtime_->newList()); EXPECT_TRUE(raisedWithStr( runBuiltin(METH(bytes, __mul__), self, count), LayoutId::kTypeError, "'list' object cannot be interpreted as an integer")); } TEST_F(BytesBuiltinsTest, DunderMulWithIntSubclassReturnsRepeatedBytes) { HandleScope scope(thread_); const byte view[] = {'a', 'b', 'c'}; Object self(&scope, runtime_->newBytesWithAll(view)); ASSERT_FALSE(runFromCStr(runtime_, R"( class C(int): pass count = C(4) )") .isError()); Object count(&scope, mainModuleAt(runtime_, "count")); Object result(&scope, runBuiltin(METH(bytes, __mul__), self, count)); EXPECT_TRUE(isBytesEqualsCStr(result, "abcabcabcabc")); } TEST_F(BytesBuiltinsTest, DunderMulWithDunderIndexReturnsRepeatedBytes) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(1, 'a')); ASSERT_FALSE(runFromCStr(runtime_, R"( class C: def __index__(self): return 2 count = C() )") .isError()); Object count(&scope, mainModuleAt(runtime_, "count")); Object result(&scope, runBuiltin(METH(bytes, __mul__), self, count)); EXPECT_TRUE(isBytesEqualsCStr(result, "aa")); } TEST_F(BytesBuiltinsTest, DunderMulWithBadDunderIndexRaisesTypeError) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(1, 'a')); ASSERT_FALSE(runFromCStr(runtime_, R"( class C: def __index__(self): return "foo" count = C() )") .isError()); Object count(&scope, mainModuleAt(runtime_, "count")); EXPECT_TRUE(raisedWithStr(runBuiltin(METH(bytes, __mul__), self, count), LayoutId::kTypeError, "__index__ returned non-int (type str)")); } TEST_F(BytesBuiltinsTest, DunderMulPropagatesDunderIndexError) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(1, 'a')); ASSERT_FALSE(runFromCStr(runtime_, R"( class C: def __index__(self): raise ArithmeticError("called __index__") count = C() )") .isError()); Object count(&scope, mainModuleAt(runtime_, "count")); EXPECT_TRUE(raisedWithStr(runBuiltin(METH(bytes, __mul__), self, count), LayoutId::kArithmeticError, "called __index__")); } TEST_F(BytesBuiltinsTest, DunderMulWithLargeIntRaisesOverflowError) { HandleScope scope(thread_); Object self(&scope, Bytes::empty()); const uword digits[] = {1, 1}; Object count(&scope, runtime_->newLargeIntWithDigits(digits)); EXPECT_TRUE(raisedWithStr(runBuiltin(METH(bytes, __mul__), self, count), LayoutId::kOverflowError, "cannot fit 'int' into an index-sized integer")); } TEST_F(BytesBuiltinsTest, DunderMulWithOverflowRaisesOverflowError) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(3, 'a')); Object count(&scope, SmallInt::fromWord(SmallInt::kMaxValue / 2)); EXPECT_TRUE(raisedWithStr(runBuiltin(METH(bytes, __mul__), self, count), LayoutId::kOverflowError, "repeated bytes are too long")); } TEST_F(BytesBuiltinsTest, DunderMulWithEmptyBytesReturnsEmptyBytes) { HandleScope scope(thread_); Object self(&scope, Bytes::empty()); Object count(&scope, runtime_->newInt(10)); Object result(&scope, runBuiltin(METH(bytes, __mul__), self, count)); EXPECT_TRUE(isBytesEqualsCStr(result, "")); } TEST_F(BytesBuiltinsTest, DunderMulWithNegativeReturnsEmptyBytes) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(4, 'a')); Object count(&scope, SmallInt::fromWord(-5)); Object result(&scope, runBuiltin(METH(bytes, __mul__), self, count)); EXPECT_TRUE(isBytesEqualsCStr(result, "")); } TEST_F(BytesBuiltinsTest, DunderMulWithZeroReturnsEmptyBytes) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(4, 'a')); Object count(&scope, SmallInt::fromWord(0)); Object result(&scope, runBuiltin(METH(bytes, __mul__), self, count)); EXPECT_TRUE(isBytesEqualsCStr(result, "")); } TEST_F(BytesBuiltinsTest, DunderMulWithOneReturnsSameBytes) { HandleScope scope(thread_); const byte bytes_array[] = {'a', 'b'}; Object self(&scope, runtime_->newBytesWithAll(bytes_array)); Object count(&scope, SmallInt::fromWord(1)); Object result(&scope, runBuiltin(METH(bytes, __mul__), self, count)); EXPECT_TRUE(isBytesEqualsCStr(result, "ab")); } TEST_F(BytesBuiltinsTest, DunderMulReturnsRepeatedBytes) { HandleScope scope(thread_); const byte bytes_array[] = {'a', 'b'}; Object self(&scope, runtime_->newBytesWithAll(bytes_array)); Object count(&scope, SmallInt::fromWord(3)); Object result(&scope, runBuiltin(METH(bytes, __mul__), self, count)); EXPECT_TRUE(isBytesEqualsCStr(result, "ababab")); } TEST_F(BytesBuiltinsTest, DunderMulWithBytesSubclassReturnsRepeatedBytes) { ASSERT_FALSE(runFromCStr(runtime_, R"( class Foo(bytes): pass self = Foo(b"ab") )") .isError()); HandleScope scope(thread_); Object self(&scope, mainModuleAt(runtime_, "self")); Object count(&scope, SmallInt::fromWord(3)); Object result(&scope, runBuiltin(METH(bytes, __mul__), self, count)); EXPECT_TRUE(isBytesEqualsCStr(result, "ababab")); } TEST_F(BytesBuiltinsTest, DunderNeWithTooFewArgsRaisesTypeError) { EXPECT_TRUE(raisedWithStr( runFromCStr(runtime_, "bytes.__ne__(b'')"), LayoutId::kTypeError, "'bytes.__ne__' takes min 2 positional arguments but 1 given")); } TEST_F(BytesBuiltinsTest, DunderNeWithTooManyArgsRaisesTypeError) { EXPECT_TRUE(raisedWithStr( runFromCStr(runtime_, "bytes.__ne__(b'', b'', b'')"), LayoutId::kTypeError, "'bytes.__ne__' takes max 2 positional arguments but 3 given")); } TEST_F(BytesBuiltinsTest, DunderNeWithNonBytesSelfRaisesTypeError) { HandleScope scope(thread_); Object self(&scope, SmallInt::fromWord(0)); Object other(&scope, runtime_->newBytes(1, 'a')); Object ne(&scope, runBuiltin(METH(bytes, __ne__), self, other)); EXPECT_TRUE(raised(*ne, LayoutId::kTypeError)); } TEST_F(BytesBuiltinsTest, DunderNeWithNonBytesOtherReturnsNotImplemented) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(1, 'a')); Object other(&scope, SmallInt::fromWord(0)); Object ne(&scope, runBuiltin(METH(bytes, __ne__), self, other)); EXPECT_TRUE(ne.isNotImplementedType()); } TEST_F(BytesBuiltinsTest, DunderNeWithBytesSubclassComparesBytes) { ASSERT_FALSE(runFromCStr(runtime_, R"( class Foo(bytes): pass self = Foo(b'123') other = Foo(b'123') )") .isError()); HandleScope scope(thread_); Object self(&scope, mainModuleAt(runtime_, "self")); Object other(&scope, mainModuleAt(runtime_, "other")); Object ne(&scope, runBuiltin(METH(bytes, __ne__), self, other)); EXPECT_EQ(ne, Bool::falseObj()); } TEST_F(BytesBuiltinsTest, DunderNeWithEqualBytesReturnsFalse) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(5, 'a')); Object other(&scope, runtime_->newBytes(5, 'a')); Object ne(&scope, runBuiltin(METH(bytes, __ne__), self, other)); ASSERT_TRUE(ne.isBool()); EXPECT_FALSE(Bool::cast(*ne).value()); } TEST_F(BytesBuiltinsTest, DunderNeWithDifferentLengthsReturnsTrue) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(1, 'a')); Object other(&scope, runtime_->newBytes(4, 'a')); Object ne(&scope, runBuiltin(METH(bytes, __ne__), self, other)); ASSERT_TRUE(ne.isBool()); EXPECT_TRUE(Bool::cast(*ne).value()); } TEST_F(BytesBuiltinsTest, DunderNeWithDifferentContentsReturnsTrue) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(3, 'a')); Object other(&scope, runtime_->newBytes(3, 'b')); Object ne(&scope, runBuiltin(METH(bytes, __ne__), self, other)); ASSERT_TRUE(ne.isBool()); EXPECT_TRUE(Bool::cast(*ne).value()); } TEST_F(BytesBuiltinsTest, DunderNewWithoutSourceWithEncodingRaisesTypeError) { EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "bytes(encoding='ascii')"), LayoutId::kTypeError, "encoding or errors without sequence argument")); } TEST_F(BytesBuiltinsTest, DunderNewWithoutSourceWithErrorsRaisesTypeError) { EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "bytes(errors='strict')"), LayoutId::kTypeError, "encoding or errors without sequence argument")); } TEST_F(BytesBuiltinsTest, DunderNewWithoutArgsReturnsEmptyBytes) { HandleScope scope(thread_); ASSERT_FALSE(runFromCStr(runtime_, "obj = bytes()").isError()); Object obj(&scope, mainModuleAt(runtime_, "obj")); EXPECT_TRUE(isBytesEqualsCStr(obj, "")); } TEST_F(BytesBuiltinsTest, DunderNewWithNonStringSourceWithEncodingRaisesTypeError) { EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "bytes(1, 'ascii')"), LayoutId::kTypeError, "encoding without a string argument")); } TEST_F(BytesBuiltinsTest, DunderNewWithoutEncodingWithErrorsAndStringSourceRaisesTypeError) { EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "bytes('', errors='strict')"), LayoutId::kTypeError, "string argument without an encoding")); } TEST_F(BytesBuiltinsTest, DunderNewWithoutEncodingWithErrorsAndNonStringSourceRaisesTypeError) { EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "bytes(1, errors='strict')"), LayoutId::kTypeError, "errors without a string argument")); } TEST_F(BytesBuiltinsTest, DunderNewWithMistypedDunderBytesRaisesTypeError) { EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"( class Foo: def __bytes__(self): return 1 bytes(Foo()) )"), LayoutId::kTypeError, "__bytes__ returned non-bytes (type int)")); } TEST_F(BytesBuiltinsTest, DunderNewPropagatesDunderBytesError) { EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"( class Foo: def __bytes__(self): raise SystemError("foo") bytes(Foo()) )"), LayoutId::kSystemError, "foo")); } TEST_F(BytesBuiltinsTest, DunderNewWithDunderBytesReturnsBytes) { HandleScope scope(thread_); ASSERT_FALSE(runFromCStr(runtime_, R"( class Foo: def __bytes__(self): return b'foo' result = bytes(Foo()) )") .isError()); Object result(&scope, mainModuleAt(runtime_, "result")); EXPECT_TRUE(isBytesEqualsCStr(result, "foo")); } TEST_F(BytesBuiltinsTest, DunderNewWithNegativeIntegerSourceRaisesValueError) { EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "result = bytes(-1)"), LayoutId::kValueError, "negative count")); } TEST_F(BytesBuiltinsTest, DunderNewWithLargeIntegerSourceRaisesOverflowError) { EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "result = bytes(2**63)"), LayoutId::kOverflowError, "cannot fit 'int' into an index-sized integer")); } TEST_F(BytesBuiltinsTest, DunderNewWithIntegerSourceReturnsZeroFilledBytes) { HandleScope scope(thread_); ASSERT_FALSE(runFromCStr(runtime_, "result = bytes(10)").isError()); Object result(&scope, mainModuleAt(runtime_, "result")); const byte bytes[10] = {}; EXPECT_TRUE(isBytesEqualsBytes(result, bytes)); } TEST_F(BytesBuiltinsTest, DunderNewWithBytesReturnsSameBytes) { HandleScope scope(thread_); ASSERT_FALSE(runFromCStr(runtime_, "result = bytes(b'123')").isError()); Object result(&scope, mainModuleAt(runtime_, "result")); const byte bytes[] = {'1', '2', '3'}; EXPECT_TRUE(isBytesEqualsBytes(result, bytes)); } TEST_F(BytesBuiltinsTest, DunderNewWithBytearrayReturnsBytesCopy) { HandleScope scope(thread_); ASSERT_FALSE( runFromCStr(runtime_, "result = bytes(bytearray(b'123'))").isError()); Object result(&scope, mainModuleAt(runtime_, "result")); const byte bytes[] = {'1', '2', '3'}; EXPECT_TRUE(isBytesEqualsBytes(result, bytes)); } TEST_F(BytesBuiltinsTest, DunderNewWithListReturnsNewBytes) { HandleScope scope(thread_); ASSERT_FALSE(runFromCStr(runtime_, "result = bytes([6, 28])").isError()); Object result(&scope, mainModuleAt(runtime_, "result")); const byte bytes[] = {6, 28}; EXPECT_TRUE(isBytesEqualsBytes(result, bytes)); } TEST_F(BytesBuiltinsTest, DunderNewWithTupleReturnsNewBytes) { HandleScope scope(thread_); ASSERT_FALSE(runFromCStr(runtime_, "result = bytes((6, 28))").isError()); Object result(&scope, mainModuleAt(runtime_, "result")); const byte bytes[] = {6, 28}; EXPECT_TRUE(isBytesEqualsBytes(result, bytes)); } TEST_F(BytesBuiltinsTest, DunderNewWithNegativeRaisesValueError) { EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "result = bytes([-1])"), LayoutId::kValueError, "bytes must be in range(0, 256)")); } TEST_F(BytesBuiltinsTest, DunderNewWithGreaterThanByteRaisesValueError) { EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "result = bytes([256])"), LayoutId::kValueError, "bytes must be in range(0, 256)")); } TEST_F(BytesBuiltinsTest, DunderNewWithIterableReturnsNewBytes) { HandleScope scope(thread_); ASSERT_FALSE(runFromCStr(runtime_, R"( class Foo: def __iter__(self): return [1, 2, 3].__iter__() result = bytes(Foo()) )") .isError()); Object result(&scope, mainModuleAt(runtime_, "result")); const byte expected[] = {1, 2, 3}; EXPECT_TRUE(isBytesEqualsBytes(result, expected)); } TEST_F(BytesBuiltinsTest, DunderReprWithEmptyBytesReturnsEmptyRepr) { HandleScope scope(thread_); Object self(&scope, Bytes::empty()); Object repr(&scope, runBuiltin(METH(bytes, __repr__), self)); EXPECT_TRUE(isStrEqualsCStr(*repr, "b''")); } TEST_F(BytesBuiltinsTest, DunderReprWithSimpleBytesReturnsRepr) { HandleScope scope(thread_); Object self(&scope, runtime_->newBytes(10, '*')); Object repr(&scope, runBuiltin(METH(bytes, __repr__), self)); EXPECT_TRUE(isStrEqualsCStr(*repr, "b'**********'")); } TEST_F(BytesBuiltinsTest, DunderReprWithBytesSubclassReturnsStr) { ASSERT_FALSE(runFromCStr(runtime_, R"( class Foo(bytes): pass self = Foo(b"*****") )") .isError()); HandleScope scope(thread_); Object self(&scope, mainModuleAt(runtime_, "self")); Object repr(&scope, runBuiltin(METH(bytes, __repr__), self)); EXPECT_TRUE(isStrEqualsCStr(*repr, "b'*****'")); } TEST_F(BytesBuiltinsTest, DunderReprWithDoubleQuoteUsesSingleQuoteDelimiters) { HandleScope scope(thread_); const byte view[] = {'_', '"', '_'}; Object self(&scope, runtime_->newBytesWithAll(view)); Object repr(&scope, runBuiltin(METH(bytes, __repr__), self)); EXPECT_TRUE(isStrEqualsCStr(*repr, R"(b'_"_')")); } TEST_F(BytesBuiltinsTest, DunderReprWithSingleQuoteUsesDoubleQuoteDelimiters) { HandleScope scope(thread_); const byte view[] = {'_', '\'', '_'}; Object self(&scope, runtime_->newBytesWithAll(view)); Object repr(&scope, runBuiltin(METH(bytes, __repr__), self)); EXPECT_TRUE(isStrEqualsCStr(*repr, R"(b"_'_")")); } TEST_F(BytesBuiltinsTest, DunderReprWithBothQuotesUsesSingleQuoteDelimiters) { HandleScope scope(thread_); const byte view[] = {'_', '"', '_', '\'', '_'}; Object self(&scope, runtime_->newBytesWithAll(view)); Object repr(&scope, runBuiltin(METH(bytes, __repr__), self)); EXPECT_TRUE(isStrEqualsCStr(*repr, R"(b'_"_\'_')")); } TEST_F(BytesBuiltinsTest, DunderReprWithSpeciaBytesUsesEscapeSequences) { HandleScope scope(thread_); const byte view[] = {'\\', '\t', '\n', '\r'}; Object self(&scope, runtime_->newBytesWithAll(view)); Object repr(&scope, runBuiltin(METH(bytes, __repr__), self)); EXPECT_TRUE(isStrEqualsCStr(*repr, R"(b'\\\t\n\r')")); } TEST_F(BytesBuiltinsTest, DunderReprWithSmallAndLargeBytesUsesHex) { HandleScope scope(thread_); const byte view[] = {0, 0x1f, 0x80, 0xff}; Object self(&scope, runtime_->newBytesWithAll(view)); Object repr(&scope, runBuiltin(METH(bytes, __repr__), self)); EXPECT_TRUE(isStrEqualsCStr(*repr, R"(b'\x00\x1f\x80\xff')")); } TEST_F(BytesBuiltinsTest, DunderRmulCallsDunderMul) { HandleScope scope(thread_); ASSERT_FALSE(runFromCStr(runtime_, "result = 3 * b'1'").isError()); Object result(&scope, mainModuleAt(runtime_, "result")); EXPECT_TRUE(isBytesEqualsCStr(result, "111")); } TEST_F(BytesBuiltinsTest, DecodeWithASCIIReturnsString) { HandleScope scope(thread_); ASSERT_FALSE( runFromCStr(runtime_, "result = b'hello'.decode('ascii')").isError()); Object result(&scope, mainModuleAt(runtime_, "result")); EXPECT_TRUE(isStrEqualsCStr(*result, "hello")); } TEST_F(BytesBuiltinsTest, JoinWithBytesReturnsBytes) { HandleScope scope(thread_); Bytes sep(&scope, newBytesFromCStr(thread_, ",")); Bytes obj1(&scope, newBytesFromCStr(thread_, "hello")); Bytes obj2(&scope, newBytesFromCStr(thread_, "world")); Tuple src(&scope, runtime_->newTupleWith2(obj1, obj2)); Bytes result(&scope, bytesJoin(thread_, sep, sep.length(), src, src.length())); EXPECT_TRUE(isBytesEqualsCStr(result, "hello,world")); } TEST_F(BytesBuiltinsTest, JoinWithBytearrayReturnsBytes) { HandleScope scope(thread_); Bytes sep(&scope, newBytesFromCStr(thread_, ",")); Bytearray obj1(&scope, newBytearrayFromCStr(thread_, "hello")); Bytearray obj2(&scope, newBytearrayFromCStr(thread_, "world")); Tuple src(&scope, runtime_->newTupleWith2(obj1, obj2)); Bytes result(&scope, bytesJoin(thread_, sep, sep.length(), src, src.length())); EXPECT_TRUE(isBytesEqualsCStr(result, "hello,world")); } TEST_F(BytesBuiltinsTest, JoinWithMemoryviewReturnsBytes) { HandleScope scope(thread_); Bytes sep(&scope, newBytesFromCStr(thread_, ",")); Bytes src1(&scope, newBytesFromCStr(thread_, "hello")); MemoryView obj1(&scope, runtime_->newMemoryView(thread_, src1, src1, src1.length(), ReadOnly::ReadOnly)); Bytes src2(&scope, newBytesFromCStr(thread_, "world")); MemoryView obj2(&scope, runtime_->newMemoryView(thread_, src2, src2, src2.length(), ReadOnly::ReadOnly)); Tuple src(&scope, runtime_->newTupleWith2(obj1, obj2)); Bytes result(&scope, bytesJoin(thread_, sep, sep.length(), src, src.length())); EXPECT_TRUE(isBytesEqualsCStr(result, "hello,world")); } TEST_F(BytesBuiltinsTest, HexWithEmptyBytesReturnsEmptyString) { HandleScope scope(thread_); Bytes self(&scope, Bytes::empty()); Object result(&scope, runBuiltin(METH(bytes, hex), self)); EXPECT_TRUE(isStrEqualsCStr(*result, "")); } TEST_F(BytesBuiltinsTest, HexWithNonEmptyBytesReturnsString) { HandleScope scope(thread_); const byte bytes_array[] = {0x12, 0x34, 0xfe, 0x5b}; Bytes self(&scope, runtime_->newBytesWithAll(bytes_array)); Object result(&scope, runBuiltin(METH(bytes, hex), self)); EXPECT_TRUE(isStrEqualsCStr(*result, "1234fe5b")); } TEST_F(BytesBuiltinsTest, HexWithBytesSubclassReturnsStr) { ASSERT_FALSE(runFromCStr(runtime_, R"( class Foo(bytes): pass self = Foo(b"*\x01a\x92") )") .isError()); HandleScope scope(thread_); Object self(&scope, mainModuleAt(runtime_, "self")); Object repr(&scope, runBuiltin(METH(bytes, hex), self)); EXPECT_TRUE(isStrEqualsCStr(*repr, "2a016192")); } TEST_F(BytesBuiltinsTest, IsalnumWithEmptyBytesReturnsFalse) { HandleScope scope(thread_); Bytes self(&scope, Bytes::empty()); Object result(&scope, runBuiltin(METH(bytes, isalnum), self)); EXPECT_EQ(result, Bool::falseObj()); } TEST_F(BytesBuiltinsTest, IsalnumWithAllAlnumReturnsTrue) { HandleScope scope(thread_); const byte view[] = {'A', '1', 'a', '2', 'B'}; Bytes self(&scope, runtime_->newBytesWithAll(view)); Object result(&scope, runBuiltin(METH(bytes, isalnum), self)); EXPECT_EQ(result, Bool::trueObj()); } TEST_F(BytesBuiltinsTest, IsalnumWithOneNonAlnumReturnsFalse) { HandleScope scope(thread_); const byte view[] = {'A', '1', ' ', '2', 'b'}; Bytes self(&scope, runtime_->newBytesWithAll(view)); Object result(&scope, runBuiltin(METH(bytes, isalnum), self)); EXPECT_EQ(result, Bool::falseObj()); } TEST_F(BytesBuiltinsTest, IsalphaWithEmptyBytesReturnsFalse) { HandleScope scope(thread_); Bytes self(&scope, Bytes::empty()); Object result(&scope, runBuiltin(METH(bytes, isalpha), self)); EXPECT_EQ(result, Bool::falseObj()); } TEST_F(BytesBuiltinsTest, IsalphaWithAllAlphaReturnsTrue) { HandleScope scope(thread_); const byte view[] = {'A', 'a', 'Z', 'z'}; Bytes self(&scope, runtime_->newBytesWithAll(view)); Object result(&scope, runBuiltin(METH(bytes, isalpha), self)); EXPECT_EQ(result, Bool::trueObj()); } TEST_F(BytesBuiltinsTest, IsAlphaWithOneDigitReturnsFalse) { HandleScope scope(thread_); const byte view[] = {'A', 'a', '1'}; Bytes self(&scope, runtime_->newBytesWithAll(view)); Object result(&scope, runBuiltin(METH(bytes, isalpha), self)); EXPECT_EQ(result, Bool::falseObj()); } TEST_F(BytesBuiltinsTest, IsdigitWithEmptyBytesReturnsFalse) { HandleScope scope(thread_); Bytes self(&scope, Bytes::empty()); Object result(&scope, runBuiltin(METH(bytes, isdigit), self)); EXPECT_EQ(result, Bool::falseObj()); } TEST_F(BytesBuiltinsTest, IsdigitAllDigitsReturnsTrue) { HandleScope scope(thread_); const byte view[] = {'2', '0', '2', '0'}; Bytes self(&scope, runtime_->newBytesWithAll(view)); Object result(&scope, runBuiltin(METH(bytes, isdigit), self)); EXPECT_EQ(result, Bool::trueObj()); } TEST_F(BytesBuiltinsTest, IsdigitOneAlphaReturnsFalse) { HandleScope scope(thread_); const byte view[] = {'4', '0', '1', 'k'}; Bytes self(&scope, runtime_->newBytesWithAll(view)); Object result(&scope, runBuiltin(METH(bytes, isdigit), self)); EXPECT_EQ(result, Bool::falseObj()); } TEST_F(BytesBuiltinsTest, IsLowerWithEmptyBytesReturnsFalse) { HandleScope scope(thread_); Bytes self(&scope, Bytes::empty()); Object result(&scope, runBuiltin(METH(bytes, islower), self)); EXPECT_EQ(result, Bool::falseObj()); } TEST_F(BytesBuiltinsTest, IslowerWithAllLowercaseReturnsTrue) { HandleScope scope(thread_); const byte view[] = {'a', 'b', 'c'}; Bytes self(&scope, runtime_->newBytesWithAll(view)); Object result(&scope, runBuiltin(METH(bytes, islower), self)); EXPECT_EQ(result, Bool::trueObj()); } TEST_F(BytesBuiltinsTest, IslowerWithOneUppercaseReturnsFalse) { HandleScope scope(thread_); const byte view[] = {'F', 'o', 'o'}; Bytes self(&scope, runtime_->newBytesWithAll(view)); Object result(&scope, runBuiltin(METH(bytes, islower), self)); EXPECT_EQ(result, Bool::falseObj()); } TEST_F(BytesBuiltinsTest, IslowerWithOneDigitReturnsFalse) { HandleScope scope(thread_); const byte view[] = {'f', '8'}; Bytes self(&scope, runtime_->newBytesWithAll(view)); Object result(&scope, runBuiltin(METH(bytes, islower), self)); EXPECT_EQ(result, Bool::falseObj()); } TEST_F(BytesBuiltinsTest, IsspaceWithEmptyBytesReturnsFalse) { HandleScope scope(thread_); Bytes self(&scope, Bytes::empty()); Object result(&scope, runBuiltin(METH(bytes, isspace), self)); EXPECT_EQ(result, Bool::falseObj()); } TEST_F(BytesBuiltinsTest, IsspaceWithAllWhitespaceReturnsTrue) { HandleScope scope(thread_); const byte view[] = {' ', '\n', '\t', '\r'}; Bytes self(&scope, runtime_->newBytesWithAll(view)); Object result(&scope, runBuiltin(METH(bytes, isspace), self)); EXPECT_EQ(result, Bool::trueObj()); } TEST_F(BytesBuiltinsTest, IsspaceWithNonSpaceReturnsFalse) { HandleScope scope(thread_); const byte view[] = {'\t', '.', ' ', '\n'}; Bytes self(&scope, runtime_->newBytesWithAll(view)); Object result(&scope, runBuiltin(METH(bytes, isspace), self)); EXPECT_EQ(result, Bool::falseObj()); } TEST_F(BytesBuiltinsTest, IstitleWithEmptyBytesReturnsFalse) { HandleScope scope(thread_); Bytes self(&scope, Bytes::empty()); Object result(&scope, runBuiltin(METH(bytes, istitle), self)); EXPECT_EQ(result, Bool::falseObj()); } TEST_F(BytesBuiltinsTest, IstitleWithTitlecaseWordsReturnsTrue) { HandleScope scope(thread_); const byte view[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'}; Bytes self(&scope, runtime_->newBytesWithAll(view)); Object result(&scope, runBuiltin(METH(bytes, istitle), self)); EXPECT_EQ(result, Bool::trueObj()); } TEST_F(BytesBuiltinsTest, IstitleWithLowercaseWordStartReturnsFalse) { HandleScope scope(thread_); const byte view[] = {'F', 'o', 'o', '1', 'b', 'a', 'r'}; Bytes self(&scope, runtime_->newBytesWithAll(view)); Object result(&scope, runBuiltin(METH(bytes, istitle), self)); EXPECT_EQ(result, Bool::falseObj()); } TEST_F(BytesBuiltinsTest, IstitleWithUppercaseMiddleReturnsFalse) { HandleScope scope(thread_); const byte view[] = {'F', 'o', 'O'}; Bytes self(&scope, runtime_->newBytesWithAll(view)); Object result(&scope, runBuiltin(METH(bytes, istitle), self)); EXPECT_EQ(result, Bool::falseObj()); } TEST_F(BytesBuiltinsTest, IsupperWithEmptyBytesReturnsFalse) { HandleScope scope(thread_); Bytes self(&scope, Bytes::empty()); Object result(&scope, runBuiltin(METH(bytes, isupper), self)); EXPECT_EQ(result, Bool::falseObj()); } TEST_F(BytesBuiltinsTest, IsupperWithAllUppercaseReturnsTrue) { HandleScope scope(thread_); const byte view[] = {'F', 'O', 'O', 'B', 'A', 'R'}; Bytes self(&scope, runtime_->newBytesWithAll(view)); Object result(&scope, runBuiltin(METH(bytes, isupper), self)); EXPECT_EQ(result, Bool::trueObj()); } TEST_F(BytesBuiltinsTest, IsupperWithOneLowercaseReturnsFalse) { HandleScope scope(thread_); const byte view[] = {'F', 'O', 'O', 'B', 'a', 'R'}; Bytes self(&scope, runtime_->newBytesWithAll(view)); Object result(&scope, runBuiltin(METH(bytes, isupper), self)); EXPECT_EQ(result, Bool::falseObj()); } TEST_F(BytesBuiltinsTest, IsupperWithOneDigitReturnsFalse) { HandleScope scope(thread_); const byte view[] = {'F', '8'}; Bytes self(&scope, runtime_->newBytesWithAll(view)); Object result(&scope, runBuiltin(METH(bytes, isupper), self)); EXPECT_EQ(result, Bool::falseObj()); } TEST_F(BytesBuiltinsTest, JoinWithNonIterableRaisesTypeError) { EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "b''.join(0)"), LayoutId::kTypeError, "'int' object is not iterable")); } TEST_F(BytesBuiltinsTest, JoinWithMistypedIterableRaisesTypeError) { EXPECT_TRUE(raisedWithStr( runFromCStr(runtime_, "b' '.join([1])"), LayoutId::kTypeError, "sequence item 0: expected a bytes-like object, 'int' found")); } TEST_F(BytesBuiltinsTest, JoinWithIterableReturnsBytes) { ASSERT_FALSE(runFromCStr(runtime_, R"( class Foo: def __iter__(self): return [b'ab', b'c', b'def'].__iter__() result = b' '.join(Foo()) )") .isError()); Thread* thread = Thread::current(); HandleScope scope(thread); Object result(&scope, mainModuleAt(runtime_, "result")); EXPECT_TRUE(isBytesEqualsCStr(result, "ab c def")); } TEST_F(BytesBuiltinsTest, MaketransWithNonBytesLikeFromRaisesTypeError) { EXPECT_TRUE(raisedWithStr( runFromCStr(runtime_, "bytes.maketrans([1,2], b'ab')"), LayoutId::kTypeError, "a bytes-like object is required, not 'list'")); } TEST_F(BytesBuiltinsTest, MaketransWithNonBytesLikeToRaisesTypeError) { EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "bytes.maketrans(b'1', 2)"), LayoutId::kTypeError, "a bytes-like object is required, not 'int'")); } TEST_F(BytesBuiltinsTest, MaketransWithDifferentLengthsRaisesValueError) { EXPECT_TRUE(raisedWithStr( runFromCStr(runtime_, "bytes.maketrans(b'12', bytearray())"), LayoutId::kValueError, "maketrans arguments must have same length")); } TEST_F(BytesBuiltinsTest, MaketransWithEmptyReturnsDefaultBytes) { HandleScope scope(thread_); ASSERT_FALSE( runFromCStr(runtime_, "result = bytes.maketrans(bytearray(), b'')") .isError()); Object result(&scope, mainModuleAt(runtime_, "result")); byte expected[256]; for (word i = 0; i < 256; i++) { expected[i] = i; } EXPECT_TRUE(isBytesEqualsBytes(result, expected)); } TEST_F(BytesBuiltinsTest, MaketransWithNonEmptyReturnsBytes) { HandleScope scope(thread_); ASSERT_FALSE( runFromCStr(runtime_, "result = bytes.maketrans(bytearray(b'abc'), b'123')") .isError()); Object result(&scope, mainModuleAt(runtime_, "result")); ASSERT_TRUE(result.isBytes()); LargeBytes actual(&scope, *result); EXPECT_EQ(actual.byteAt('a'), '1'); EXPECT_EQ(actual.byteAt('b'), '2'); EXPECT_EQ(actual.byteAt('c'), '3'); } TEST_F(BytesBuiltinsTest, TranslateWithNonBytesLikeTableRaisesTypeError) { EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "b''.translate(42)"), LayoutId::kTypeError, "a bytes-like object is required, not 'int'")); } TEST_F(BytesBuiltinsTest, TranslateWithNonBytesLikeDeleteRaisesTypeError) { EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "b''.translate(None, 42)"), LayoutId::kTypeError, "a bytes-like object is required, not 'int'")); } TEST_F(BytesBuiltinsTest, TranslateWithShortTableRaisesValueError) { EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "b''.translate(b'')"), LayoutId::kValueError, "translation table must be 256 characters long")); } TEST_F(BytesBuiltinsTest, TranslateWithEmptyBytesReturnsEmptyBytes) { HandleScope scope(thread_); Object self(&scope, Bytes::empty()); Object table(&scope, NoneType::object()); Object del(&scope, runtime_->newBytearray()); Object result(&scope, runBuiltin(METH(bytes, translate), self, table, del)); EXPECT_EQ(result, Bytes::empty()); } TEST_F(BytesBuiltinsTest, TranslateWithNonEmptySecondArgDeletesBytes) { HandleScope scope(thread_); const byte alabama[] = {'A', 'l', 'a', 'b', 'a', 'm', 'a'}; const byte abc[] = {'a', 'b', 'c'}; Object self(&scope, runtime_->newBytesWithAll(alabama)); Object table(&scope, NoneType::object()); Object del(&scope, runtime_->newBytesWithAll(abc)); Object result(&scope, runBuiltin(METH(bytes, translate), self, table, del)); EXPECT_TRUE(isBytesEqualsCStr(result, "Alm")); } TEST_F(BytesBuiltinsTest, TranslateWithTableTranslatesBytes) { HandleScope scope(thread_); ASSERT_FALSE( runFromCStr(runtime_, "table = bytes.maketrans(b'Aa', b'12')").isError()); const byte alabama[] = {'A', 'l', 'a', 'b', 'a', 'm', 'a'}; Object self(&scope, runtime_->newBytesWithAll(alabama)); Object table(&scope, mainModuleAt(runtime_, "table")); Object del(&scope, Bytes::empty()); Object result(&scope, runBuiltin(METH(bytes, translate), self, table, del)); EXPECT_TRUE(isBytesEqualsCStr(result, "1l2b2m2")); } TEST_F(BytesBuiltinsTest, TranslateWithTableAndDeleteTranslatesAndDeletesBytes) { HandleScope scope(thread_); ASSERT_FALSE( runFromCStr(runtime_, "table = bytes.maketrans(b'Aa', b'12')").isError()); const byte alabama[] = {'A', 'l', 'a', 'b', 'a', 'm', 'a'}; const byte abc[] = {'a', 'b', 'c'}; Object self(&scope, runtime_->newBytesWithAll(alabama)); Object table(&scope, mainModuleAt(runtime_, "table")); Object del(&scope, runtime_->newBytesWithAll(abc)); Object result(&scope, runBuiltin(METH(bytes, translate), self, table, del)); EXPECT_TRUE(isBytesEqualsCStr(result, "1lm")); } TEST_F(BytesBuiltinsTest, TranslateDeletesAllBytes) { HandleScope scope(thread_); const byte alabama[] = {'b', 'a', 'c', 'a', 'a', 'c', 'a'}; const byte abc[] = {'a', 'b', 'c'}; Object self(&scope, runtime_->newBytesWithAll(alabama)); Object table(&scope, NoneType::object()); Object del(&scope, runtime_->newBytesWithAll(abc)); Object result(&scope, runBuiltin(METH(bytes, translate), self, table, del)); EXPECT_EQ(result, Bytes::empty()); } TEST_F(BytesIteratorBuiltinsTest, DunderLengthHintReturnsRemainingCount) { HandleScope scope(thread_); const byte data[] = {100, 0, 37}; Bytes bytes(&scope, SmallBytes::fromBytes(data)); Object iter(&scope, runtime_->newBytesIterator(thread_, bytes)); Object result(&scope, runBuiltin(METH(bytes_iterator, __length_hint__), iter)); EXPECT_TRUE(isIntEqualsWord(*result, 3)); ASSERT_TRUE(!runBuiltin(METH(bytes_iterator, __next__), iter).isError()); result = runBuiltin(METH(bytes_iterator, __length_hint__), iter); EXPECT_TRUE(isIntEqualsWord(*result, 2)); ASSERT_TRUE(!runBuiltin(METH(bytes_iterator, __next__), iter).isError()); result = runBuiltin(METH(bytes_iterator, __length_hint__), iter); EXPECT_TRUE(isIntEqualsWord(*result, 1)); ASSERT_TRUE(!runBuiltin(METH(bytes_iterator, __next__), iter).isError()); result = runBuiltin(METH(bytes_iterator, __length_hint__), iter); EXPECT_TRUE(isIntEqualsWord(*result, 0)); EXPECT_TRUE(raised(runBuiltin(METH(bytes_iterator, __next__), iter), LayoutId::kStopIteration)); } TEST_F(BytesIteratorBuiltinsTest, DunderIterReturnsSelf) { HandleScope scope(thread_); const byte data[] = {100, 0, 37}; Bytes bytes(&scope, SmallBytes::fromBytes(data)); Object iter(&scope, runtime_->newBytesIterator(thread_, bytes)); Object result(&scope, runBuiltin(METH(bytes_iterator, __iter__), iter)); EXPECT_EQ(result, iter); } TEST_F(BytesIteratorBuiltinsTest, DunderNextReturnsNextElement) { HandleScope scope(thread_); const byte data[] = {100, 0, 37}; Bytes bytes(&scope, SmallBytes::fromBytes(data)); Object iter(&scope, runtime_->newBytesIterator(thread_, bytes)); Object result(&scope, runBuiltin(METH(bytes_iterator, __next__), iter)); EXPECT_TRUE(isIntEqualsWord(*result, 100)); result = runBuiltin(METH(bytes_iterator, __next__), iter); EXPECT_TRUE(isIntEqualsWord(*result, 0)); result = runBuiltin(METH(bytes_iterator, __next__), iter); EXPECT_TRUE(isIntEqualsWord(*result, 37)); EXPECT_TRUE(raised(runBuiltin(METH(bytes_iterator, __next__), iter), LayoutId::kStopIteration)); } } // namespace testing } // namespace py