88790a0c814e2692c5b494e8454d7e723fe0d654
[cached-property.git] / tests / test_coroutine_cached_property.py
1 # -*- coding: utf-8 -*-
2 """
3 The same tests as in :mod:`.test_async_cached_property`, but with the old
4 yield from instead of the new async/await syntax. Used to test Python 3.4
5 compatibility which has asyncio but doesn't have async/await yet.
6 """
7
8 import unittest
9 import asyncio
10 from freezegun import freeze_time
11
12 import cached_property
13
14
15 def unittest_run_loop(f):
16 def wrapper(*args, **kwargs):
17 coro = asyncio.coroutine(f)
18 future = coro(*args, **kwargs)
19 loop = asyncio.get_event_loop()
20 loop.run_until_complete(future)
21
22 return wrapper
23
24
25 def CheckFactory(cached_property_decorator):
26 """
27 Create dynamically a Check class whose add_cached method is decorated by
28 the cached_property_decorator.
29 """
30
31 class Check(object):
32 def __init__(self):
33 self.control_total = 0
34 self.cached_total = 0
35
36 @asyncio.coroutine
37 def add_control(self):
38 self.control_total += 1
39 return self.control_total
40
41 @cached_property_decorator
42 @asyncio.coroutine
43 def add_cached(self):
44 self.cached_total += 1
45 return self.cached_total
46
47 return Check
48
49
50 class TestCachedProperty(unittest.TestCase):
51 """Tests for cached_property"""
52
53 cached_property_factory = cached_property.cached_property
54
55 @asyncio.coroutine
56 def assert_control(self, check, expected):
57 """
58 Assert that both `add_control` and 'control_total` equal `expected`
59 """
60 value = yield from check.add_control()
61 self.assertEqual(value, expected)
62 self.assertEqual(check.control_total, expected)
63
64 @asyncio.coroutine
65 def assert_cached(self, check, expected):
66 """
67 Assert that both `add_cached` and 'cached_total` equal `expected`
68 """
69 print("assert_cached", check.add_cached)
70 value = yield from check.add_cached
71 self.assertEqual(value, expected)
72 self.assertEqual(check.cached_total, expected)
73
74 @unittest_run_loop
75 @asyncio.coroutine
76 def test_cached_property(self):
77 Check = CheckFactory(self.cached_property_factory)
78 check = Check()
79
80 # The control shows that we can continue to add 1
81 yield from self.assert_control(check, 1)
82 yield from self.assert_control(check, 2)
83
84 # The cached version demonstrates how nothing is added after the first
85 yield from self.assert_cached(check, 1)
86 yield from self.assert_cached(check, 1)
87
88 # The cache does not expire
89 with freeze_time("9999-01-01"):
90 yield from self.assert_cached(check, 1)
91
92 # Typically descriptors return themselves if accessed though the class
93 # rather than through an instance.
94 self.assertTrue(isinstance(Check.add_cached, self.cached_property_factory))
95
96 @unittest_run_loop
97 @asyncio.coroutine
98 def test_reset_cached_property(self):
99 Check = CheckFactory(self.cached_property_factory)
100 check = Check()
101
102 # Run standard cache assertion
103 yield from self.assert_cached(check, 1)
104 yield from self.assert_cached(check, 1)
105
106 # Clear the cache
107 del check.add_cached
108
109 # Value is cached again after the next access
110 yield from self.assert_cached(check, 2)
111 yield from self.assert_cached(check, 2)
112
113 @unittest_run_loop
114 @asyncio.coroutine
115 def test_none_cached_property(self):
116 class Check(object):
117 def __init__(self):
118 self.cached_total = None
119
120 @self.cached_property_factory
121 @asyncio.coroutine
122 def add_cached(self):
123 return self.cached_total
124
125 yield from self.assert_cached(Check(), None)