this repo has no description
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