this repo has no description
at trunk 328 lines 9.3 kB view raw
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()