this repo has no description
1#!/usr/bin/env python3
2# Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
3import unittest
4import weakref
5from unittest.mock import MagicMock, Mock
6
7
8class WeakRefTests(unittest.TestCase):
9 def test_ref_dunder_callback_readonly(self):
10 class C:
11 pass
12
13 def callback(*args):
14 pass
15
16 obj = C()
17 ref = weakref.ref(obj)
18 with self.assertRaises(AttributeError):
19 ref.__callback__ = callback
20
21 def test_ref_dunder_callback_with_callback_returns_callback(self):
22 class C:
23 pass
24
25 def callback(*args):
26 pass
27
28 obj = C()
29 ref = weakref.ref(obj, callback)
30 self.assertIs(ref.__callback__, callback)
31
32 def test_ref_dunder_callback_without_callback_returns_none(self):
33 class C:
34 pass
35
36 obj = C()
37 ref = weakref.ref(obj)
38 self.assertIsNone(ref.__callback__)
39
40 def test_dunder_callback_with_subtype_returns_callback(self):
41 class SubRef(weakref.ref):
42 pass
43
44 class C:
45 pass
46
47 def callback(wr):
48 pass
49
50 obj = C()
51 ref = SubRef(obj, callback)
52 self.assertIs(ref.__callback__, callback)
53
54 def test_dunder_callback_with_subtype_passes_subtype(self):
55 class SubRef(weakref.ref):
56 pass
57
58 class C:
59 pass
60
61 def callback(wr):
62 wr.callback_arg = wr
63
64 ref = SubRef(C(), callback)
65 try:
66 from _builtins import _gc
67
68 _gc()
69 except ImportError:
70 pass
71
72 self.assertIs(ref.callback_arg, ref)
73
74 def test_ref_dunder_call_with_non_ref_raises_type_error(self):
75 self.assertRaisesRegex(
76 TypeError,
77 "'__call__' .* 'weakref' object.* a 'str'",
78 weakref.ref.__call__,
79 "not a weakref",
80 )
81
82 def test_dunder_eq_proxies_dunder_eq(self):
83 class C:
84 def __eq__(self, other):
85 return self is other
86
87 obj1 = C()
88 obj2 = C()
89 ref1 = weakref.ref(obj1)
90 ref2 = weakref.ref(obj2)
91 obj1.__eq__ = MagicMock()
92 self.assertIs(ref1.__eq__(ref2), False)
93 obj1.__eq__.called_once_with(obj1, obj2)
94 self.assertIs(ref1.__eq__(ref1), True)
95 obj1.__eq__.called_once_with(obj1, obj1)
96
97 def test_dunder_eq_with_non_ref_returns_not_implemented(self):
98 class C:
99 pass
100
101 obj = C()
102 ref = weakref.ref(obj)
103 not_a_ref = object()
104 self.assertIs(ref.__eq__(not_a_ref), NotImplemented)
105
106 def test_dunder_ge_always_returns_not_implemented(self):
107 class C:
108 pass
109
110 obj = C()
111 ref = weakref.ref(obj)
112 not_a_ref = object()
113 self.assertIs(ref.__ge__(ref), NotImplemented)
114 self.assertIs(ref.__ge__(not_a_ref), NotImplemented)
115
116 def test_dunder_gt_always_returns_not_implemented(self):
117 class C:
118 pass
119
120 obj = C()
121 ref = weakref.ref(obj)
122 not_a_ref = object()
123 self.assertIs(ref.__gt__(ref), NotImplemented)
124 self.assertIs(ref.__gt__(not_a_ref), NotImplemented)
125
126 def test_dunder_le_always_returns_not_implemented(self):
127 class C:
128 pass
129
130 obj = C()
131 ref = weakref.ref(obj)
132 not_a_ref = object()
133 self.assertIs(ref.__le__(ref), NotImplemented)
134 self.assertIs(ref.__le__(not_a_ref), NotImplemented)
135
136 def test_dunder_lt_always_returns_not_implemented(self):
137 class C:
138 pass
139
140 obj = C()
141 ref = weakref.ref(obj)
142 not_a_ref = object()
143 self.assertIs(ref.__lt__(ref), NotImplemented)
144 self.assertIs(ref.__lt__(not_a_ref), NotImplemented)
145
146 def test_dunder_ne_proxies_dunder_ne(self):
147 class C:
148 def __ne__(self, other):
149 return self is other
150
151 obj1 = C()
152 obj2 = C()
153 ref1 = weakref.ref(obj1)
154 ref2 = weakref.ref(obj2)
155 obj1.__ne__ = MagicMock()
156 self.assertIs(ref1.__ne__(ref2), False)
157 obj1.__ne__.called_once_with(obj1, obj2)
158 self.assertIs(ref1.__ne__(ref1), True)
159 obj1.__ne__.called_once_with(obj1, obj1)
160
161 def test_dunder_ne_with_non_ref_returns_not_implemented(self):
162 class C:
163 pass
164
165 obj = C()
166 ref = weakref.ref(obj)
167 not_a_ref = object()
168 self.assertIs(ref.__ne__(not_a_ref), NotImplemented)
169
170 def test_dunder_new_with_subtype_return_subtype_instance(self):
171 class SubRef(weakref.ref):
172 pass
173
174 class C:
175 def __eq__(self, other):
176 return "C.__eq__"
177
178 c = C()
179 sub_ref = SubRef(c)
180 self.assertIsInstance(sub_ref, SubRef)
181 self.assertIsInstance(sub_ref, weakref.ref)
182
183 ref = weakref.ref(c)
184 self.assertEqual(sub_ref.__eq__(ref), "C.__eq__")
185
186 sub_ref.new_attribute = 50
187 self.assertEqual(sub_ref.new_attribute, 50)
188
189 def test_dunder_new_with_non_type_raises_type_error(self):
190 with self.assertRaises(TypeError):
191 weakref.ref.__new__("not a type object")
192
193 def test_dunder_new_with_non_ref_subtype_raises_type_error(self):
194 with self.assertRaises(TypeError):
195 weakref.ref.__new__(list)
196
197 def test_dunder_new_with_int_raises_type_error(self):
198 with self.assertRaisesRegex(
199 TypeError, "cannot create weak reference to 'int' object"
200 ):
201 weakref.ref.__new__(weakref.ref, 42)
202
203 def test_hash_on_proxy_not_callable_object_raises_type_error(self):
204 with self.assertRaises(TypeError) as context:
205
206 class NotCallable:
207 def get_name(self):
208 return "NotCallableObject"
209
210 not_callable = NotCallable()
211 proxy = weakref.proxy(not_callable)
212 hash(proxy)
213 self.assertEqual(str(context.exception), "unhashable type: 'weakproxy'")
214
215 def test_proxy_not_callable_object_returns_proxy_type(self):
216 class NotCallable:
217 def get_name(self):
218 return "NotCallableObject"
219
220 not_callable = NotCallable()
221 proxy = weakref.proxy(not_callable)
222 self.assertEqual(type(proxy), weakref.ProxyType)
223
224 def test_proxy_calls_to_dunder_functions(self):
225 class C:
226 def __add__(self, another):
227 return 50 + another
228
229 c = C()
230 proxy = weakref.proxy(c)
231 self.assertEqual(proxy + 5, 55)
232
233 def test_proxy_with_hash_raises_type_error(self):
234 with self.assertRaises(TypeError) as context:
235
236 class C:
237 pass
238
239 c = C()
240 hash(weakref.proxy(c))
241 self.assertEqual(str(context.exception), "unhashable type: 'weakproxy'")
242
243 def test_proxy_dunder_hash_function_access_suceeds(self):
244 class C:
245 pass
246
247 c = C()
248 m = c.__hash__()
249 self.assertNotEqual(m, 0)
250
251 def test_proxy_field_access(self):
252 class C:
253 def __init__(self):
254 self.field = "field_value"
255
256 c = C()
257 proxy = weakref.proxy(c)
258 self.assertEqual(proxy.field, "field_value")
259
260 def test_proxy_instance_method_call(self):
261 class C:
262 def method(self):
263 return "method_return"
264
265 c = C()
266 proxy = weakref.proxy(c)
267 self.assertEqual(proxy.method(), "method_return")
268
269 def test_hash_on_proxy_callable_object_raises_type_error(self):
270 with self.assertRaises(TypeError) as context:
271
272 class Callable:
273 def __call__(self):
274 return "CallableObject"
275
276 callable = Callable()
277 proxy = weakref.proxy(callable)
278 hash(proxy)
279 self.assertEqual(str(context.exception), "unhashable type: 'weakcallableproxy'")
280
281 def test_proxy_callable_object_returns_callable_proxy_type(self):
282 class Callable:
283 def __call__(self):
284 return "CallableObject"
285
286 callable = Callable()
287 proxy = weakref.proxy(callable)
288 self.assertTrue(isinstance(proxy, weakref.CallableProxyType))
289
290 def test_proxy_callable_object_returns_callable_object(self):
291 class Callable:
292 def __call__(self):
293 return "CallableObject"
294
295 callable_obj = Callable()
296 proxy = weakref.proxy(callable_obj)
297 self.assertEqual(proxy(), "CallableObject")
298
299 def test_hash_returns_referent_hash(self):
300 class C:
301 def __hash__(self):
302 return 123456
303
304 i = C()
305 r = weakref.ref(i)
306 self.assertEqual(hash(r), hash(i))
307
308 def test_hash_picks_correct_dunder_hash(self):
309 class C:
310 def __hash__(self):
311 raise Exception("Should not pick this")
312
313 r = weakref.ref(C)
314 self.assertEqual(hash(r), hash(C))
315
316 def test_hash_caches_referent_hash(self):
317 m = Mock()
318 m.__hash__ = MagicMock(return_value=99)
319 r = weakref.ref(m)
320 self.assertEqual(hash(r), 99)
321 self.assertEqual(hash(r), 99)
322 m.__hash__.assert_called_once()
323
324 # TODO(T43270097): Add a test for callback.
325
326
327if __name__ == "__main__":
328 unittest.main()