# -*- coding: utf-8 -*- import pytest from requests.structures import CaseInsensitiveDict, LookupDict, TimedCache, TimedCacheManaged class TestCaseInsensitiveDict: @pytest.fixture(autouse=True) def setup(self): """CaseInsensitiveDict instance with "Accept" header.""" self.case_insensitive_dict = CaseInsensitiveDict() self.case_insensitive_dict['Accept'] = 'application/json' def test_list(self): assert list(self.case_insensitive_dict) == ['Accept'] possible_keys = pytest.mark.parametrize('key', ('accept', 'ACCEPT', 'aCcEpT', 'Accept')) @possible_keys def test_getitem(self, key): assert self.case_insensitive_dict[key] == 'application/json' @possible_keys def test_delitem(self, key): del self.case_insensitive_dict[key] assert key not in self.case_insensitive_dict def test_lower_items(self): assert list(self.case_insensitive_dict.lower_items()) == [('accept', 'application/json')] def test_repr(self): assert repr(self.case_insensitive_dict) == "{'Accept': 'application/json'}" def test_copy(self): copy = self.case_insensitive_dict.copy() assert copy is not self.case_insensitive_dict assert copy == self.case_insensitive_dict @pytest.mark.parametrize( 'other, result', ( ({'AccePT': 'application/json'}, True), ({}, False), (None, False) ) ) def test_instance_equality(self, other, result): assert (self.case_insensitive_dict == other) is result class TestLookupDict: @pytest.fixture(autouse=True) def setup(self): """LookupDict instance with "bad_gateway" attribute.""" self.lookup_dict = LookupDict('test') self.lookup_dict.bad_gateway = 502 def test_repr(self): assert repr(self.lookup_dict) == "" get_item_parameters = pytest.mark.parametrize( 'key, value', ( ('bad_gateway', 502), ('not_a_key', None) ) ) @get_item_parameters def test_getitem(self, key, value): assert self.lookup_dict[key] == value @get_item_parameters def test_get(self, key, value): assert self.lookup_dict.get(key) == value class TestTimedCache(object): @pytest.fixture(autouse=True) def setup(self): self.any_value = 'some value' self.expiration_secs = 60 self.cache = TimedCache(expiration_secs=self.expiration_secs) yield self.cache.clear() def test_get(self): self.cache['a'] = self.any_value assert self.cache['a'] is self.any_value def test_repr(self): repr = str(self.cache) assert repr == '' def test_get_expired_item(self, mocker): self.cache = TimedCache(maxlen=1, expiration_secs=self.expiration_secs) mocker.patch('requests.structures.current_time', lambda: 0) self.cache['a'] = self.any_value mocker.patch('requests.structures.current_time', lambda: self.expiration_secs + 1) assert self.cache.get('a') is None def test_evict_first_entry_when_full(self, mocker): self.cache = TimedCache(maxlen=2, expiration_secs=2) mocker.patch('requests.structures.current_time', lambda: 0) self.cache['a'] = self.any_value mocker.patch('requests.structures.current_time', lambda: 1) self.cache['b'] = self.any_value mocker.patch('requests.structures.current_time', lambda: 3) self.cache['c'] = self.any_value assert len(self.cache) is 2 with pytest.raises(KeyError, message='Expected key not found'): self.cache['a'] assert self.cache['b'] is self.any_value assert self.cache['c'] is self.any_value def test_delete_item_removes_item(self): self.cache['a'] = self.any_value del self.cache['a'] with pytest.raises(KeyError, message='Expected key not found'): self.cache['a'] def test_iterating_hides_timestamps(self): self.cache['a'] = 1 self.cache['b'] = 2 expected = [('a', 1), ('b', 2)] actual = [(key, val) for key, val in self.cache] assert expected == actual class TestTimedCacheManagedDecorator(object): def test_caches_repeated_calls(self, mocker): mocker.patch('requests.structures.current_time', lambda: 0) nonlocals = {'value': 0} @TimedCacheManaged def some_method(x): nonlocals['value'] = nonlocals['value'] + x return nonlocals['value'] first_result = some_method(1) assert first_result is 1 second_result = some_method(1) assert second_result is 1 third_result = some_method(2) assert third_result is 3