this repo has no description
at trunk 421 lines 12 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "super-builtins.h" 3 4#include "gtest/gtest.h" 5 6#include "builtins.h" 7#include "runtime.h" 8#include "str-builtins.h" 9#include "test-utils.h" 10 11namespace py { 12namespace testing { 13 14using SuperBuiltinsTest = RuntimeFixture; 15 16TEST_F(SuperBuiltinsTest, DunderInitWithMetaclassInstanceReturnsSuper) { 17 ASSERT_FALSE(runFromCStr(runtime_, R"( 18class M(type): 19 def get_super(self): 20 return super() 21class C(metaclass=M): pass 22s = C.get_super() 23)") 24 .isError()); 25 HandleScope scope(thread_); 26 Object s_obj(&scope, mainModuleAt(runtime_, "s")); 27 Object m(&scope, mainModuleAt(runtime_, "M")); 28 Object c(&scope, mainModuleAt(runtime_, "C")); 29 ASSERT_TRUE(s_obj.isSuper()); 30 Super s(&scope, *s_obj); 31 EXPECT_EQ(s.type(), m); 32 EXPECT_EQ(s.object(), c); 33 EXPECT_EQ(s.objectType(), m); 34} 35 36TEST_F(SuperBuiltinsTest, DunderInitWithNonDefaultMetaclassReturnsSuper) { 37 HandleScope scope(thread_); 38 ASSERT_FALSE(runFromCStr(runtime_, R"( 39class M(type): pass 40class C(metaclass=M): 41 def __new__(cls): 42 return super() 43class D(C): pass 44s = D() 45)") 46 .isError()); 47 Object c(&scope, mainModuleAt(runtime_, "C")); 48 Object d(&scope, mainModuleAt(runtime_, "D")); 49 Object s_obj(&scope, mainModuleAt(runtime_, "s")); 50 ASSERT_TRUE(s_obj.isSuper()); 51 Super s(&scope, *s_obj); 52 EXPECT_EQ(s.type(), c); 53 EXPECT_EQ(s.object(), d); 54 EXPECT_EQ(s.objectType(), d); 55} 56 57TEST_F(SuperBuiltinsTest, DunderCallWorksInTypesWithNonDefaultMetaclass) { 58 ASSERT_FALSE(runFromCStr(runtime_, R"( 59class M(type): pass 60class A(metaclass=M): 61 x = 2 62class B(A): 63 x = 4 64 def getsuper(self): 65 return super() 66result = B().getsuper().x 67)") 68 .isError()); 69 HandleScope scope(thread_); 70 Object result(&scope, mainModuleAt(runtime_, "result")); 71 EXPECT_TRUE(isIntEqualsWord(*result, 2)); 72} 73 74TEST_F(SuperBuiltinsTest, DunderGetattributeReturnsAttribute) { 75 HandleScope scope(thread_); 76 ASSERT_FALSE(runFromCStr(runtime_, R"( 77class A: 78 foo = 8 79class B(A): 80 foo = 10 81 def getsuper(self): 82 return super() 83s = B().getsuper() 84)") 85 .isError()); 86 Object s(&scope, mainModuleAt(runtime_, "s")); 87 Object name(&scope, runtime_->newStrFromCStr("foo")); 88 EXPECT_TRUE( 89 isIntEqualsWord(runBuiltin(METH(super, __getattribute__), s, name), 8)); 90} 91 92TEST_F(SuperBuiltinsTest, DunderGetattributeWithNonStringNameRaisesTypeError) { 93 HandleScope scope(thread_); 94 ASSERT_FALSE(runFromCStr(runtime_, R"( 95class A: pass 96class B(A): 97 def getsuper(self): 98 return super() 99s = B().getsuper() 100)") 101 .isError()); 102 Object s(&scope, mainModuleAt(runtime_, "s")); 103 Object name(&scope, runtime_->newInt(0)); 104 EXPECT_TRUE(raisedWithStr(runBuiltin(METH(super, __getattribute__), s, name), 105 LayoutId::kTypeError, 106 "attribute name must be string, not 'int'")); 107} 108 109TEST_F(SuperBuiltinsTest, 110 DunderGetattributeWithMissingAttributeRaisesAttributeError) { 111 HandleScope scope(thread_); 112 ASSERT_FALSE(runFromCStr(runtime_, R"( 113class A: pass 114class B(A): 115 def getsuper(self): 116 return super() 117s = B().getsuper() 118)") 119 .isError()); 120 Object s(&scope, mainModuleAt(runtime_, "s")); 121 Object name(&scope, runtime_->newStrFromCStr("xxx")); 122 EXPECT_TRUE(raisedWithStr(runBuiltin(METH(super, __getattribute__), s, name), 123 LayoutId::kAttributeError, 124 "super object has no attribute 'xxx'")); 125} 126 127TEST_F(SuperBuiltinsTest, SuperTest1) { 128 ASSERT_FALSE(runFromCStr(runtime_, R"( 129class A: 130 def f(self): 131 return 1 132 133class B(A): 134 def f(self): 135 return super(B, self).f() + 2 136 137class C(A): 138 def f(self): 139 return super(C, self).f() + 3 140 141class D(C, B): 142 def f(self): 143 return super(D, self).f() + 4 144 145class E(D): 146 pass 147 148class F(E): 149 f = E.f 150 151class G(A): 152 pass 153 154result0 = D().f() 155result1 = D.f(D()) 156result2 = E().f() 157result3 = E.f(E()) 158result4 = F().f() 159result5 = F.f(F()) 160)") 161 .isError()); 162 EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "result0"), 10)); 163 EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "result1"), 10)); 164 EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "result2"), 10)); 165 EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "result3"), 10)); 166 EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "result4"), 10)); 167 EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "result5"), 10)); 168} 169 170TEST_F(SuperBuiltinsTest, SuperTest2) { 171 ASSERT_FALSE(runFromCStr(runtime_, R"( 172class A: 173 @classmethod 174 def cm(cls): 175 return (cls, 1) 176 177class B(A): 178 @classmethod 179 def cm(cls): 180 return (cls, super(B, cls).cm(), 2) 181 182class C(A): 183 @classmethod 184 def cm(cls): 185 return (cls, super(C, cls).cm(), 3) 186 187class D(C, B): 188 def cm(cls): 189 return (cls, super(D, cls).cm(), 4) 190 191class E(D): 192 pass 193 194class G(A): 195 pass 196 197result0 = A.cm() == (A, 1) 198result1 = A().cm() == (A, 1) 199result2 = G.cm() == (G, 1) 200result3 = G().cm() == (G, 1) 201d = D() 202result4 = d.cm() == (d, (D, (D, (D, 1), 2), 3), 4) 203e = E() 204result5 = e.cm() == (e, (E, (E, (E, 1), 2), 3), 4) 205)") 206 .isError()); 207 EXPECT_EQ(mainModuleAt(runtime_, "result0"), Bool::trueObj()); 208 EXPECT_EQ(mainModuleAt(runtime_, "result1"), Bool::trueObj()); 209 EXPECT_EQ(mainModuleAt(runtime_, "result2"), Bool::trueObj()); 210 EXPECT_EQ(mainModuleAt(runtime_, "result3"), Bool::trueObj()); 211 EXPECT_EQ(mainModuleAt(runtime_, "result4"), Bool::trueObj()); 212 EXPECT_EQ(mainModuleAt(runtime_, "result5"), Bool::trueObj()); 213} 214 215TEST_F(SuperBuiltinsTest, SuperTestNoArgument) { 216 ASSERT_FALSE(runFromCStr(runtime_, R"( 217class A: 218 @classmethod 219 def cm(cls): 220 return (cls, 1) 221 222 def f(self): 223 return 1 224 225class B(A): 226 @classmethod 227 def cm(cls): 228 return (cls, super().cm(), 2) 229 230 def f(self): 231 return super().f() + 2 232 233class C(A): 234 @classmethod 235 def cm(cls): 236 return (cls, super().cm(), 3) 237 238 def f(self): 239 return super().f() + 3 240 241class D(C, B): 242 def cm(cls): 243 return (cls, super().cm(), 4) 244 245 def f(self): 246 return super().f() + 4 247 248a = B().f() 249b = D().f() 250c = B.cm() == (B, (B, 1), 2) 251d = D() 252e = d.cm() == (d, (D, (D, (D, 1), 2), 3), 4) 253)") 254 .isError()); 255 HandleScope scope(thread_); 256 Object a(&scope, mainModuleAt(runtime_, "a")); 257 Object b(&scope, mainModuleAt(runtime_, "b")); 258 Bool c(&scope, mainModuleAt(runtime_, "c")); 259 Bool e(&scope, mainModuleAt(runtime_, "e")); 260 EXPECT_TRUE(isIntEqualsWord(*a, 3)); 261 EXPECT_TRUE(isIntEqualsWord(*b, 10)); 262 EXPECT_EQ(*c, Bool::trueObj()); 263 EXPECT_EQ(*e, Bool::trueObj()); 264} 265 266TEST_F(SuperBuiltinsTest, 267 SuperCalledFromFunctionWithCellVarReturnsSuperInstance) { 268 ASSERT_FALSE(runFromCStr(runtime_, R"( 269class MetaA(type): 270 x = 42 271class MetaB(MetaA): 272 def __new__(metacls, cls, bases, classdict): 273 cellvar = None 274 def foobar(): 275 return cellvar 276 return super().__new__(metacls, cls, bases, classdict) 277class C(metaclass=MetaB): pass 278result = type(C()).x 279)") 280 .isError()); 281 HandleScope scope(thread_); 282 Object result(&scope, mainModuleAt(runtime_, "result")); 283 EXPECT_TRUE(isIntEqualsWord(*result, 42)); 284} 285 286TEST_F(SuperBuiltinsTest, NoArgumentRaisesRuntimeError) { 287 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "super()"), 288 LayoutId::kRuntimeError, "super(): no arguments")); 289 Thread::current()->clearPendingException(); 290 291 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"( 292def f(a): 293 super() 294f(1) 295)"), 296 LayoutId::kRuntimeError, 297 "super(): __class__ cell not found")); 298} 299 300TEST_F(SuperBuiltinsTest, SuperGetAttributeReturnsAttributeInSuperClass) { 301 HandleScope scope(thread_); 302 ASSERT_FALSE(runFromCStr(runtime_, R"( 303class A: 304 x = 13 305class B(A): 306 x = 42 307 def getsuper(self): 308 return super() 309s = B().getsuper() 310)") 311 .isError()); 312 Object s_obj(&scope, mainModuleAt(runtime_, "s")); 313 ASSERT_TRUE(s_obj.isSuper()); 314 Super s(&scope, *s_obj); 315 Object name(&scope, Runtime::internStrFromCStr(thread_, "x")); 316 EXPECT_TRUE(isIntEqualsWord(superGetAttribute(thread_, s, name), 13)); 317} 318 319TEST_F(SuperBuiltinsTest, SuperGetAttributeWithMissingAttributeReturnsError) { 320 HandleScope scope(thread_); 321 ASSERT_FALSE(runFromCStr(runtime_, R"( 322class A: pass 323class B(A): 324 x = 42 325 def getsuper(self): 326 return super() 327s = B().getsuper() 328)") 329 .isError()); 330 Object s_obj(&scope, mainModuleAt(runtime_, "s")); 331 ASSERT_TRUE(s_obj.isSuper()); 332 Super s(&scope, *s_obj); 333 Object name(&scope, Runtime::internStrFromCStr(thread_, "x")); 334 EXPECT_TRUE(superGetAttribute(thread_, s, name).isError()); 335 EXPECT_FALSE(thread_->hasPendingException()); 336} 337 338TEST_F(SuperBuiltinsTest, SuperGetAttributeCallsDunderGetOnDataDescriptor) { 339 HandleScope scope(thread_); 340 ASSERT_FALSE(runFromCStr(runtime_, R"( 341class D: 342 def __set__(self, instance, value): pass 343 def __get__(self, instance, owner): return (self, instance, owner) 344d = D() 345class A: 346 x = d 347class B(A): 348 x = 42 349 def getsuper(self): 350 return super() 351i = B() 352s = i.getsuper() 353)") 354 .isError()); 355 Object d(&scope, mainModuleAt(runtime_, "d")); 356 Object b(&scope, mainModuleAt(runtime_, "B")); 357 Object i(&scope, mainModuleAt(runtime_, "i")); 358 Object s_obj(&scope, mainModuleAt(runtime_, "s")); 359 ASSERT_TRUE(s_obj.isSuper()); 360 Super s(&scope, *s_obj); 361 Object name(&scope, Runtime::internStrFromCStr(thread_, "x")); 362 Object result_obj(&scope, superGetAttribute(thread_, s, name)); 363 ASSERT_TRUE(result_obj.isTuple()); 364 Tuple result(&scope, *result_obj); 365 ASSERT_EQ(result.length(), 3); 366 EXPECT_EQ(result.at(0), d); 367 EXPECT_EQ(result.at(1), i); 368 EXPECT_EQ(result.at(2), b); 369} 370 371TEST_F(SuperBuiltinsTest, SuperGetAttributeCallsDunderGetOnNonDataDescriptor) { 372 HandleScope scope(thread_); 373 ASSERT_FALSE(runFromCStr(runtime_, R"( 374class D: 375 def __get__(self, instance, owner): return (self, instance, owner) 376d = D() 377class A: 378 x = d 379class B(A): 380 x = 42 381 def getsuper(self): 382 return super() 383i = B() 384s = i.getsuper() 385)") 386 .isError()); 387 Object d(&scope, mainModuleAt(runtime_, "d")); 388 Object b(&scope, mainModuleAt(runtime_, "B")); 389 Object i(&scope, mainModuleAt(runtime_, "i")); 390 Object s_obj(&scope, mainModuleAt(runtime_, "s")); 391 ASSERT_TRUE(s_obj.isSuper()); 392 Super s(&scope, *s_obj); 393 Object name(&scope, Runtime::internStrFromCStr(thread_, "x")); 394 Object result_obj(&scope, superGetAttribute(thread_, s, name)); 395 ASSERT_TRUE(result_obj.isTuple()); 396 Tuple result(&scope, *result_obj); 397 ASSERT_EQ(result.length(), 3); 398 EXPECT_EQ(result.at(0), d); 399 EXPECT_EQ(result.at(1), i); 400 EXPECT_EQ(result.at(2), b); 401} 402 403TEST_F(SuperBuiltinsTest, SuperGetAttributeDunderClassReturnsSuper) { 404 HandleScope scope(thread_); 405 ASSERT_FALSE(runFromCStr(runtime_, R"( 406class C: 407 def foo(self): 408 return super() 409s = C().foo() 410)") 411 .isError()); 412 Object s_obj(&scope, mainModuleAt(runtime_, "s")); 413 ASSERT_TRUE(s_obj.isSuper()); 414 Super s(&scope, *s_obj); 415 Object name(&scope, Runtime::internStrFromCStr(thread_, "__class__")); 416 Type super_type(&scope, runtime_->typeAt(LayoutId::kSuper)); 417 EXPECT_EQ(superGetAttribute(thread_, s, name), super_type); 418} 419 420} // namespace testing 421} // namespace py