runtime/set-builtins-test.cpp (1,033 lines of code) (raw):
// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
#include "set-builtins.h"
#include "gtest/gtest.h"
#include "builtins.h"
#include "runtime.h"
#include "test-utils.h"
namespace py {
namespace testing {
using FrozenSetBuiltinsTest = RuntimeFixture;
using SetBuiltinsTest = RuntimeFixture;
using SetIteratorBuiltinsTest = RuntimeFixture;
TEST_F(SetBuiltinsTest, SetPopException) {
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
s = {1}
s.pop()
s.pop()
)"),
LayoutId::kKeyError, "pop from an empty set"));
}
TEST_F(SetBuiltinsTest, SetPop) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
s = {1}
a = s.pop()
b = len(s)
)")
.isError());
Object a(&scope, mainModuleAt(runtime_, "a"));
Object b(&scope, mainModuleAt(runtime_, "b"));
EXPECT_TRUE(isIntEqualsWord(*a, 1));
EXPECT_TRUE(isIntEqualsWord(*b, 0));
}
TEST_F(SetBuiltinsTest, InitializeByTypeCall) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
s = set()
)")
.isError());
Object s(&scope, mainModuleAt(runtime_, "s"));
EXPECT_TRUE(s.isSet());
EXPECT_EQ(Set::cast(*s).numItems(), 0);
}
TEST_F(SetBuiltinsTest, SetAdd) {
Thread* thread = Thread::current();
HandleScope scope(thread);
ASSERT_FALSE(runFromCStr(runtime_, R"(
s = set()
s.add(1)
s.add("Hello, World")
)")
.isError());
Set s(&scope, mainModuleAt(runtime_, "s"));
Object one(&scope, runtime_->newInt(1));
Object hello_world(&scope, runtime_->newStrFromCStr("Hello, World"));
EXPECT_EQ(s.numItems(), 2);
EXPECT_TRUE(setIncludes(thread, s, one));
EXPECT_TRUE(setIncludes(thread, s, hello_world));
}
TEST_F(SetBuiltinsTest, DunderIterReturnsSetIterator) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set empty_set(&scope, runtime_->newSet());
Object iter(&scope, runBuiltin(METH(set, __iter__), empty_set));
ASSERT_TRUE(iter.isSetIterator());
}
TEST_F(SetBuiltinsTest, DunderAnd) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set1(&scope, runtime_->newSet());
Set set2(&scope, runtime_->newSet());
Object result(&scope, runBuiltin(METH(set, __and__), set1, set2));
ASSERT_TRUE(result.isSet());
EXPECT_EQ(Set::cast(*result).numItems(), 0);
Object key(&scope, SmallInt::fromWord(1));
setHashAndAdd(thread, set1, key);
key = SmallInt::fromWord(2);
setHashAndAdd(thread, set1, key);
Object result1(&scope, runBuiltin(METH(set, __and__), set1, set2));
ASSERT_TRUE(result1.isSet());
EXPECT_EQ(Set::cast(*result1).numItems(), 0);
key = SmallInt::fromWord(1);
setHashAndAdd(thread, set2, key);
Object result2(&scope, runBuiltin(METH(set, __and__), set1, set2));
ASSERT_TRUE(result2.isSet());
Set set(&scope, *result2);
EXPECT_EQ(set.numItems(), 1);
EXPECT_TRUE(setIncludes(thread, set, key));
}
TEST_F(SetBuiltinsTest, DunderAndWithNonSet) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Object empty_set(&scope, runtime_->newSet());
Object none(&scope, NoneType::object());
Object result(&scope, runBuiltin(METH(set, __and__), empty_set, none));
ASSERT_TRUE(result.isNotImplementedType());
}
TEST_F(SetBuiltinsTest, DunderIand) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set1(&scope, runtime_->newSet());
Set set2(&scope, runtime_->newSet());
Object key(&scope, NoneType::object());
Object result(&scope, runBuiltin(METH(set, __iand__), set1, set2));
ASSERT_TRUE(result.isSet());
EXPECT_EQ(*result, *set1);
EXPECT_EQ(Set::cast(*result).numItems(), 0);
key = SmallInt::fromWord(1);
setHashAndAdd(thread, set1, key);
key = SmallInt::fromWord(2);
setHashAndAdd(thread, set1, key);
Object result1(&scope, runBuiltin(METH(set, __iand__), set1, set2));
ASSERT_TRUE(result1.isSet());
EXPECT_EQ(*result1, *set1);
EXPECT_EQ(Set::cast(*result1).numItems(), 0);
set1 = runtime_->newSet();
key = SmallInt::fromWord(1);
setHashAndAdd(thread, set1, key);
key = SmallInt::fromWord(2);
setHashAndAdd(thread, set1, key);
setHashAndAdd(thread, set2, key);
Object result2(&scope, runBuiltin(METH(set, __iand__), set1, set2));
ASSERT_TRUE(result2.isSet());
EXPECT_EQ(*result2, *set1);
Set set(&scope, *result2);
EXPECT_EQ(set.numItems(), 1);
EXPECT_TRUE(setIncludes(thread, set, key));
}
TEST_F(SetBuiltinsTest, DunderIandWithNonSet) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Object empty_set(&scope, runtime_->newSet());
Object none(&scope, NoneType::object());
Object result(&scope, runBuiltin(METH(set, __iand__), empty_set, none));
ASSERT_TRUE(result.isNotImplementedType());
}
TEST_F(SetBuiltinsTest, SetIntersectionWithOneArgumentReturnsIntersection) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, setFromRange(0, 3));
Set set1(&scope, setFromRange(0, 2));
// set.intersect() with 1 argument
Object result(&scope, runBuiltin(METH(set, intersection), set, set1));
ASSERT_TRUE(result.isSet());
EXPECT_NE(*result, *set);
set = *result;
EXPECT_EQ(set.numItems(), 2);
Object key(&scope, SmallInt::fromWord(0));
key = SmallInt::fromWord(0);
EXPECT_TRUE(setIncludes(thread, set, key));
key = SmallInt::fromWord(1);
EXPECT_TRUE(setIncludes(thread, set, key));
}
TEST_F(SetBuiltinsTest, SetIntersectionWithEmptySetReturnsEmptySet) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, setFromRange(0, 3));
Set set1(&scope, runtime_->newSet());
// set.intersect() with 2 arguments
Object result(&scope, runBuiltin(METH(set, intersection), set, set1));
ASSERT_TRUE(result.isSet());
EXPECT_NE(*result, *set);
EXPECT_EQ(Set::cast(*result).numItems(), 0);
}
TEST_F(SetBuiltinsTest, SetIntersectionWithEmptyIterableReturnsEmptySet) {
HandleScope scope(thread_);
Set set(&scope, setFromRange(0, 3));
List list(&scope, runtime_->newList());
Object result(&scope, runBuiltin(METH(set, intersection), set, list));
ASSERT_TRUE(result.isSet());
EXPECT_EQ(Set::cast(*result).numItems(), 0);
}
TEST_F(SetBuiltinsTest, SetIntersectionWithIterableReturnsIntersection) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, setFromRange(0, 3));
List list(&scope, runtime_->newList());
Object key(&scope, SmallInt::fromWord(4));
runtime_->listAdd(thread, list, key);
key = SmallInt::fromWord(0);
runtime_->listAdd(thread, list, key);
Object result(&scope, runBuiltin(METH(set, intersection), set, list));
ASSERT_TRUE(result.isSet());
EXPECT_EQ(Set::cast(*result).numItems(), 1);
set = *result;
EXPECT_TRUE(setIncludes(thread, set, key));
}
TEST_F(SetBuiltinsTest, SetIntersectionWithFrozenSetReturnsSet) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
FrozenSet frozen_set(&scope, runtime_->emptyFrozenSet());
Object result(&scope, runBuiltin(METH(set, intersection), set, frozen_set));
ASSERT_TRUE(result.isSet());
}
TEST_F(SetBuiltinsTest, FrozenSetIntersectionWithSetReturnsFrozenSet) {
Thread* thread = Thread::current();
HandleScope scope(thread);
FrozenSet frozen_set(&scope, runtime_->emptyFrozenSet());
Set set(&scope, runtime_->newSet());
Object result(&scope, runBuiltin(METH(set, intersection), frozen_set, set));
ASSERT_TRUE(result.isFrozenSet());
}
TEST_F(SetBuiltinsTest, SetAndWithFrozenSetReturnsSet) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
FrozenSet frozen_set(&scope, runtime_->emptyFrozenSet());
Object result(&scope, runBuiltin(METH(set, __and__), set, frozen_set));
ASSERT_TRUE(result.isSet());
}
TEST_F(SetBuiltinsTest, FrozenSetAndWithSetReturnsFrozenSet) {
Thread* thread = Thread::current();
HandleScope scope(thread);
FrozenSet frozen_set(&scope, runtime_->emptyFrozenSet());
Set set(&scope, runtime_->newSet());
Object result(&scope, runBuiltin(METH(frozenset, __and__), frozen_set, set));
ASSERT_TRUE(result.isFrozenSet());
}
TEST_F(SetIteratorBuiltinsTest, CallDunderNext) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
Object value(&scope, SmallInt::fromWord(0));
setHashAndAdd(thread, set, value);
value = SmallInt::fromWord(1);
setHashAndAdd(thread, set, value);
Object iter(&scope, runBuiltin(METH(set, __iter__), set));
ASSERT_TRUE(iter.isSetIterator());
Object item1(&scope, runBuiltin(METH(set_iterator, __next__), iter));
EXPECT_TRUE(isIntEqualsWord(*item1, 0));
Object item2(&scope, runBuiltin(METH(set_iterator, __next__), iter));
EXPECT_TRUE(isIntEqualsWord(*item2, 1));
Object item3(&scope, runBuiltin(METH(set_iterator, __next__), iter));
ASSERT_TRUE(item3.isError());
}
TEST_F(SetIteratorBuiltinsTest, CallDunderNextWithEmptySet) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
Object iter(&scope, runBuiltin(METH(set, __iter__), set));
ASSERT_TRUE(iter.isSetIterator());
Object result(&scope, runBuiltin(METH(set_iterator, __next__), iter));
ASSERT_TRUE(result.isError());
}
TEST_F(SetIteratorBuiltinsTest, DunderIterReturnsSelf) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set empty_set(&scope, runtime_->newSet());
Object iter(&scope, runBuiltin(METH(set, __iter__), empty_set));
ASSERT_TRUE(iter.isSetIterator());
// Now call __iter__ on the iterator object
Object result(&scope, runBuiltin(METH(set_iterator, __iter__), iter));
ASSERT_EQ(*result, *iter);
}
TEST_F(SetIteratorBuiltinsTest, DunderLengthHintOnEmptySetReturnsZero) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set empty_set(&scope, runtime_->newSet());
Object iter(&scope, runBuiltin(METH(set, __iter__), empty_set));
ASSERT_TRUE(iter.isSetIterator());
Object length_hint(&scope,
runBuiltin(METH(set_iterator, __length_hint__), iter));
EXPECT_TRUE(isIntEqualsWord(*length_hint, 0));
}
TEST_F(SetIteratorBuiltinsTest, DunderLengthHintOnConsumedSetReturnsZero) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set one_element_set(&scope, runtime_->newSet());
Object zero(&scope, SmallInt::fromWord(0));
setHashAndAdd(thread, one_element_set, zero);
Object iter(&scope, runBuiltin(METH(set, __iter__), one_element_set));
ASSERT_TRUE(iter.isSetIterator());
Object length_hint1(&scope,
runBuiltin(METH(set_iterator, __length_hint__), iter));
EXPECT_TRUE(isIntEqualsWord(*length_hint1, 1));
// Consume the iterator
Object item1(&scope, runBuiltin(METH(set_iterator, __next__), iter));
EXPECT_TRUE(isIntEqualsWord(*item1, 0));
Object length_hint2(&scope,
runBuiltin(METH(set_iterator, __length_hint__), iter));
EXPECT_TRUE(isIntEqualsWord(*length_hint2, 0));
}
TEST_F(SetBuiltinsTest, IsdisjointWithNonIterableArg) {
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
s = {1}
s.isdisjoint(None)
)"),
LayoutId::kTypeError, "object is not iterable"));
}
TEST_F(SetBuiltinsTest, IsdisjointWithSetArg) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
Set other(&scope, runtime_->newSet());
Object value(&scope, NoneType::object());
// set().isdisjoint(set())
Object result(&scope, runBuiltin(METH(set, isdisjoint), set, other));
ASSERT_TRUE(result.isBool());
EXPECT_EQ(*result, Bool::trueObj());
// set().isdisjoint({None})
setHashAndAdd(thread, other, value);
Object result1(&scope, runBuiltin(METH(set, isdisjoint), set, other));
ASSERT_TRUE(result1.isBool());
EXPECT_EQ(*result1, Bool::trueObj());
// {None}.isdisjoint({None})
setHashAndAdd(thread, set, value);
Object result2(&scope, runBuiltin(METH(set, isdisjoint), set, other));
ASSERT_TRUE(result2.isBool());
EXPECT_EQ(*result2, Bool::falseObj());
// {None}.isdisjoint({1})
other = runtime_->newSet();
value = SmallInt::fromWord(1);
setHashAndAdd(thread, other, value);
Object result3(&scope, runBuiltin(METH(set, isdisjoint), set, other));
ASSERT_TRUE(result3.isBool());
EXPECT_EQ(*result3, Bool::trueObj());
}
TEST_F(SetBuiltinsTest, IsdisjointWithIterableArg) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
List other(&scope, runtime_->newList());
Object value(&scope, NoneType::object());
// set().isdisjoint([])
Object result(&scope, runBuiltin(METH(set, isdisjoint), set, other));
ASSERT_TRUE(result.isBool());
EXPECT_EQ(*result, Bool::trueObj());
// set().isdisjoint([None])
runtime_->listAdd(thread, other, value);
Object result1(&scope, runBuiltin(METH(set, isdisjoint), set, other));
ASSERT_TRUE(result1.isBool());
EXPECT_EQ(*result1, Bool::trueObj());
// {None}.isdisjoint([None])
setHashAndAdd(thread, set, value);
Object result2(&scope, runBuiltin(METH(set, isdisjoint), set, other));
ASSERT_TRUE(result2.isBool());
EXPECT_EQ(*result2, Bool::falseObj());
// {None}.isdisjoint([1])
other = runtime_->newList();
value = SmallInt::fromWord(1);
runtime_->listAdd(thread, other, value);
Object result3(&scope, runBuiltin(METH(set, isdisjoint), set, other));
ASSERT_TRUE(result3.isBool());
EXPECT_EQ(*result3, Bool::trueObj());
}
TEST_F(SetBuiltinsTest, DunderEqWithSetSubclass) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class Bar(set): pass
a = set()
a1 = {1}
b = Bar()
cmp = (a == b)
cmp1 = (a1 == b)
cmp2 = (b == a)
cmp3 = (b == a1)
cmp4 = (b == b)
)")
.isError());
EXPECT_EQ(mainModuleAt(runtime_, "cmp"), Bool::trueObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp1"), Bool::falseObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp2"), Bool::trueObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp3"), Bool::falseObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp4"), Bool::trueObj());
}
TEST_F(SetBuiltinsTest, DunderNeWithSetSubclass) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class Bar(set): pass
a = set()
a1 = {1}
b = Bar()
cmp = (a != b)
cmp1 = (a1 != b)
cmp2 = (b != a)
cmp3 = (b != a1)
cmp4 = (b != b)
)")
.isError());
EXPECT_EQ(mainModuleAt(runtime_, "cmp"), Bool::falseObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp1"), Bool::trueObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp2"), Bool::falseObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp3"), Bool::trueObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp4"), Bool::falseObj());
}
TEST_F(SetBuiltinsTest, DunderGeWithSetSubclass) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class Bar(set): pass
a = set()
a1 = {1}
b = Bar()
cmp = (a >= b)
cmp1 = (a1 >= b)
cmp2 = (b >= a)
cmp3 = (b >= a1)
cmp4 = (b >= b)
)")
.isError());
EXPECT_EQ(mainModuleAt(runtime_, "cmp"), Bool::trueObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp1"), Bool::trueObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp2"), Bool::trueObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp3"), Bool::falseObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp4"), Bool::trueObj());
}
TEST_F(SetBuiltinsTest, DunderGtWithSetSubclass) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class Bar(set): pass
a = set()
a1 = {1}
b = Bar()
cmp = (a > b)
cmp1 = (a1 > b)
cmp2 = (b > a)
cmp3 = (b > a1)
cmp4 = (b > b)
)")
.isError());
EXPECT_EQ(mainModuleAt(runtime_, "cmp"), Bool::falseObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp1"), Bool::trueObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp2"), Bool::falseObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp3"), Bool::falseObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp4"), Bool::falseObj());
}
TEST_F(SetBuiltinsTest, DunderLeWithSetSubclass) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class Bar(set): pass
a = set()
a1 = {1}
b = Bar()
cmp = (a <= b)
cmp1 = (a1 <= b)
cmp2 = (b <= a)
cmp3 = (b <= a1)
cmp4 = (b <= b)
)")
.isError());
EXPECT_EQ(mainModuleAt(runtime_, "cmp"), Bool::trueObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp1"), Bool::falseObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp2"), Bool::trueObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp3"), Bool::trueObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp4"), Bool::trueObj());
}
TEST_F(SetBuiltinsTest, DunderLtWithSetSubclass) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class Bar(set): pass
a = set()
a1 = {1}
b = Bar()
cmp = (a < b)
cmp1 = (a1 < b)
cmp2 = (b < a)
cmp3 = (b < a1)
cmp4 = (b < b)
)")
.isError());
EXPECT_EQ(mainModuleAt(runtime_, "cmp"), Bool::falseObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp1"), Bool::falseObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp2"), Bool::falseObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp3"), Bool::trueObj());
EXPECT_EQ(mainModuleAt(runtime_, "cmp4"), Bool::falseObj());
}
TEST_F(SetBuiltinsTest, DunderEqWithEmptySetsReturnsTrue) {
// (set() == set()) is True
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
Set set1(&scope, runtime_->newSet());
Object result(&scope, runBuiltin(METH(set, __eq__), set, set1));
ASSERT_EQ(*result, Bool::trueObj());
}
TEST_F(SetBuiltinsTest, DunderEqWithSameSetReturnsTrue) {
// s = {0, 1, 2}; (s == s) is True
HandleScope scope(thread_);
Set set(&scope, setFromRange(0, 3));
Object result(&scope, runBuiltin(METH(set, __eq__), set, set));
ASSERT_EQ(*result, Bool::trueObj());
}
TEST_F(SetBuiltinsTest, DunderEqWithEqualSetsReturnsTrue) {
// ({0, 1, 2) == {0, 1, 2}) is True
HandleScope scope(thread_);
Set set(&scope, setFromRange(0, 3));
Set set1(&scope, setFromRange(0, 3));
Object result(&scope, runBuiltin(METH(set, __eq__), set, set1));
ASSERT_EQ(*result, Bool::trueObj());
}
TEST_F(SetBuiltinsTest, DunderEqWithUnequalSetsReturnsFalse) {
// ({0, 1, 2} == {1, 2, 3}) is False
HandleScope scope(thread_);
Set set(&scope, setFromRange(0, 3));
Set set1(&scope, setFromRange(1, 4));
Object result(&scope, runBuiltin(METH(set, __eq__), set, set1));
ASSERT_EQ(*result, Bool::falseObj());
}
TEST_F(SetBuiltinsTest, DunderNeWithEmptySetsReturnsFalse) {
// (set() != set()) is True
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
Set set1(&scope, runtime_->newSet());
Object result(&scope, runBuiltin(METH(set, __ne__), set, set1));
ASSERT_EQ(*result, Bool::falseObj());
}
TEST_F(SetBuiltinsTest, DunderNeWithSameSetReturnsFalse) {
// s = {0, 1, 2}; (s != s) is False
HandleScope scope(thread_);
Set set(&scope, setFromRange(0, 3));
Object result(&scope, runBuiltin(METH(set, __ne__), set, set));
ASSERT_EQ(*result, Bool::falseObj());
}
TEST_F(SetBuiltinsTest, DunderNeWithEqualSetsReturnsFalse) {
// ({0, 1, 2} != {0, 1, 2}) is False
HandleScope scope(thread_);
Set set(&scope, setFromRange(0, 3));
Set set1(&scope, setFromRange(0, 3));
Object result(&scope, runBuiltin(METH(set, __ne__), set, set1));
ASSERT_EQ(*result, Bool::falseObj());
}
TEST_F(SetBuiltinsTest, DunderNeWithUnequalSetsReturnsTrue) {
// ({0, 1, 2} != {1, 2, 3}) is True
HandleScope scope(thread_);
Set set(&scope, setFromRange(0, 3));
Set set1(&scope, setFromRange(1, 4));
Object result(&scope, runBuiltin(METH(set, __ne__), set, set1));
ASSERT_EQ(*result, Bool::trueObj());
}
TEST_F(SetBuiltinsTest, DunderGeWithSameSetReturnsTrue) {
// s = {0, 1, 2}; (s >= s) is True
HandleScope scope(thread_);
Set set(&scope, setFromRange(0, 3));
Object result(&scope, runBuiltin(METH(set, __ge__), set, set));
ASSERT_EQ(*result, Bool::trueObj());
}
TEST_F(SetBuiltinsTest, DunderGeWithEqualSetsReturnsTrue) {
// ({0, 1, 2} >= {0, 1, 2}) is True
HandleScope scope(thread_);
Set set(&scope, setFromRange(0, 3));
Set set1(&scope, setFromRange(0, 3));
Object result(&scope, runBuiltin(METH(set, __ge__), set, set1));
ASSERT_EQ(*result, Bool::trueObj());
}
TEST_F(SetBuiltinsTest, DunderGeWithSupersetReturnsFalse) {
// ({0, 1, 2} >= {0, 1, 2, 3}) is False
HandleScope scope(thread_);
Set set(&scope, setFromRange(0, 3));
Set set1(&scope, setFromRange(0, 4));
Object result(&scope, runBuiltin(METH(set, __ge__), set, set1));
ASSERT_EQ(*result, Bool::falseObj());
}
TEST_F(SetBuiltinsTest, DunderGeWithEmptySetReturnsTrue) {
// ({0, 1, 2} >= set()) is True
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, setFromRange(0, 3));
Set set1(&scope, runtime_->newSet());
Object result(&scope, runBuiltin(METH(set, __ge__), set, set1));
ASSERT_EQ(*result, Bool::trueObj());
}
TEST_F(SetBuiltinsTest, DunderLeWithEmptySetReturnsTrue) {
// s = {0, 1, 2}; (s <= s) is True
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
Set set1(&scope, runtime_->newSet());
Object result(&scope, runBuiltin(METH(set, __le__), set, set1));
ASSERT_EQ(*result, Bool::trueObj());
}
TEST_F(SetBuiltinsTest, DunderLeWithEqualSetsReturnsTrue) {
// ({0, 1, 2} <= {0, 1, 2}) is True
HandleScope scope(thread_);
Set set(&scope, setFromRange(0, 3));
Set set1(&scope, setFromRange(0, 3));
Object result(&scope, runBuiltin(METH(set, __le__), set, set1));
ASSERT_EQ(*result, Bool::trueObj());
}
TEST_F(SetBuiltinsTest, DunderLeWithSubsetReturnsFalse) {
// ({0, 1, 2, 3} <= {0, 1, 2}) is False
HandleScope scope(thread_);
Set set(&scope, setFromRange(0, 4));
Set set1(&scope, setFromRange(0, 3));
Object result(&scope, runBuiltin(METH(set, __le__), set, set1));
ASSERT_EQ(*result, Bool::falseObj());
}
TEST_F(SetBuiltinsTest, DunderLeWithEmptySetReturnsFalse) {
// ({0, 1, 2} <= set()) is False
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, setFromRange(0, 3));
Set set1(&scope, runtime_->newSet());
Object result(&scope, runBuiltin(METH(set, __le__), set, set1));
ASSERT_EQ(*result, Bool::falseObj());
}
TEST_F(SetBuiltinsTest, DunderGtWithEqualSetsReturnsFalse) {
// ({0, 1, 2} > {0, 1, 2}) is False
HandleScope scope(thread_);
Set set(&scope, setFromRange(0, 3));
Set set1(&scope, setFromRange(0, 3));
Object result(&scope, runBuiltin(METH(set, __gt__), set, set1));
ASSERT_EQ(*result, Bool::falseObj());
}
TEST_F(SetBuiltinsTest, DunderGtWithSubsetReturnsTrue) {
// ({0, 1, 2, 3} > {0, 1, 2}) is True
HandleScope scope(thread_);
Set set(&scope, setFromRange(0, 4));
Set set1(&scope, setFromRange(0, 3));
Object result(&scope, runBuiltin(METH(set, __gt__), set, set1));
ASSERT_EQ(*result, Bool::trueObj());
}
TEST_F(SetBuiltinsTest, DunderGtWithSupersetReturnsFalse) {
// ({0, 1, 2} > {0, 1, 2, 3}) is False
HandleScope scope(thread_);
Set set(&scope, setFromRange(0, 3));
Set set1(&scope, setFromRange(0, 4));
Object result(&scope, runBuiltin(METH(set, __gt__), set, set1));
ASSERT_EQ(*result, Bool::falseObj());
}
TEST_F(SetBuiltinsTest, DunderLtWithEqualSetsReturnsFalse) {
// ({0, 1, 2} < {0, 1, 2}) is False
HandleScope scope(thread_);
Set set(&scope, setFromRange(0, 3));
Set set1(&scope, setFromRange(0, 3));
Object result(&scope, runBuiltin(METH(set, __lt__), set, set1));
ASSERT_EQ(*result, Bool::falseObj());
}
TEST_F(SetBuiltinsTest, DunderLtWithSupersetReturnsTrue) {
// ({0, 1, 2} < {0, 1, 2, 3}) is True
HandleScope scope(thread_);
Set set(&scope, setFromRange(0, 3));
Set set1(&scope, setFromRange(0, 4));
Object result(&scope, runBuiltin(METH(set, __lt__), set, set1));
ASSERT_EQ(*result, Bool::trueObj());
}
TEST_F(SetBuiltinsTest, DunderLtWithSubsetReturnsFalse) {
// ({0, 1, 2, 3} < {0, 1, 2}) is False
HandleScope scope(thread_);
Set set(&scope, setFromRange(0, 4));
Set set1(&scope, setFromRange(0, 3));
Object result(&scope, runBuiltin(METH(set, __lt__), set, set1));
ASSERT_EQ(*result, Bool::falseObj());
}
TEST_F(SetBuiltinsTest, DunderEqWithNonSetSecondArgReturnsNotImplemented) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
Object none(&scope, NoneType::object());
Object result(&scope, runBuiltin(METH(set, __eq__), set, none));
ASSERT_EQ(*result, NotImplementedType::object());
}
TEST_F(SetBuiltinsTest, DunderNeWithNonSetSecondArgReturnsNotImplemented) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
Object none(&scope, NoneType::object());
Object result(&scope, runBuiltin(METH(set, __ne__), set, none));
ASSERT_EQ(*result, NotImplementedType::object());
}
TEST_F(SetBuiltinsTest, DunderGeWithNonSetSecondArgReturnsNotImplemented) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
Object none(&scope, NoneType::object());
Object result(&scope, runBuiltin(METH(set, __ge__), set, none));
ASSERT_EQ(*result, NotImplementedType::object());
}
TEST_F(SetBuiltinsTest, DunderGtWithNonSetSecondArgReturnsNotImplemented) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
Object none(&scope, NoneType::object());
Object result(&scope, runBuiltin(METH(set, __gt__), set, none));
ASSERT_EQ(*result, NotImplementedType::object());
}
TEST_F(SetBuiltinsTest, DunderLeWithNonSetSecondArgReturnsNotImplemented) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
Object none(&scope, NoneType::object());
Object result(&scope, runBuiltin(METH(set, __le__), set, none));
ASSERT_EQ(*result, NotImplementedType::object());
}
TEST_F(SetBuiltinsTest, DunderLtWithNonSetSecondArgReturnsNotImplemented) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
Object none(&scope, NoneType::object());
Object result(&scope, runBuiltin(METH(set, __lt__), set, none));
ASSERT_EQ(*result, NotImplementedType::object());
}
TEST_F(SetBuiltinsTest, DunderInitWithNonIterableRaisesTypeError) {
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
set.__init__(set(), None)
)"),
LayoutId::kTypeError,
"'NoneType' object is not iterable"));
}
TEST_F(SetBuiltinsTest, DunderInitWithIteratorUpdatesSet) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
Set set1(&scope, setFromRange(0, 3));
Object result(&scope, runBuiltin(METH(set, __init__), set, set1));
ASSERT_TRUE(result.isNoneType());
EXPECT_EQ(set.numItems(), set1.numItems());
Object key(&scope, SmallInt::fromWord(0));
EXPECT_TRUE(setIncludes(thread, set, key));
key = SmallInt::fromWord(1);
EXPECT_TRUE(setIncludes(thread, set, key));
key = SmallInt::fromWord(2);
EXPECT_TRUE(setIncludes(thread, set, key));
}
TEST_F(SetBuiltinsTest, DunderInitWithSetSubclassUpdatesSet) {
Thread* thread = Thread::current();
HandleScope scope(thread);
ASSERT_FALSE(runFromCStr(runtime_, R"(
class Set(set): pass
s = Set([0, 1, 2])
)")
.isError());
Object s(&scope, mainModuleAt(runtime_, "s"));
ASSERT_TRUE(runtime_->isInstanceOfSet(*s));
Object key(&scope, SmallInt::fromWord(0));
Set set(&scope, *s);
EXPECT_TRUE(setIncludes(thread, set, key));
key = SmallInt::fromWord(1);
EXPECT_TRUE(setIncludes(thread, set, key));
key = SmallInt::fromWord(2);
EXPECT_TRUE(setIncludes(thread, set, key));
}
TEST_F(SetBuiltinsTest, DunderLenWithSetSubclassReturnsLen) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
class Set(set): pass
s = Set([0, 1, 2])
)")
.isError());
Object s(&scope, mainModuleAt(runtime_, "s"));
ASSERT_TRUE(runtime_->isInstanceOfSet(*s));
Object result(&scope, runBuiltin(METH(set, __len__), s));
EXPECT_TRUE(isIntEqualsWord(*result, 3));
}
TEST_F(SetBuiltinsTest, FrozenSetDunderNewReturnsSingleton) {
ASSERT_FALSE(
runFromCStr(runtime_, "result = frozenset.__new__(frozenset)").isError());
HandleScope scope(thread_);
Object result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_TRUE(result.isFrozenSet());
EXPECT_EQ(*result, runtime_->emptyFrozenSet());
}
TEST_F(SetBuiltinsTest, SubclassOfFrozenSetDunderNewDoesNotReturnSingleton) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class C(frozenset):
pass
o = C()
)")
.isError());
HandleScope scope(thread_);
Object o(&scope, mainModuleAt(runtime_, "o"));
EXPECT_NE(*o, runtime_->emptyFrozenSet());
}
TEST_F(SetBuiltinsTest, FrozenSetDunderNewFromEmptyIterableReturnsSingleton) {
HandleScope scope(thread_);
Type type(&scope, runtime_->typeAt(LayoutId::kFrozenSet));
List empty_iterable(&scope, runtime_->newList());
Object result(&scope,
runBuiltin(METH(frozenset, __new__), type, empty_iterable));
EXPECT_EQ(*result, runtime_->emptyFrozenSet());
}
TEST_F(SetBuiltinsTest, FrozenSetDunderNewFromFrozenSetIsIdempotent) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Type type(&scope, runtime_->typeAt(LayoutId::kFrozenSet));
List nonempty_list(&scope, listFromRange(1, 5));
FrozenSet frozenset(&scope, runtime_->newFrozenSet());
frozenset = setUpdate(Thread::current(), frozenset, nonempty_list);
Object result(&scope, runBuiltin(METH(frozenset, __new__), type, frozenset));
EXPECT_EQ(*result, *frozenset);
}
TEST_F(SetBuiltinsTest,
FrozenSetDunderNewFromIterableContainsIterableElements) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Type type(&scope, runtime_->typeAt(LayoutId::kFrozenSet));
List nonempty_list(&scope, listFromRange(1, 5));
Object result_obj(&scope,
runBuiltin(METH(frozenset, __new__), type, nonempty_list));
ASSERT_TRUE(result_obj.isFrozenSet());
FrozenSet result(&scope, *result_obj);
EXPECT_EQ(result.numItems(), 4);
Int one(&scope, SmallInt::fromWord(1));
EXPECT_TRUE(setIncludes(thread, result, one));
Int two(&scope, SmallInt::fromWord(2));
EXPECT_TRUE(setIncludes(thread, result, two));
Int three(&scope, SmallInt::fromWord(3));
EXPECT_TRUE(setIncludes(thread, result, three));
Int four(&scope, SmallInt::fromWord(4));
EXPECT_TRUE(setIncludes(thread, result, four));
}
TEST_F(SetBuiltinsTest, FrozenSetFromIterableIsNotSingleton) {
HandleScope scope(thread_);
Type type(&scope, runtime_->typeAt(LayoutId::kFrozenSet));
List nonempty_list(&scope, listFromRange(1, 5));
Object result1(&scope,
runBuiltin(METH(frozenset, __new__), type, nonempty_list));
ASSERT_TRUE(result1.isFrozenSet());
Object result2(&scope,
runBuiltin(METH(frozenset, __new__), type, nonempty_list));
ASSERT_TRUE(result2.isFrozenSet());
ASSERT_NE(*result1, *result2);
}
TEST_F(SetBuiltinsTest, FrozenSetDunderNewWithNonIterableRaisesTypeError) {
HandleScope scope(thread_);
Type type(&scope, runtime_->typeAt(LayoutId::kFrozenSet));
Object none(&scope, NoneType::object());
Object result(&scope, runBuiltin(METH(frozenset, __new__), type, none));
ASSERT_TRUE(result.isError());
}
TEST_F(SetBuiltinsTest, SetCopy) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
Object set_copy(&scope, setCopy(thread, set));
ASSERT_TRUE(set_copy.isSet());
EXPECT_EQ(Set::cast(*set_copy).numItems(), 0);
Object key(&scope, SmallInt::fromWord(0));
setHashAndAdd(thread, set, key);
key = SmallInt::fromWord(1);
setHashAndAdd(thread, set, key);
key = SmallInt::fromWord(2);
setHashAndAdd(thread, set, key);
Object set_copy1(&scope, setCopy(thread, set));
ASSERT_TRUE(set_copy1.isSet());
EXPECT_EQ(Set::cast(*set_copy1).numItems(), 3);
set = *set_copy1;
key = SmallInt::fromWord(0);
EXPECT_TRUE(setIncludes(thread, set, key));
key = SmallInt::fromWord(1);
EXPECT_TRUE(setIncludes(thread, set, key));
key = SmallInt::fromWord(2);
EXPECT_TRUE(setIncludes(thread, set, key));
}
TEST_F(SetBuiltinsTest, SetEqualsWithSameSetReturnsTrue) {
// s = {0, 1, 2}; (s == s) is True
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, setFromRange(0, 3));
ASSERT_TRUE(setEquals(thread, set, set));
}
TEST_F(SetBuiltinsTest, SetIsSubsetWithEmptySetsReturnsTrue) {
// (set() <= set()) is True
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
Set set1(&scope, runtime_->newSet());
ASSERT_TRUE(setIsSubset(thread, set, set1));
}
TEST_F(SetBuiltinsTest, SetIsSubsetWithEmptySetAndNonEmptySetReturnsTrue) {
// (set() <= {0, 1, 2}) is True
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
Set set1(&scope, setFromRange(0, 3));
ASSERT_TRUE(setIsSubset(thread, set, set1));
}
TEST_F(SetBuiltinsTest, SetIsSubsetWithEqualsetReturnsTrue) {
// ({0, 1, 2} <= {0, 1, 2}) is True
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, setFromRange(0, 3));
Set set1(&scope, setFromRange(0, 3));
ASSERT_TRUE(setIsSubset(thread, set, set1));
}
TEST_F(SetBuiltinsTest, SetIsSubsetWithSubsetReturnsTrue) {
// ({1, 2, 3} <= {1, 2, 3, 4}) is True
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, setFromRange(1, 4));
Set set1(&scope, setFromRange(1, 5));
ASSERT_TRUE(setIsSubset(thread, set, set1));
}
TEST_F(SetBuiltinsTest, SetIsSubsetWithSupersetReturnsFalse) {
// ({1, 2, 3, 4} <= {1, 2, 3}) is False
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, setFromRange(1, 5));
Set set1(&scope, setFromRange(1, 4));
ASSERT_FALSE(setIsSubset(thread, set, set1));
}
TEST_F(SetBuiltinsTest, SetIsSubsetWithSameSetReturnsTrue) {
// s = {0, 1, 2}; (s <= s) is True
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, setFromRange(0, 4));
ASSERT_TRUE(setIsSubset(thread, set, set));
}
TEST_F(SetBuiltinsTest, SetIsProperSubsetWithSupersetReturnsTrue) {
// ({0, 1, 2, 3} < {0, 1, 2, 3, 4}) is True
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, setFromRange(0, 4));
Set set1(&scope, setFromRange(0, 5));
ASSERT_TRUE(setIsProperSubset(thread, set, set1));
}
TEST_F(SetBuiltinsTest, SetIsProperSubsetWithUnequalSetsReturnsFalse) {
// ({1, 2, 3} < {0, 1, 2}) is False
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, setFromRange(1, 4));
Set set1(&scope, setFromRange(0, 3));
ASSERT_FALSE(setIsProperSubset(thread, set, set1));
}
TEST_F(SetBuiltinsTest, SetIsProperSubsetWithSameSetReturnsFalse) {
// s = {0, 1, 2}; (s < s) is False
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, setFromRange(0, 3));
ASSERT_FALSE(setIsProperSubset(thread, set, set));
}
TEST_F(SetBuiltinsTest, SetIsProperSubsetWithSubsetReturnsFalse) {
// ({1, 2, 3, 4} < {1, 2, 3}) is False
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, setFromRange(1, 5));
Set set1(&scope, setFromRange(1, 4));
ASSERT_FALSE(setIsProperSubset(thread, set, set1));
}
TEST_F(SetBuiltinsTest, RecursiveSetPrintsEllipsis) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class C:
def __init__(self, obj):
self.val = obj
def __repr__(self):
return self.val.__repr__()
def __hash__(self):
return 5
s = set()
c = C(s)
s.add(c)
result = s.__repr__()
)")
.isError());
EXPECT_TRUE(isStrEqualsCStr(mainModuleAt(runtime_, "result"), "{set(...)}"));
}
TEST_F(SetBuiltinsTest, CopyReturnsNewObject) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
Object result(&scope, runBuiltin(METH(set, copy), set));
EXPECT_NE(*set, *result);
EXPECT_TRUE(result.isSet());
}
TEST_F(SetBuiltinsTest, CopyReturnsShallowCopy) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
Object obj(&scope, newTupleWithNone(5));
setHashAndAdd(thread, set, obj);
Set set2(&scope, runBuiltin(METH(set, copy), set));
bool has_object = false;
Object value(&scope, NoneType::object());
for (word i = 0; setNextItem(set2, &i, &value);) {
if (value == *obj) {
has_object = true;
break;
}
}
EXPECT_TRUE(has_object);
}
TEST_F(FrozenSetBuiltinsTest, CopyFrozenSetReturnsSameObject) {
Thread* thread = Thread::current();
HandleScope scope(thread);
FrozenSet set(&scope, runtime_->newFrozenSet());
Object result(&scope, runBuiltin(METH(frozenset, copy), set));
EXPECT_EQ(*set, *result);
EXPECT_TRUE(result.isFrozenSet());
}
TEST_F(FrozenSetBuiltinsTest, CopyFrozenSetSubsetReturnsNewObject) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
class C(frozenset):
pass
sub = C()
result = frozenset.copy(sub)
)")
.isError());
Object sub(&scope, mainModuleAt(runtime_, "sub"));
Object result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_TRUE(runtime_->isInstanceOfFrozenSet(*sub));
EXPECT_TRUE(runtime_->isInstanceOfFrozenSet(*result));
EXPECT_FALSE(sub.isFrozenSet());
EXPECT_TRUE(result.isFrozenSet());
EXPECT_NE(sub, result);
}
TEST_F(FrozenSetBuiltinsTest, CopyMakesShallowCopy) {
Thread* thread = Thread::current();
HandleScope scope(thread);
FrozenSet set(&scope, runtime_->newFrozenSet());
Object obj(&scope, newTupleWithNone(5));
setHashAndAdd(thread, set, obj);
FrozenSet set2(&scope, runBuiltin(METH(frozenset, copy), set));
bool has_object = false;
Object value(&scope, NoneType::object());
for (word i = 0; setNextItem(set2, &i, &value);) {
if (value == *obj) {
has_object = true;
break;
}
}
EXPECT_TRUE(has_object);
}
TEST_F(SetBuiltinsTest, UpdateWithNoArgsDoesNothing) {
Thread* thread = Thread::current();
HandleScope scope(thread);
Set set(&scope, runtime_->newSet());
Tuple starargs(&scope, runtime_->emptyTuple());
Object result(&scope, runBuiltin(METH(set, update), set, starargs));
EXPECT_TRUE(result.isNoneType());
EXPECT_EQ(set.numItems(), 0);
}
TEST_F(SetBuiltinsTest, UpdateWithNonIterableRaisesTypeError) {
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
result = set()
result.update({5}, {6}, None)
)"),
LayoutId::kTypeError,
"'NoneType' object is not iterable"));
HandleScope scope(thread_);
Set result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_EQ(result.numItems(), 2);
}
TEST_F(SetBuiltinsTest, UpdateWithSetAddsElements) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
result = set()
result.update({5})
)")
.isError());
HandleScope scope(thread_);
Set result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_EQ(result.numItems(), 1);
}
TEST_F(SetBuiltinsTest, UpdateWithMultipleSetsAddsAllElements) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
result = set()
result.update({5}, {6})
)")
.isError());
HandleScope scope(thread_);
Set result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_EQ(result.numItems(), 2);
}
TEST_F(SetBuiltinsTest, UpdateWithIterableAddsElements) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
result = set([1, 2])
result.update([5, 6])
)")
.isError());
HandleScope scope(thread_);
Set result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_EQ(result.numItems(), 4);
}
TEST_F(SetBuiltinsTest, DunderOrWithNonSetBaseOtherReturnsNotImplemented) {
ASSERT_FALSE(
runFromCStr(runtime_, "result = set.__or__(set(), None)").isError());
EXPECT_EQ(mainModuleAt(runtime_, "result"), NotImplementedType::object());
}
TEST_F(SetBuiltinsTest, DunderOrReturnsSetContainingUnionOfElements) {
ASSERT_FALSE(
runFromCStr(runtime_, "result = set.__or__({1, 2}, {2, 3})").isError());
Thread* thread = Thread::current();
HandleScope scope(thread);
Object result_obj(&scope, mainModuleAt(runtime_, "result"));
EXPECT_TRUE(result_obj.isSet());
Set result(&scope, *result_obj);
EXPECT_EQ(result.numItems(), 3);
Object one(&scope, SmallInt::fromWord(1));
EXPECT_TRUE(setIncludes(thread, result, one));
Object two(&scope, SmallInt::fromWord(2));
EXPECT_TRUE(setIncludes(thread, result, two));
Object three(&scope, SmallInt::fromWord(3));
EXPECT_TRUE(setIncludes(thread, result, three));
}
} // namespace testing
} // namespace py