runtime/builtins-module-test.cpp (1,306 lines of code) (raw):
// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
#include "builtins-module.h"
#include "gtest/gtest.h"
#include "builtins.h"
#include "dict-builtins.h"
#include "module-builtins.h"
#include "runtime.h"
#include "str-builtins.h"
#include "test-utils.h"
#include "trampolines.h"
namespace py {
namespace testing {
using BuiltinsModuleTest = RuntimeFixture;
using BuiltinsModuleDeathTest = RuntimeFixture;
TEST_F(BuiltinsModuleTest, BuiltinCallableOnTypeReturnsTrue) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class Foo:
pass
a = callable(Foo)
)")
.isError());
HandleScope scope(thread_);
Bool a(&scope, mainModuleAt(runtime_, "a"));
EXPECT_TRUE(a.value());
}
TEST_F(BuiltinsModuleTest, BuiltinCallableOnMethodReturnsTrue) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class Foo:
def bar():
return None
a = callable(Foo.bar)
b = callable(Foo().bar)
)")
.isError());
HandleScope scope(thread_);
Bool a(&scope, mainModuleAt(runtime_, "a"));
Bool b(&scope, mainModuleAt(runtime_, "b"));
EXPECT_TRUE(a.value());
EXPECT_TRUE(b.value());
}
TEST_F(BuiltinsModuleTest, BuiltinCallableOnNonCallableReturnsFalse) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
a = callable(1)
b = callable("hello")
)")
.isError());
HandleScope scope(thread_);
Bool a(&scope, mainModuleAt(runtime_, "a"));
Bool b(&scope, mainModuleAt(runtime_, "b"));
EXPECT_FALSE(a.value());
EXPECT_FALSE(b.value());
}
TEST_F(BuiltinsModuleTest, BuiltinCallableOnObjectWithCallOnTypeReturnsTrue) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class Foo:
def __call__(self):
pass
f = Foo()
a = callable(f)
)")
.isError());
HandleScope scope(thread_);
Bool a(&scope, mainModuleAt(runtime_, "a"));
EXPECT_TRUE(a.value());
}
TEST_F(BuiltinsModuleTest,
BuiltinCallableOnObjectWithInstanceCallButNoTypeCallReturnsFalse) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class Foo:
pass
def fakecall():
pass
f = Foo()
f.__call__ = fakecall
a = callable(f)
)")
.isError());
HandleScope scope(thread_);
Bool a(&scope, mainModuleAt(runtime_, "a"));
EXPECT_FALSE(a.value());
}
TEST_F(BuiltinsModuleTest, DirCallsDunderDirReturnsSortedList) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
class C:
def __dir__(self):
return ["B", "A"]
c = C()
d = dir(c)
)")
.isError());
Object d_obj(&scope, mainModuleAt(runtime_, "d"));
ASSERT_TRUE(d_obj.isList());
List d(&scope, *d_obj);
ASSERT_EQ(d.numItems(), 2);
EXPECT_TRUE(isStrEqualsCStr(d.at(0), "A"));
EXPECT_TRUE(isStrEqualsCStr(d.at(1), "B"));
}
TEST_F(BuiltinsModuleTest, EllipsisMatchesEllipsis) {
EXPECT_EQ(moduleAtByCStr(runtime_, "builtins", "Ellipsis"),
runtime_->ellipsis());
}
TEST_F(BuiltinsModuleTest, IdReturnsInt) {
HandleScope scope(thread_);
Object obj(&scope, runtime_->newInt(12345));
EXPECT_TRUE(runBuiltin(FUNC(builtins, id), obj).isInt());
}
TEST_F(BuiltinsModuleTest, IdDoesNotChangeAfterGC) {
HandleScope scope(thread_);
Object obj(&scope, runtime_->newStrFromCStr("hello world foobar"));
Object id_before(&scope, runBuiltin(FUNC(builtins, id), obj));
runtime_->collectGarbage();
Object id_after(&scope, runBuiltin(FUNC(builtins, id), obj));
EXPECT_EQ(*id_before, *id_after);
}
TEST_F(BuiltinsModuleTest, IdReturnsDifferentValueForDifferentObject) {
HandleScope scope(thread_);
Object obj1(&scope, runtime_->newStrFromCStr("hello world foobar"));
Object obj2(&scope, runtime_->newStrFromCStr("hello world foobarbaz"));
EXPECT_NE(runBuiltin(FUNC(builtins, id), obj1),
runBuiltin(FUNC(builtins, id), obj2));
}
TEST_F(BuiltinsModuleTest, BuiltinLenGetLenFromDict) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
len0 = len({})
len1 = len({'one': 1})
len5 = len({'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5})
)")
.isError());
HandleScope scope(thread_);
Object len0(&scope, mainModuleAt(runtime_, "len0"));
EXPECT_EQ(*len0, SmallInt::fromWord(0));
Object len1(&scope, mainModuleAt(runtime_, "len1"));
EXPECT_EQ(*len1, SmallInt::fromWord(1));
Object len5(&scope, mainModuleAt(runtime_, "len5"));
EXPECT_EQ(*len5, SmallInt::fromWord(5));
}
TEST_F(BuiltinsModuleTest, BuiltinLenGetLenFromList) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
len0 = len([])
len1 = len([1])
len5 = len([1,2,3,4,5])
)")
.isError());
HandleScope scope(thread_);
Object len0(&scope, mainModuleAt(runtime_, "len0"));
EXPECT_EQ(*len0, SmallInt::fromWord(0));
Object len1(&scope, mainModuleAt(runtime_, "len1"));
EXPECT_EQ(*len1, SmallInt::fromWord(1));
Object len5(&scope, mainModuleAt(runtime_, "len5"));
EXPECT_EQ(*len5, SmallInt::fromWord(5));
}
TEST_F(BuiltinsModuleTest, BuiltinLenGetLenFromSet) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
len1 = len({1})
len5 = len({1,2,3,4,5})
)")
.isError());
HandleScope scope(thread_);
// TODO(cshapiro): test the empty set when we have builtins.set defined.
Object len1(&scope, mainModuleAt(runtime_, "len1"));
EXPECT_EQ(*len1, SmallInt::fromWord(1));
Object len5(&scope, mainModuleAt(runtime_, "len5"));
EXPECT_EQ(*len5, SmallInt::fromWord(5));
}
TEST_F(BuiltinsModuleTest, BuiltinOrd) {
HandleScope scope(thread_);
Str str(&scope, runtime_->newStrFromCStr("A"));
EXPECT_TRUE(isIntEqualsWord(runBuiltin(FUNC(builtins, ord), str), 65));
Int one(&scope, SmallInt::fromWord(1));
EXPECT_TRUE(raisedWithStr(runBuiltin(FUNC(builtins, ord), one),
LayoutId::kTypeError,
"Unsupported type in builtin 'ord'"));
}
TEST_F(BuiltinsModuleTest, BuiltinOrdWithBytearray) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
a_bytearray = bytearray(b'A')
)")
.isError());
HandleScope scope(thread_);
Object a_bytearray(&scope, mainModuleAt(runtime_, "a_bytearray"));
EXPECT_TRUE(
isIntEqualsWord(runBuiltin(FUNC(builtins, ord), a_bytearray), 65));
}
TEST_F(BuiltinsModuleTest, BuiltinOrdWithEmptyBytearrayRaisesTypeError) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
a_bytearray = bytearray(b'')
)")
.isError());
HandleScope scope(thread_);
Object empty(&scope, mainModuleAt(runtime_, "a_bytearray"));
EXPECT_TRUE(raisedWithStr(runBuiltin(FUNC(builtins, ord), empty),
LayoutId::kTypeError,
"Builtin 'ord' expects string of length 1"));
}
TEST_F(BuiltinsModuleTest, BuiltinOrdWithLongBytearrayRaisesTypeError) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
a_bytearray = bytearray(b'AB')
)")
.isError());
HandleScope scope(thread_);
Object not_a_char(&scope, mainModuleAt(runtime_, "a_bytearray"));
EXPECT_TRUE(raisedWithStr(runBuiltin(FUNC(builtins, ord), not_a_char),
LayoutId::kTypeError,
"Builtin 'ord' expects string of length 1"));
}
TEST_F(BuiltinsModuleTest, BuiltinOrdWithBytes) {
unsigned char bytes[] = {'A'};
HandleScope scope(thread_);
Object a_bytes(&scope, runtime_->newBytesWithAll(bytes));
EXPECT_TRUE(isIntEqualsWord(runBuiltin(FUNC(builtins, ord), a_bytes), 65));
}
TEST_F(BuiltinsModuleTest, BuiltinOrdWithEmptyBytesRaisesTypeError) {
HandleScope scope(thread_);
Object empty(&scope, Bytes::empty());
EXPECT_TRUE(raisedWithStr(runBuiltin(FUNC(builtins, ord), empty),
LayoutId::kTypeError,
"Builtin 'ord' expects string of length 1"));
}
TEST_F(BuiltinsModuleTest, BuiltinOrdWithLongBytesRaisesTypeError) {
unsigned char bytes[] = {'A', 'B'};
HandleScope scope(thread_);
Object too_many_bytes(&scope, runtime_->newBytesWithAll(bytes));
EXPECT_TRUE(raisedWithStr(runBuiltin(FUNC(builtins, ord), too_many_bytes),
LayoutId::kTypeError,
"Builtin 'ord' expects string of length 1"));
}
TEST_F(BuiltinsModuleTest, BuiltinOrdWithStrSubclass) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class MyStr(str): pass
a_str = MyStr("A")
)")
.isError());
HandleScope scope(thread_);
Object a_str(&scope, mainModuleAt(runtime_, "a_str"));
EXPECT_TRUE(isIntEqualsWord(runBuiltin(FUNC(builtins, ord), a_str), 65));
}
TEST_F(BuiltinsModuleTest, BuiltinOrdSupportNonASCII) {
HandleScope scope(thread_);
Str two_bytes(&scope, runtime_->newStrFromCStr("\xC3\xA9"));
Object two_ord(&scope, runBuiltin(FUNC(builtins, ord), two_bytes));
EXPECT_TRUE(isIntEqualsWord(*two_ord, 0xE9));
Str three_bytes(&scope, runtime_->newStrFromCStr("\xE2\xB3\x80"));
Object three_ord(&scope, runBuiltin(FUNC(builtins, ord), three_bytes));
EXPECT_TRUE(isIntEqualsWord(*three_ord, 0x2CC0));
Str four_bytes(&scope, runtime_->newStrFromCStr("\xF0\x9F\x86\x92"));
Object four_ord(&scope, runBuiltin(FUNC(builtins, ord), four_bytes));
EXPECT_TRUE(isIntEqualsWord(*four_ord, 0x1F192));
}
TEST_F(BuiltinsModuleTest, BuiltinOrdWithEmptyStrRaisesTypeError) {
HandleScope scope(thread_);
Object empty(&scope, Str::empty());
EXPECT_TRUE(raisedWithStr(runBuiltin(FUNC(builtins, ord), empty),
LayoutId::kTypeError,
"Builtin 'ord' expects string of length 1"));
}
TEST_F(BuiltinsModuleTest, BuiltinOrdWithEmptyStrSubclassRaisesTypeError) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class MyStr(str): pass
empty = MyStr("")
)")
.isError());
HandleScope scope(thread_);
Object empty(&scope, mainModuleAt(runtime_, "empty"));
EXPECT_TRUE(raisedWithStr(runBuiltin(FUNC(builtins, ord), empty),
LayoutId::kTypeError,
"Builtin 'ord' expects string of length 1"));
}
TEST_F(BuiltinsModuleTest, BuiltinOrdStrWithManyCodePointsRaisesTypeError) {
HandleScope scope(thread_);
Object two_chars(&scope, runtime_->newStrFromCStr("ab"));
EXPECT_TRUE(raisedWithStr(runBuiltin(FUNC(builtins, ord), two_chars),
LayoutId::kTypeError,
"Builtin 'ord' expects string of length 1"));
}
TEST_F(BuiltinsModuleTest,
BuiltinOrdStrSubclassWithManyCodePointsRaiseTypeError) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class MyStr(str): pass
two_code_points = MyStr("ab")
)")
.isError());
HandleScope scope(thread_);
Object two_code_points(&scope, mainModuleAt(runtime_, "two_code_points"));
EXPECT_TRUE(raisedWithStr(runBuiltin(FUNC(builtins, ord), two_code_points),
LayoutId::kTypeError,
"Builtin 'ord' expects string of length 1"));
}
TEST_F(BuiltinsModuleTest, BuiltInReprOnUserTypeWithDunderRepr) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class Foo:
def __repr__(self):
return "foo"
a = repr(Foo())
)")
.isError());
HandleScope scope(thread_);
Object a(&scope, mainModuleAt(runtime_, "a"));
EXPECT_TRUE(isStrEqualsCStr(*a, "foo"));
}
TEST_F(BuiltinsModuleTest, BuiltInReprOnClass) {
ASSERT_FALSE(runFromCStr(runtime_, "result = repr(int)").isError());
HandleScope scope(thread_);
Object result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_TRUE(isStrEqualsCStr(*result, "<class 'int'>"));
}
TEST_F(BuiltinsModuleTest, BuiltInAsciiCallsDunderRepr) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class Foo:
def __repr__(self):
return "foo"
a = ascii(Foo())
)")
.isError());
HandleScope scope(thread_);
Object a(&scope, mainModuleAt(runtime_, "a"));
EXPECT_TRUE(isStrEqualsCStr(*a, "foo"));
}
TEST_F(BuiltinsModuleTest, DunderBuildClassWithNonFunctionRaisesTypeError) {
HandleScope scope(thread_);
Object body(&scope, NoneType::object());
Object name(&scope, runtime_->newStrFromCStr("a"));
Object metaclass(&scope, Unbound::object());
Object bootstrap(&scope, Bool::falseObj());
Object bases(&scope, runtime_->emptyTuple());
Object kwargs(&scope, runtime_->newDict());
EXPECT_TRUE(raisedWithStr(
runBuiltin(FUNC(builtins, __build_class__), body, name, metaclass,
bootstrap, bases, kwargs),
LayoutId::kTypeError, "__build_class__: func must be a function"));
}
TEST_F(BuiltinsModuleTest, DunderBuildClassWithNonStringRaisesTypeError) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, "def f(): pass").isError());
Object body(&scope, mainModuleAt(runtime_, "f"));
Object name(&scope, NoneType::object());
Object metaclass(&scope, Unbound::object());
Object bootstrap(&scope, Bool::falseObj());
Object bases(&scope, runtime_->emptyTuple());
Object kwargs(&scope, runtime_->newDict());
EXPECT_TRUE(raisedWithStr(
runBuiltin(FUNC(builtins, __build_class__), body, name, metaclass,
bootstrap, bases, kwargs),
LayoutId::kTypeError, "__build_class__: name is not a string"));
}
TEST_F(BuiltinsModuleTest, DunderBuildClassCallsMetaclass) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
class Meta(type):
def __new__(mcls, name, bases, namespace, *args, **kwargs):
return (mcls, name, bases, namespace, args, kwargs)
class C(int, float, metaclass=Meta, hello="world"):
x = 42
)")
.isError());
Object meta(&scope, mainModuleAt(runtime_, "Meta"));
Object c_obj(&scope, mainModuleAt(runtime_, "C"));
ASSERT_TRUE(c_obj.isTuple());
Tuple c(&scope, *c_obj);
ASSERT_EQ(c.length(), 6);
EXPECT_EQ(c.at(0), meta);
EXPECT_TRUE(isStrEqualsCStr(c.at(1), "C"));
ASSERT_TRUE(c.at(2).isTuple());
Tuple c_bases(&scope, c.at(2));
ASSERT_EQ(c_bases.length(), 2);
EXPECT_EQ(c_bases.at(0), runtime_->typeAt(LayoutId::kInt));
EXPECT_EQ(c_bases.at(1), runtime_->typeAt(LayoutId::kFloat));
ASSERT_TRUE(c.at(3).isDict());
Dict c_namespace(&scope, c.at(3));
Str x(&scope, runtime_->newStrFromCStr("x"));
EXPECT_EQ(dictIncludes(thread_, c_namespace, x, strHash(thread_, *x)),
Bool::trueObj());
ASSERT_TRUE(c.at(4).isTuple());
EXPECT_EQ(Tuple::cast(c.at(4)).length(), 0);
Str hello(&scope, runtime_->newStrFromCStr("hello"));
ASSERT_TRUE(c.at(5).isDict());
Dict c_kwargs(&scope, c.at(5));
EXPECT_EQ(c_kwargs.numItems(), 1);
EXPECT_TRUE(isStrEqualsCStr(dictAtByStr(thread_, c_kwargs, hello), "world"));
}
TEST_F(BuiltinsModuleTest, DunderBuildClassCalculatesMostSpecificMetaclass) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
class Meta(type): pass
class C1(int, metaclass=Meta): pass
class C2(C1, metaclass=type): pass
t1 = type(C1)
t2 = type(C2)
)")
.isError());
Object meta(&scope, mainModuleAt(runtime_, "Meta"));
Object t1(&scope, mainModuleAt(runtime_, "t1"));
Object t2(&scope, mainModuleAt(runtime_, "t2"));
ASSERT_TRUE(t1.isType());
ASSERT_TRUE(t2.isType());
EXPECT_EQ(t1, meta);
EXPECT_EQ(t2, meta);
}
TEST_F(BuiltinsModuleTest,
DunderBuildClassWithIncompatibleMetaclassesRaisesTypeError) {
EXPECT_TRUE(raisedWithStr(
runFromCStr(runtime_, R"(
class M1(type): pass
class M2(type): pass
class C1(metaclass=M1): pass
class C2(C1, metaclass=M2): pass
)"),
LayoutId::kTypeError,
"metaclass conflict: the metaclass of a derived class must be a "
"(non-strict) subclass of the metaclasses of all its bases"));
}
TEST_F(BuiltinsModuleTest, DunderBuildClassWithMeetMetaclassUsesMeet) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
class M1(type): pass
class M2(type): pass
class M3(M1, M2): pass
class C1(metaclass=M1): pass
class C2(metaclass=M2): pass
class C3(C1, C2, metaclass=M3): pass
t1 = type(C1)
t2 = type(C2)
t3 = type(C3)
)")
.isError());
Object m1(&scope, mainModuleAt(runtime_, "M1"));
Object m2(&scope, mainModuleAt(runtime_, "M2"));
Object m3(&scope, mainModuleAt(runtime_, "M3"));
Object t1(&scope, mainModuleAt(runtime_, "t1"));
Object t2(&scope, mainModuleAt(runtime_, "t2"));
Object t3(&scope, mainModuleAt(runtime_, "t3"));
ASSERT_TRUE(t1.isType());
ASSERT_TRUE(t2.isType());
ASSERT_TRUE(t3.isType());
EXPECT_EQ(t1, m1);
EXPECT_EQ(t2, m2);
EXPECT_EQ(t3, m3);
}
TEST_F(BuiltinsModuleTest, DunderBuildClassPropagatesDunderPrepareError) {
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
class Meta(type):
@classmethod
def __prepare__(cls, *args, **kwds):
raise IndentationError("foo")
class C(metaclass=Meta):
pass
)"),
LayoutId::kIndentationError, "foo"));
}
TEST_F(BuiltinsModuleTest, DunderBuildClassWithNonDictPrepareRaisesTypeError) {
EXPECT_TRUE(
raisedWithStr(runFromCStr(runtime_, R"(
class Meta(type):
@classmethod
def __prepare__(cls, *args, **kwds):
return 42
class C(metaclass=Meta):
pass
)"),
LayoutId::kTypeError,
"Meta.__prepare__() must return a mapping, not int"));
}
TEST_F(BuiltinsModuleTest,
DunderBuildClassWithNonTypeMetaclassAndNonDictPrepareRaisesTypeError) {
EXPECT_TRUE(raisedWithStr(
runFromCStr(runtime_, R"(
class Meta:
def __prepare__(self, *args, **kwds):
return 42
class C(metaclass=Meta()):
pass
)"),
LayoutId::kTypeError,
"<metaclass>.__prepare__() must return a mapping, not int"));
}
TEST_F(BuiltinsModuleTest, DunderBuildClassUsesDunderPrepareForClassDict) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
class Meta(type):
@classmethod
def __prepare__(cls, *args, **kwds):
return {"foo": 42}
class C(metaclass=Meta):
pass
result = C.foo
)")
.isError());
Object result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_TRUE(isIntEqualsWord(*result, 42));
}
TEST_F(BuiltinsModuleTest, DunderBuildClassPassesNameBasesAndKwargsToPrepare) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
class Meta(type):
def __init__(metacls, name, bases, namespace, **kwargs):
pass
def __new__(metacls, name, bases, namespace, **kwargs):
return super().__new__(metacls, name, bases, namespace)
@classmethod
def __prepare__(metacls, name, bases, **kwargs):
return {"foo": name, "bar": bases[0], "baz": kwargs["answer"]}
class C(int, metaclass=Meta, answer=42):
pass
name = C.foo
base = C.bar
answer = C.baz
)")
.isError());
Object name(&scope, mainModuleAt(runtime_, "name"));
Object base(&scope, mainModuleAt(runtime_, "base"));
Object answer(&scope, mainModuleAt(runtime_, "answer"));
EXPECT_TRUE(isStrEqualsCStr(*name, "C"));
EXPECT_EQ(base, runtime_->typeAt(LayoutId::kInt));
EXPECT_TRUE(isIntEqualsWord(*answer, 42));
}
TEST_F(BuiltinsModuleTest, DunderBuildClassWithRaisingBodyPropagatesException) {
EXPECT_TRUE(raised(runFromCStr(runtime_, R"(
class C:
raise UserWarning()
)"),
LayoutId::kUserWarning));
}
TEST_F(BuiltinsModuleTest, DunderImportWithBuiltinReturnsModule) {
HandleScope scope(thread_);
Object name(&scope, runtime_->newStrFromCStr("_io"));
Object globals(&scope, NoneType::object());
Object locals(&scope, NoneType::object());
Object fromlist(&scope, runtime_->emptyTuple());
Object level(&scope, runtime_->newInt(0));
Object result_obj(&scope, runBuiltin(FUNC(builtins, __import__), name,
globals, locals, fromlist, level));
ASSERT_TRUE(result_obj.isModule());
Module result(&scope, *result_obj);
EXPECT_TRUE(isStrEqualsCStr(result.name(), "_io"));
}
TEST_F(BuiltinsModuleTest, DunderImportWithExtensionModuleReturnsModule) {
HandleScope scope(thread_);
Object name(&scope, runtime_->newStrFromCStr("errno"));
Object globals(&scope, NoneType::object());
Object locals(&scope, NoneType::object());
Object fromlist(&scope, runtime_->emptyTuple());
Object level(&scope, runtime_->newInt(0));
Object result_obj(&scope, runBuiltin(FUNC(builtins, __import__), name,
globals, locals, fromlist, level));
ASSERT_TRUE(result_obj.isModule());
Module result(&scope, *result_obj);
EXPECT_TRUE(isStrEqualsCStr(result.name(), "errno"));
}
TEST_F(BuiltinsModuleTest, DunderImportRaisesImportError) {
HandleScope scope(thread_);
// The minimal implementation should not open files.
Object name(&scope, runtime_->newStrFromCStr("antigravity"));
Object globals(&scope, NoneType::object());
Object locals(&scope, NoneType::object());
Object fromlist(&scope, runtime_->emptyTuple());
Object level(&scope, runtime_->newInt(0));
EXPECT_TRUE(
raisedWithStr(runBuiltin(FUNC(builtins, __import__), name, globals,
locals, fromlist, level),
LayoutId::kImportError,
"failed to import antigravity (bootstrap importer)"));
}
TEST_F(BuiltinsModuleTest, GetAttrFromClassReturnsValue) {
const char* src = R"(
class Foo:
bar = 1
obj = getattr(Foo, 'bar')
)";
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, src).isError());
Object obj(&scope, mainModuleAt(runtime_, "obj"));
EXPECT_EQ(*obj, SmallInt::fromWord(1));
}
TEST_F(BuiltinsModuleTest, GetAttrFromInstanceReturnsValue) {
const char* src = R"(
class Foo:
bar = 1
obj = getattr(Foo(), 'bar')
)";
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, src).isError());
Object obj(&scope, mainModuleAt(runtime_, "obj"));
EXPECT_EQ(*obj, SmallInt::fromWord(1));
}
TEST_F(BuiltinsModuleTest, GetAttrFromInstanceWithMissingAttrReturnsDefault) {
const char* src = R"(
class Foo: pass
obj = getattr(Foo(), 'bar', 2)
)";
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, src).isError());
Object obj(&scope, mainModuleAt(runtime_, "obj"));
EXPECT_EQ(*obj, SmallInt::fromWord(2));
}
TEST_F(BuiltinsModuleTest, GetAttrWithNonStringAttrRaisesTypeError) {
const char* src = R"(
class Foo: pass
getattr(Foo(), 1)
)";
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, src), LayoutId::kTypeError,
"attribute name must be string, not 'int'"));
}
TEST_F(BuiltinsModuleTest, GetAttrWithNonStringAttrAndDefaultRaisesTypeError) {
const char* src = R"(
class Foo: pass
getattr(Foo(), 1, 2)
)";
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, src), LayoutId::kTypeError,
"attribute name must be string, not 'int'"));
}
TEST_F(BuiltinsModuleTest,
GetAttrFromClassMissingAttrWithoutDefaultRaisesAttributeError) {
const char* src = R"(
class Foo:
bar = 1
getattr(Foo, 'foo')
)";
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, src),
LayoutId::kAttributeError,
"type object 'Foo' has no attribute 'foo'"));
}
TEST_F(BuiltinsModuleTest,
HashWithObjectWithNotCallableDunderHashRaisesTypeError) {
const char* src = R"(
class C:
__hash__ = None
hash(C())
)";
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, src), LayoutId::kTypeError,
"unhashable type: 'C'"));
}
TEST_F(BuiltinsModuleTest, HashWithObjectReturningNonIntRaisesTypeError) {
const char* src = R"(
class C:
def __hash__(self): return "10"
hash(C())
)";
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, src), LayoutId::kTypeError,
"__hash__ method should return an integer"));
}
TEST_F(BuiltinsModuleTest, HashWithObjectReturnsObjectDunderHashValue) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class C:
def __hash__(self): return 10
h = hash(C())
)")
.isError());
EXPECT_EQ(mainModuleAt(runtime_, "h"), SmallInt::fromWord(10));
}
TEST_F(BuiltinsModuleTest,
HashWithObjectWithModifiedDunderHashReturnsClassDunderHashValue) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class C:
def __hash__(self): return 10
def fake_hash(): return 0
c = C()
c.__hash__ = fake_hash
h = hash(c)
)")
.isError());
EXPECT_EQ(mainModuleAt(runtime_, "h"), SmallInt::fromWord(10));
}
TEST_F(BuiltinsModuleTest, BuiltInSetAttr) {
const char* src = R"(
class Foo:
bar = 1
a = setattr(Foo, 'foo', 2)
b = Foo.foo
)";
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, src).isError());
Object a(&scope, mainModuleAt(runtime_, "a"));
Object b(&scope, mainModuleAt(runtime_, "b"));
EXPECT_EQ(*a, NoneType::object());
EXPECT_EQ(*b, SmallInt::fromWord(2));
}
TEST_F(BuiltinsModuleTest, BuiltInSetAttrRaisesTypeError) {
const char* src = R"(
class Foo:
bar = 1
a = setattr(Foo, 2, 'foo')
)";
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, src), LayoutId::kTypeError,
"attribute name must be string, not 'int'"));
}
TEST_F(BuiltinsModuleTest, ModuleAttrReturnsBuiltinsName) {
// TODO(eelizondo): Parameterize test for all builtin types
const char* src = R"(
a = hasattr(object, '__module__')
b = getattr(object, '__module__')
c = hasattr(list, '__module__')
d = getattr(list, '__module__')
)";
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, src).isError());
Object a(&scope, mainModuleAt(runtime_, "a"));
EXPECT_EQ(*a, Bool::trueObj());
Object b(&scope, mainModuleAt(runtime_, "b"));
ASSERT_TRUE(b.isStr());
EXPECT_TRUE(Str::cast(*b).equalsCStr("builtins"));
Object c(&scope, mainModuleAt(runtime_, "c"));
EXPECT_EQ(*c, Bool::trueObj());
Object d(&scope, mainModuleAt(runtime_, "d"));
ASSERT_TRUE(d.isStr());
EXPECT_TRUE(Str::cast(*b).equalsCStr("builtins"));
}
TEST_F(BuiltinsModuleTest, QualnameAttrReturnsTypeName) {
// TODO(eelizondo): Parameterize test for all builtin types
const char* src = R"(
a = hasattr(object, '__qualname__')
b = getattr(object, '__qualname__')
c = hasattr(list, '__qualname__')
d = getattr(list, '__qualname__')
)";
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, src).isError());
Object a(&scope, mainModuleAt(runtime_, "a"));
EXPECT_EQ(*a, Bool::trueObj());
Object b(&scope, mainModuleAt(runtime_, "b"));
ASSERT_TRUE(b.isStr());
EXPECT_TRUE(Str::cast(*b).equalsCStr("object"));
Object c(&scope, mainModuleAt(runtime_, "c"));
EXPECT_EQ(*c, Bool::trueObj());
Object d(&scope, mainModuleAt(runtime_, "d"));
ASSERT_TRUE(d.isStr());
EXPECT_TRUE(Str::cast(*d).equalsCStr("list"));
}
TEST_F(BuiltinsModuleTest, BuiltinCompile) {
HandleScope scope(thread_);
ASSERT_FALSE(
runFromCStr(
runtime_,
R"(code = compile("a+b", "<string>", "eval", dont_inherit=True))")
.isError());
Str filename(&scope, runtime_->newStrFromCStr("<string>"));
Code code(&scope, mainModuleAt(runtime_, "code"));
ASSERT_TRUE(code.filename().isStr());
EXPECT_TRUE(Str::cast(code.filename()).equals(*filename));
ASSERT_TRUE(code.names().isTuple());
Tuple names(&scope, code.names());
ASSERT_EQ(names.length(), 2);
ASSERT_TRUE(names.contains(runtime_->newStrFromCStr("a")));
ASSERT_TRUE(names.contains(runtime_->newStrFromCStr("b")));
}
TEST_F(BuiltinsModuleTest, BuiltinCompileBytes) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
data = b'a+b'
code = compile(data, "<string>", "eval", dont_inherit=True)
)")
.isError());
Code code(&scope, mainModuleAt(runtime_, "code"));
Object filename(&scope, code.filename());
EXPECT_TRUE(isStrEqualsCStr(*filename, "<string>"));
ASSERT_TRUE(code.names().isTuple());
Tuple names(&scope, code.names());
ASSERT_EQ(names.length(), 2);
ASSERT_TRUE(names.contains(runtime_->newStrFromCStr("a")));
ASSERT_TRUE(names.contains(runtime_->newStrFromCStr("b")));
}
TEST_F(BuiltinsModuleTest, BuiltinCompileWithBytesSubclass) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
class Foo(bytes): pass
data = Foo(b"a+b")
code = compile(data, "<string>", "eval", dont_inherit=True)
)")
.isError());
Code code(&scope, mainModuleAt(runtime_, "code"));
Object filename(&scope, code.filename());
EXPECT_TRUE(isStrEqualsCStr(*filename, "<string>"));
ASSERT_TRUE(code.names().isTuple());
Tuple names(&scope, code.names());
ASSERT_EQ(names.length(), 2);
ASSERT_TRUE(names.contains(runtime_->newStrFromCStr("a")));
ASSERT_TRUE(names.contains(runtime_->newStrFromCStr("b")));
}
TEST_F(BuiltinsModuleTest, BuiltinCompileWithStrSubclass) {
HandleScope scope(thread_);
ASSERT_FALSE(runFromCStr(runtime_, R"(
class Foo(str): pass
data = Foo("a+b")
code = compile(data, "<string>", "eval", dont_inherit=True)
)")
.isError());
Code code(&scope, mainModuleAt(runtime_, "code"));
Object filename(&scope, code.filename());
EXPECT_TRUE(isStrEqualsCStr(*filename, "<string>"));
ASSERT_TRUE(code.names().isTuple());
Tuple names(&scope, code.names());
ASSERT_EQ(names.length(), 2);
ASSERT_TRUE(names.contains(runtime_->newStrFromCStr("a")));
ASSERT_TRUE(names.contains(runtime_->newStrFromCStr("b")));
}
TEST_F(BuiltinsModuleDeathTest, BuiltinCompileRaisesTypeErrorGivenTooFewArgs) {
EXPECT_TRUE(
raisedWithStr(runFromCStr(runtime_, "compile(1)"), LayoutId::kTypeError,
"'compile' takes min 3 positional arguments but 1 given"));
}
TEST_F(BuiltinsModuleDeathTest, BuiltinCompileRaisesTypeErrorGivenTooManyArgs) {
EXPECT_TRUE(
raisedWithStr(runFromCStr(runtime_, "compile(1, 2, 3, 4, 5, 6, 7, 8, 9)"),
LayoutId::kTypeError,
"'compile' takes max 6 positional arguments but 9 given"));
}
TEST_F(BuiltinsModuleTest, BuiltinCompileRaisesTypeErrorGivenBadMode) {
EXPECT_TRUE(raisedWithStr(
runFromCStr(runtime_,
"compile('hello', 'hello', 'hello', dont_inherit=True)"),
LayoutId::kValueError,
"compile() mode must be 'exec', 'eval' or 'single'"));
}
TEST_F(BuiltinsModuleTest, AllOnListWithOnlyTrueReturnsTrue) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
result = all([True, True])
)")
.isError());
HandleScope scope(thread_);
Bool result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_TRUE(result.value());
}
TEST_F(BuiltinsModuleTest, AllOnListWithFalseReturnsFalse) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
result = all([True, False, True])
)")
.isError());
HandleScope scope(thread_);
Bool result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_FALSE(result.value());
}
TEST_F(BuiltinsModuleTest, AnyOnListWithOnlyFalseReturnsFalse) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
result = any([False, False])
)")
.isError());
HandleScope scope(thread_);
Bool result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_FALSE(result.value());
}
TEST_F(BuiltinsModuleTest, AnyOnListWithTrueReturnsTrue) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
result = any([False, True, False])
)")
.isError());
HandleScope scope(thread_);
Bool result(&scope, mainModuleAt(runtime_, "result"));
EXPECT_TRUE(result.value());
}
TEST_F(BuiltinsModuleTest, FilterWithNonIterableArgumentRaisesTypeError) {
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "filter(None, 1)"),
LayoutId::kTypeError,
"'int' object is not iterable"));
}
TEST_F(BuiltinsModuleTest,
FilterWithNoneFuncAndIterableReturnsItemsOfTrueBoolValue) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
f = filter(None, [1,0,2,0])
r0 = f.__next__()
r1 = f.__next__()
exhausted = False
try:
f.__next__()
except StopIteration:
exhausted = True
)")
.isError());
HandleScope scope(thread_);
Object r0(&scope, mainModuleAt(runtime_, "r0"));
Object r1(&scope, mainModuleAt(runtime_, "r1"));
Object exhausted(&scope, mainModuleAt(runtime_, "exhausted"));
EXPECT_TRUE(isIntEqualsWord(*r0, 1));
EXPECT_TRUE(isIntEqualsWord(*r1, 2));
EXPECT_EQ(*exhausted, Bool::trueObj());
}
TEST_F(
BuiltinsModuleTest,
FilterWithFuncReturningBoolAndIterableReturnsItemsEvaluatedToTrueByFunc) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
def even(e): return e % 2 == 0
f = filter(even, [1,2,3,4])
r0 = f.__next__()
r1 = f.__next__()
exhausted = False
try:
f.__next__()
except StopIteration:
exhausted = True
)")
.isError());
HandleScope scope(thread_);
Object r0(&scope, mainModuleAt(runtime_, "r0"));
Object r1(&scope, mainModuleAt(runtime_, "r1"));
Object exhausted(&scope, mainModuleAt(runtime_, "exhausted"));
EXPECT_TRUE(isIntEqualsWord(*r0, 2));
EXPECT_TRUE(isIntEqualsWord(*r1, 4));
EXPECT_EQ(*exhausted, Bool::trueObj());
}
TEST_F(BuiltinsModuleTest, FormatWithNonStrFmtSpecRaisesTypeError) {
EXPECT_TRUE(
raised(runFromCStr(runtime_, "format('hi', 1)"), LayoutId::kTypeError));
}
TEST_F(BuiltinsModuleTest, FormatCallsDunderFormat) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class C:
def __format__(self, fmt_spec):
return "foobar"
result = format(C(), 'hi')
)")
.isError());
EXPECT_TRUE(isStrEqualsCStr(mainModuleAt(runtime_, "result"), "foobar"));
}
TEST_F(BuiltinsModuleTest, FormatRaisesWhenDunderFormatReturnsNonStr) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class C:
def __format__(self, fmt_spec):
return 1
)")
.isError());
EXPECT_TRUE(
raised(runFromCStr(runtime_, "format(C(), 'hi')"), LayoutId::kTypeError));
}
TEST_F(BuiltinsModuleTest, IterWithIterableCallsDunderIter) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
l = list(iter([1, 2, 3]))
)")
.isError());
HandleScope scope(thread_);
Object l(&scope, mainModuleAt(runtime_, "l"));
EXPECT_PYLIST_EQ(l, {1, 2, 3});
}
TEST_F(BuiltinsModuleTest, IterWithNonIterableRaisesTypeError) {
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
iter(None)
)"),
LayoutId::kTypeError,
"'NoneType' object is not iterable"));
}
TEST_F(BuiltinsModuleTest, IterWithRaisingDunderIterPropagatesException) {
EXPECT_TRUE(raised(runFromCStr(runtime_, R"(
class C:
def __iter__(self):
raise UserWarning()
iter(C())
)"),
LayoutId::kUserWarning));
}
TEST_F(BuiltinsModuleTest, NextWithoutIteratorRaisesTypeError) {
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
class C:
pass
next(C())
)"),
LayoutId::kTypeError,
"'C' object is not iterable"));
}
TEST_F(BuiltinsModuleTest, NextWithIteratorFetchesNextItem) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class C:
def __iter__(self):
self.a = 1
return self
def __next__(self):
x = self.a
self.a += 1
return x
itr = iter(C())
c = next(itr)
d = next(itr)
)")
.isError());
EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "c"), 1));
EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "d"), 2));
}
TEST_F(BuiltinsModuleTest, NextWithIteratorAndDefaultFetchesNextItem) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class C:
def __iter__(self):
self.a = 1
return self
def __next__(self):
x = self.a
self.a += 1
return x
itr = iter(C())
c = next(itr, 0)
d = next(itr, 0)
)")
.isError());
EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "c"), 1));
EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "d"), 2));
}
TEST_F(BuiltinsModuleTest, NextWithIteratorRaisesStopIteration) {
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
class C:
def __iter__(self):
return self
def __next__(self):
raise StopIteration('stopit')
itr = iter(C())
next(itr)
)"),
LayoutId::kStopIteration, "stopit"));
}
TEST_F(BuiltinsModuleTest, NextWithIteratorAndDefaultReturnsDefault) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class C:
def __iter__(self):
return self
def __next__(self):
raise StopIteration('stopit')
itr = iter(C())
c = next(itr, None)
)")
.isError());
EXPECT_TRUE(mainModuleAt(runtime_, "c").isNoneType());
}
TEST_F(BuiltinsModuleTest, SortedReturnsSortedList) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
unsorted = [5, 7, 8, 6]
result = sorted(unsorted)
)")
.isError());
HandleScope scope(thread_);
Object unsorted_obj(&scope, mainModuleAt(runtime_, "unsorted"));
ASSERT_TRUE(unsorted_obj.isList());
Object result_obj(&scope, mainModuleAt(runtime_, "result"));
ASSERT_TRUE(result_obj.isList());
EXPECT_NE(*unsorted_obj, *result_obj);
List unsorted(&scope, *unsorted_obj);
ASSERT_EQ(unsorted.numItems(), 4);
EXPECT_EQ(unsorted.at(0), SmallInt::fromWord(5));
EXPECT_EQ(unsorted.at(1), SmallInt::fromWord(7));
EXPECT_EQ(unsorted.at(2), SmallInt::fromWord(8));
EXPECT_EQ(unsorted.at(3), SmallInt::fromWord(6));
List result(&scope, *result_obj);
ASSERT_EQ(result.numItems(), 4);
EXPECT_EQ(result.at(0), SmallInt::fromWord(5));
EXPECT_EQ(result.at(1), SmallInt::fromWord(6));
EXPECT_EQ(result.at(2), SmallInt::fromWord(7));
EXPECT_EQ(result.at(3), SmallInt::fromWord(8));
}
TEST_F(BuiltinsModuleTest, SortedWithReverseReturnsReverseSortedList) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
unsorted = [1, 2, 3, 4]
result = sorted(unsorted, reverse=True)
)")
.isError());
HandleScope scope(thread_);
Object unsorted_obj(&scope, mainModuleAt(runtime_, "unsorted"));
ASSERT_TRUE(unsorted_obj.isList());
Object result_obj(&scope, mainModuleAt(runtime_, "result"));
ASSERT_TRUE(result_obj.isList());
EXPECT_NE(*unsorted_obj, *result_obj);
List unsorted(&scope, *unsorted_obj);
ASSERT_EQ(unsorted.numItems(), 4);
EXPECT_EQ(unsorted.at(0), SmallInt::fromWord(1));
EXPECT_EQ(unsorted.at(1), SmallInt::fromWord(2));
EXPECT_EQ(unsorted.at(2), SmallInt::fromWord(3));
EXPECT_EQ(unsorted.at(3), SmallInt::fromWord(4));
List result(&scope, *result_obj);
ASSERT_EQ(result.numItems(), 4);
EXPECT_EQ(result.at(0), SmallInt::fromWord(4));
EXPECT_EQ(result.at(1), SmallInt::fromWord(3));
EXPECT_EQ(result.at(2), SmallInt::fromWord(2));
EXPECT_EQ(result.at(3), SmallInt::fromWord(1));
}
TEST_F(BuiltinsModuleTest, MaxWithEmptyIterableRaisesValueError) {
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "max([])"),
LayoutId::kValueError,
"max() arg is an empty sequence"));
}
TEST_F(BuiltinsModuleTest, MaxWithMultipleArgsReturnsMaximum) {
ASSERT_FALSE(runFromCStr(runtime_, "result = max(1, 3, 5, 2, -1)").isError());
EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "result"), 5));
}
TEST_F(BuiltinsModuleTest, MaxWithNoArgsRaisesTypeError) {
EXPECT_TRUE(
raisedWithStr(runFromCStr(runtime_, "max()"), LayoutId::kTypeError,
"'max' takes min 1 positional arguments but 0 given"));
}
TEST_F(BuiltinsModuleTest, MaxWithIterableReturnsMaximum) {
ASSERT_FALSE(
runFromCStr(runtime_, "result = max((1, 3, 5, 2, -1))").isError());
EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "result"), 5));
}
TEST_F(BuiltinsModuleTest, MaxWithEmptyIterableAndDefaultReturnsDefault) {
ASSERT_FALSE(runFromCStr(runtime_, "result = max([], default=42)").isError());
EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "result"), 42));
}
TEST_F(BuiltinsModuleTest, MaxWithKeyOrdersByKeyFunction) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
result = max((1, 2, 3), key=lambda x: -x)
)")
.isError());
EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "result"), 1));
}
TEST_F(BuiltinsModuleTest, MaxWithEmptyIterableAndKeyAndDefaultReturnsDefault) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
result = max((), key=lambda x: x, default='empty')
)")
.isError());
EXPECT_TRUE(isStrEqualsCStr(mainModuleAt(runtime_, "result"), "empty"));
}
TEST_F(BuiltinsModuleTest, MaxWithMultipleArgsAndDefaultRaisesTypeError) {
EXPECT_TRUE(raisedWithStr(
runFromCStr(runtime_, "max(1, 2, default=0)"), LayoutId::kTypeError,
"Cannot specify a default for max() with multiple positional arguments"));
}
TEST_F(BuiltinsModuleTest, MaxWithKeyReturnsFirstOccuranceOfEqualValues) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class A:
pass
first = A()
second = A()
result = max(first, second, key=lambda x: 1) is first
)")
.isError());
EXPECT_EQ(mainModuleAt(runtime_, "result"), Bool::trueObj());
}
TEST_F(BuiltinsModuleTest, MaxWithoutKeyReturnsFirstOccuranceOfEqualValues) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class A():
def __gt__(self, _):
return False
first = A()
second = A()
result = max(first, second) is first
)")
.isError());
EXPECT_EQ(mainModuleAt(runtime_, "result"), Bool::trueObj());
}
TEST_F(BuiltinsModuleTest, MinWithEmptyIterableRaisesValueError) {
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "min([])"),
LayoutId::kValueError,
"min() arg is an empty sequence"));
}
TEST_F(BuiltinsModuleTest, MinWithMultipleArgsReturnsMinimum) {
ASSERT_FALSE(runFromCStr(runtime_, "result = min(4, 3, 1, 2, 5)").isError());
EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "result"), 1));
}
TEST_F(BuiltinsModuleTest, MinWithNoArgsRaisesTypeError) {
EXPECT_TRUE(
raisedWithStr(runFromCStr(runtime_, "min()"), LayoutId::kTypeError,
"'min' takes min 1 positional arguments but 0 given"));
}
TEST_F(BuiltinsModuleTest, MinWithIterableReturnsMinimum) {
ASSERT_FALSE(
runFromCStr(runtime_, "result = min((4, 3, 1, 2, 5))").isError());
EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "result"), 1));
}
TEST_F(BuiltinsModuleTest, MinWithEmptyIterableAndDefaultReturnsDefault) {
ASSERT_FALSE(runFromCStr(runtime_, "result = min([], default=42)").isError());
EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "result"), 42));
}
TEST_F(BuiltinsModuleTest, MinWithKeyOrdersByKeyFunction) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
result = min((1, 2, 3), key=lambda x: -x)
)")
.isError());
EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "result"), 3));
}
TEST_F(BuiltinsModuleTest, MinWithEmptyIterableAndKeyAndDefaultReturnsDefault) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
result = min((), key=lambda x: x, default='empty')
)")
.isError());
EXPECT_TRUE(isStrEqualsCStr(mainModuleAt(runtime_, "result"), "empty"));
}
TEST_F(BuiltinsModuleTest, MinWithMultipleArgsAndDefaultRaisesTypeError) {
EXPECT_TRUE(raisedWithStr(
runFromCStr(runtime_, "min(1, 2, default=0)"), LayoutId::kTypeError,
"Cannot specify a default for min() with multiple positional arguments"));
}
TEST_F(BuiltinsModuleTest, MinReturnsFirstOccuranceOfEqualValues) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class A:
pass
first = A()
second = A()
result = min(first, second, key=lambda x: 1) is first
)")
.isError());
EXPECT_EQ(mainModuleAt(runtime_, "result"), Bool::trueObj());
}
TEST_F(BuiltinsModuleTest, MinWithoutKeyReturnsFirstOccuranceOfEqualValues) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
class A():
def __lt__(self, _):
return False
first = A()
second = A()
result = min(first, second) is first
)")
.isError());
EXPECT_EQ(mainModuleAt(runtime_, "result"), Bool::trueObj());
}
TEST_F(BuiltinsModuleTest, MapWithNonIterableArgumentRaisesTypeError) {
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "map(1,1)"),
LayoutId::kTypeError,
"'int' object is not iterable"));
}
TEST_F(BuiltinsModuleTest,
MapWithIterableDunderNextReturnsFuncAppliedElementsSequentially) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
def inc(e):
return e + 1
m = map(inc, [1,2])
r0 = m.__next__()
r1 = m.__next__()
)")
.isError());
EXPECT_EQ(mainModuleAt(runtime_, "r0"), SmallInt::fromWord(2));
EXPECT_EQ(mainModuleAt(runtime_, "r1"), SmallInt::fromWord(3));
}
TEST_F(
BuiltinsModuleTest,
MapWithMultipleIterablesDunderNextReturnsFuncAppliedElementsSequentially) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
def inc(e0, e1):
return e0 + e1
m = map(inc, [1,2], [100,200])
r0 = m.__next__()
r1 = m.__next__()
)")
.isError());
EXPECT_EQ(mainModuleAt(runtime_, "r0"), SmallInt::fromWord(101));
EXPECT_EQ(mainModuleAt(runtime_, "r1"), SmallInt::fromWord(202));
}
TEST_F(BuiltinsModuleTest, MapDunderNextFinishesByRaisingStopIteration) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
def inc(e):
return e + 1
m = map(inc, [1,2])
m.__next__()
m.__next__()
exc_raised = False
try:
m.__next__()
except StopIteration:
exc_raised = True
)")
.isError());
EXPECT_EQ(mainModuleAt(runtime_, "exc_raised"), Bool::trueObj());
}
TEST_F(
BuiltinsModuleTest,
MapWithMultipleIterablesDunderNextFinishesByRaisingStopIterationOnShorterOne) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
def inc(e0, e1):
return e0, e1
m = map(inc, [1,2], [100])
m.__next__()
exc_raised = False
try:
m.__next__()
except StopIteration:
exc_raised = True
)")
.isError());
EXPECT_EQ(mainModuleAt(runtime_, "exc_raised"), Bool::trueObj());
}
TEST_F(BuiltinsModuleTest, EnumerateWithNonIterableRaisesTypeError) {
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "enumerate(1.0)"),
LayoutId::kTypeError,
"'float' object is not iterable"));
}
TEST_F(BuiltinsModuleTest, EnumerateReturnsEnumeratedTuples) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
e = enumerate([7, 3])
res1 = e.__next__()
res2 = e.__next__()
exhausted = False
try:
e.__next__()
except StopIteration:
exhausted = True
)")
.isError());
HandleScope scope(thread_);
Object res1(&scope, mainModuleAt(runtime_, "res1"));
ASSERT_TRUE(res1.isTuple());
EXPECT_EQ(Tuple::cast(*res1).at(0), SmallInt::fromWord(0));
EXPECT_EQ(Tuple::cast(*res1).at(1), SmallInt::fromWord(7));
Object res2(&scope, mainModuleAt(runtime_, "res2"));
ASSERT_TRUE(res2.isTuple());
EXPECT_EQ(Tuple::cast(*res2).at(0), SmallInt::fromWord(1));
EXPECT_EQ(Tuple::cast(*res2).at(1), SmallInt::fromWord(3));
EXPECT_EQ(mainModuleAt(runtime_, "exhausted"), Bool::trueObj());
}
TEST_F(BuiltinsModuleTest, AbsReturnsAbsoluteValue) {
ASSERT_FALSE(runFromCStr(runtime_, R"(
res1 = abs(10)
res2 = abs(-10)
)")
.isError());
HandleScope scope(thread_);
Object res1(&scope, mainModuleAt(runtime_, "res1"));
EXPECT_TRUE(isIntEqualsWord(*res1, 10));
Object res2(&scope, mainModuleAt(runtime_, "res2"));
EXPECT_TRUE(isIntEqualsWord(*res2, 10));
}
TEST_F(BuiltinsModuleTest, AbsWithoutDunderAbsRaisesTypeError) {
EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
class Foo(): pass
res1 = abs(Foo())
)"),
LayoutId::kTypeError,
"bad operand type for abs(): 'Foo'"));
}
} // namespace testing
} // namespace py