diff options
author | Martin Panter <vadmium+py@gmail.com> | 2017-01-29 10:16:28 +0000 |
---|---|---|
committer | Martin Panter <vadmium+py@gmail.com> | 2017-01-29 10:16:28 +0000 |
commit | 23352add84278fc0476b2d6599489fbb70c9f5bc (patch) | |
tree | 600bf5132e46d31b69efbd3bbc8a3d37159c0744 /Lib/test/test_functools.py | |
parent | 6d1d733828b49eb03d45da81c6b8c6b849fbc5df (diff) | |
parent | 0fb1e3c9fc84c62a91f1e5889dc8e0855cefa4ae (diff) | |
download | cpython-23352add84278fc0476b2d6599489fbb70c9f5bc.tar.gz |
Issues #29349: Merge Py 2 fix 3.6
Diffstat (limited to 'Lib/test/test_functools.py')
-rw-r--r-- | Lib/test/test_functools.py | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index 824549b803..63fe83e5db 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -9,6 +9,7 @@ import sys from test import support import time import unittest +import unittest.mock from weakref import proxy import contextlib try: @@ -1191,6 +1192,41 @@ class TestLRU: self.assertEqual(misses, 4) self.assertEqual(currsize, 2) + def test_lru_hash_only_once(self): + # To protect against weird reentrancy bugs and to improve + # efficiency when faced with slow __hash__ methods, the + # LRU cache guarantees that it will only call __hash__ + # only once per use as an argument to the cached function. + + @self.module.lru_cache(maxsize=1) + def f(x, y): + return x * 3 + y + + # Simulate the integer 5 + mock_int = unittest.mock.Mock() + mock_int.__mul__ = unittest.mock.Mock(return_value=15) + mock_int.__hash__ = unittest.mock.Mock(return_value=999) + + # Add to cache: One use as an argument gives one call + self.assertEqual(f(mock_int, 1), 16) + self.assertEqual(mock_int.__hash__.call_count, 1) + self.assertEqual(f.cache_info(), (0, 1, 1, 1)) + + # Cache hit: One use as an argument gives one additional call + self.assertEqual(f(mock_int, 1), 16) + self.assertEqual(mock_int.__hash__.call_count, 2) + self.assertEqual(f.cache_info(), (1, 1, 1, 1)) + + # Cache eviction: No use as an argument gives no additonal call + self.assertEqual(f(6, 2), 20) + self.assertEqual(mock_int.__hash__.call_count, 2) + self.assertEqual(f.cache_info(), (1, 2, 1, 1)) + + # Cache miss: One use as an argument gives one additional call + self.assertEqual(f(mock_int, 1), 16) + self.assertEqual(mock_int.__hash__.call_count, 3) + self.assertEqual(f.cache_info(), (1, 3, 1, 1)) + def test_lru_reentrancy_with_len(self): # Test to make sure the LRU cache code isn't thrown-off by # caching the built-in len() function. Since len() can be @@ -1203,6 +1239,15 @@ class TestLRU: finally: builtins.len = old_len + def test_lru_star_arg_handling(self): + # Test regression that arose in ea064ff3c10f + @functools.lru_cache() + def f(*args): + return args + + self.assertEqual(f(1, 2), (1, 2)) + self.assertEqual(f((1, 2)), ((1, 2),)) + def test_lru_type_error(self): # Regression test for issue #28653. # lru_cache was leaking when one of the arguments |