mirror of https://github.com/python/cpython.git
Issue #29200: Add test for lru cache only calling __hash__ once
This commit is contained in:
parent
4f5c6a27d8
commit
d191ef25c1
|
@ -8,6 +8,7 @@
|
||||||
import sys
|
import sys
|
||||||
from test import support
|
from test import support
|
||||||
import unittest
|
import unittest
|
||||||
|
import unittest.mock
|
||||||
from weakref import proxy
|
from weakref import proxy
|
||||||
import contextlib
|
import contextlib
|
||||||
try:
|
try:
|
||||||
|
@ -1190,6 +1191,41 @@ def f(x):
|
||||||
self.assertEqual(misses, 4)
|
self.assertEqual(misses, 4)
|
||||||
self.assertEqual(currsize, 2)
|
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
|
||||||
|
assert f(mock_int, 1) == 16
|
||||||
|
assert mock_int.__hash__.call_count == 1
|
||||||
|
assert f.cache_info() == (0, 1, 1, 1)
|
||||||
|
|
||||||
|
# Cache hit: One use as an argument gives one additional call
|
||||||
|
assert f(mock_int, 1) == 16
|
||||||
|
assert mock_int.__hash__.call_count == 2
|
||||||
|
assert f.cache_info() == (1, 1, 1, 1)
|
||||||
|
|
||||||
|
# Cache eviction: No use as an argument gives no additonal call
|
||||||
|
assert f(6, 2) == 20
|
||||||
|
assert mock_int.__hash__.call_count == 2
|
||||||
|
assert f.cache_info() == (1, 2, 1, 1)
|
||||||
|
|
||||||
|
# Cache miss: One use as an argument gives one additional call
|
||||||
|
assert f(mock_int, 1) == 16
|
||||||
|
assert mock_int.__hash__.call_count == 3
|
||||||
|
assert f.cache_info() == (1, 3, 1, 1)
|
||||||
|
|
||||||
def test_lru_reentrancy_with_len(self):
|
def test_lru_reentrancy_with_len(self):
|
||||||
# Test to make sure the LRU cache code isn't thrown-off by
|
# Test to make sure the LRU cache code isn't thrown-off by
|
||||||
# caching the built-in len() function. Since len() can be
|
# caching the built-in len() function. Since len() can be
|
||||||
|
|
Loading…
Reference in New Issue