this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include "descriptor-builtins.h"
3
4#include "gtest/gtest.h"
5
6#include "builtins.h"
7#include "handles.h"
8#include "objects.h"
9#include "runtime.h"
10#include "test-utils.h"
11
12namespace py {
13namespace testing {
14
15using DescriptorBuiltinsTest = RuntimeFixture;
16
17TEST_F(DescriptorBuiltinsTest, Classmethod) {
18 ASSERT_FALSE(runFromCStr(runtime_, R"(
19class Foo():
20 a = 1
21 @classmethod
22 def bar(cls):
23 return cls.a
24instance_a = Foo().bar()
25Foo.a = 2
26class_a = Foo.bar()
27)")
28 .isError());
29 EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "instance_a"), 1));
30 EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "class_a"), 2));
31}
32
33TEST_F(DescriptorBuiltinsTest, StaticmethodObjAccess) {
34 ASSERT_FALSE(runFromCStr(runtime_, R"(
35class E:
36 @staticmethod
37 def f(x):
38 return x + 1
39
40result = E().f(5)
41)")
42 .isError());
43 EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "result"), 6));
44}
45
46TEST_F(DescriptorBuiltinsTest, StaticmethodClsAccess) {
47 ASSERT_FALSE(runFromCStr(runtime_, R"(
48class E():
49 @staticmethod
50 def f(x, y):
51 return x + y
52
53result = E.f(1,2)
54)")
55 .isError());
56 EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "result"), 3));
57}
58
59TEST_F(DescriptorBuiltinsTest,
60 PropertyCreateEmptyGetterSetterDeleterReturnsNone) {
61 HandleScope scope(thread_);
62 ASSERT_FALSE(runFromCStr(runtime_, "x = property()").isError());
63 Object x(&scope, mainModuleAt(runtime_, "x"));
64 ASSERT_TRUE(x.isProperty());
65 Property prop(&scope, *x);
66 ASSERT_TRUE(prop.getter().isNoneType());
67 ASSERT_TRUE(prop.setter().isNoneType());
68 ASSERT_TRUE(prop.deleter().isNoneType());
69}
70
71TEST_F(DescriptorBuiltinsTest, PropertyCreateWithGetterSetterReturnsArgs) {
72 HandleScope scope(thread_);
73 ASSERT_FALSE(runFromCStr(runtime_, R"(
74def get_foo():
75 pass
76def set_foo():
77 pass
78x = property(get_foo, set_foo)
79)")
80 .isError());
81 Object x(&scope, mainModuleAt(runtime_, "x"));
82 ASSERT_TRUE(x.isProperty());
83 Property prop(&scope, *x);
84 ASSERT_TRUE(prop.getter().isFunction());
85 ASSERT_TRUE(prop.setter().isFunction());
86 ASSERT_TRUE(prop.deleter().isNoneType());
87}
88
89TEST_F(DescriptorBuiltinsTest, PropertyModifyViaGetterReturnsGetter) {
90 HandleScope scope(thread_);
91 ASSERT_FALSE(runFromCStr(runtime_, R"(
92def get_foo():
93 pass
94def set_foo():
95 pass
96x = property(None, set_foo)
97y = x.getter(get_foo)
98)")
99 .isError());
100 Object x(&scope, mainModuleAt(runtime_, "x"));
101 ASSERT_TRUE(x.isProperty());
102 Property x_prop(&scope, *x);
103 ASSERT_TRUE(x_prop.getter().isNoneType());
104 ASSERT_TRUE(x_prop.setter().isFunction());
105 ASSERT_TRUE(x_prop.deleter().isNoneType());
106
107 Object y(&scope, mainModuleAt(runtime_, "y"));
108 ASSERT_TRUE(y.isProperty());
109 Property y_prop(&scope, *y);
110 ASSERT_TRUE(y_prop.getter().isFunction());
111 ASSERT_TRUE(y_prop.setter().isFunction());
112 ASSERT_TRUE(y_prop.deleter().isNoneType());
113}
114
115TEST_F(DescriptorBuiltinsTest, PropertyModifyViaSetterReturnsSetter) {
116 HandleScope scope(thread_);
117 ASSERT_FALSE(runFromCStr(runtime_, R"(
118def get_foo():
119 pass
120def set_foo():
121 pass
122x = property(get_foo)
123y = x.setter(set_foo)
124)")
125 .isError());
126 Object x(&scope, mainModuleAt(runtime_, "x"));
127 ASSERT_TRUE(x.isProperty());
128 Property x_prop(&scope, *x);
129 ASSERT_TRUE(x_prop.getter().isFunction());
130 ASSERT_TRUE(x_prop.setter().isNoneType());
131 ASSERT_TRUE(x_prop.deleter().isNoneType());
132
133 Object y(&scope, mainModuleAt(runtime_, "y"));
134 ASSERT_TRUE(y.isProperty());
135 Property y_prop(&scope, *y);
136 ASSERT_TRUE(y_prop.getter().isFunction());
137 ASSERT_TRUE(y_prop.setter().isFunction());
138 ASSERT_TRUE(y_prop.deleter().isNoneType());
139}
140
141TEST_F(DescriptorBuiltinsTest, PropertyAddedViaClassAccessibleViaInstance) {
142 ASSERT_FALSE(runFromCStr(runtime_, R"(
143class C:
144 def __init__(self, x):
145 self.__x = x
146
147 def getx(self):
148 return self.__x
149
150 x = property(getx)
151
152c1 = C(24)
153c2 = C(42)
154result0 = c1.x
155result1 = c2.x
156)")
157 .isError());
158 EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "result0"), 24));
159 EXPECT_TRUE(isIntEqualsWord(mainModuleAt(runtime_, "result1"), 42));
160}
161
162TEST_F(DescriptorBuiltinsTest, PropertyNoDeleterRaisesAttributeError) {
163 const char* src = R"(
164class C:
165 def __init__(self, x):
166 self.__x = x
167
168 def getx(self):
169 return self.__x
170
171 def setx(self, value):
172 self.__x = value
173
174 x = property(getx, setx)
175
176c1 = C(24)
177del c1.x
178)";
179
180 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, src),
181 LayoutId::kAttributeError,
182 "can't delete attribute"));
183}
184
185TEST_F(DescriptorBuiltinsTest, PropertyNoGetterRaisesAttributeErrorUnreadable) {
186 const char* src = R"(
187class C:
188 def __init__(self, x):
189 self.__x = x
190
191 def setx(self, value):
192 self.__x = value
193
194 x = property(None, setx)
195
196c1 = C(24)
197c1.x
198)";
199
200 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, src),
201 LayoutId::kAttributeError, "unreadable attribute"));
202}
203
204TEST_F(DescriptorBuiltinsTest,
205 PropertyNoSetterRaisesAttributeErrorCannotModify) {
206 const char* src = R"(
207class C:
208 def __init__(self, x):
209 self.__x = x
210
211 def getx(self):
212 return self.__x
213
214 x = property(getx)
215
216c1 = C(24)
217c1.x = 42
218)";
219
220 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, src),
221 LayoutId::kAttributeError, "can't set attribute"));
222}
223
224TEST_F(DescriptorBuiltinsTest, PropertyAddedViaClassAccessibleViaClass) {
225 HandleScope scope(thread_);
226 ASSERT_FALSE(runFromCStr(runtime_, R"(
227class C:
228 def __init__(self, x):
229 self.__x = x
230
231 def getx(self):
232 return self.__x
233
234 x = property(getx)
235
236x = C.x
237)")
238 .isError());
239
240 Object x(&scope, mainModuleAt(runtime_, "x"));
241 ASSERT_TRUE(x.isProperty());
242}
243
244TEST_F(DescriptorBuiltinsTest, PropertyAddedViaClassModifiedViaSetter) {
245 HandleScope scope(thread_);
246 ASSERT_FALSE(runFromCStr(runtime_, R"(
247class C:
248 def __init__(self, x):
249 self.__x = x
250
251 def getx(self):
252 return self.__x
253
254 def setx(self, value):
255 self.__x = value
256
257 x = property(getx, setx)
258
259c1 = C(24)
260x1 = c1.x
261c1.x = 42
262x2 = c1.x
263)")
264 .isError());
265
266 Object x1(&scope, mainModuleAt(runtime_, "x1"));
267 EXPECT_TRUE(isIntEqualsWord(*x1, 24));
268 Object x2(&scope, mainModuleAt(runtime_, "x2"));
269 EXPECT_TRUE(isIntEqualsWord(*x2, 42));
270}
271
272TEST_F(DescriptorBuiltinsTest, PropertyAddedViaDecoratorSanityCheck) {
273 HandleScope scope(thread_);
274 ASSERT_FALSE(runFromCStr(runtime_, R"(
275class C:
276 def __init__(self, x):
277 self.__x = x
278
279 @property
280 def x(self):
281 return self.__x
282
283 @x.setter
284 def x(self, value):
285 self.__x = value
286
287c1 = C(24)
288c1.x = 42
289x = c1.x
290)")
291 .isError());
292
293 Object x(&scope, mainModuleAt(runtime_, "x"));
294 EXPECT_TRUE(isIntEqualsWord(*x, 42));
295}
296
297TEST_F(DescriptorBuiltinsTest, PropertyWithCallableDeleterDeletesValue) {
298 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"(
299def deleter(obj):
300 del obj.y
301
302class Foo:
303 x = property(None, None, deleter, doc="documentation")
304 y = 123
305
306foo = Foo()
307del foo.x
308foo.y
309)"),
310 LayoutId::kAttributeError,
311 "'Foo' object has no attribute 'y'"));
312}
313
314TEST_F(DescriptorBuiltinsTest, PropertyWithCallableGetterReturnsValue) {
315 HandleScope scope(thread_);
316 ASSERT_FALSE(runFromCStr(runtime_, R"(
317class Getter:
318 def __call__(self, obj):
319 return 123
320
321class Foo:
322 x = property(Getter())
323
324result = Foo().x
325)")
326 .isError());
327 Object result(&scope, mainModuleAt(runtime_, "result"));
328 EXPECT_TRUE(isIntEqualsWord(*result, 123));
329}
330
331TEST_F(DescriptorBuiltinsTest, PropertyWithCallableSetterSetsValue) {
332 HandleScope scope(thread_);
333 ASSERT_FALSE(runFromCStr(runtime_, R"(
334class Setter:
335 def __call__(self, obj, value):
336 obj.y = value
337
338class Foo:
339 x = property(None, Setter(), None, doc="documentation")
340
341foo = Foo()
342foo.x = 123
343result = foo.y
344)")
345 .isError());
346 Object result(&scope, mainModuleAt(runtime_, "result"));
347 EXPECT_TRUE(isIntEqualsWord(*result, 123));
348}
349
350} // namespace testing
351} // namespace py