|
1 | 1 | from __future__ import absolute_import
|
2 | 2 |
|
| 3 | +from inspect import getargspec |
3 | 4 | from unittest import TestCase
|
4 | 5 |
|
5 | 6 | from requests.compat import json as _json
|
6 | 7 |
|
7 |
| -from plotly.utils import PlotlyJSONEncoder, get_by_path, node_generator |
| 8 | +from plotly.utils import (PlotlyJSONEncoder, get_by_path, memoize, |
| 9 | + node_generator) |
8 | 10 |
|
9 | 11 |
|
10 | 12 | class TestJSONEncoder(TestCase):
|
@@ -50,3 +52,98 @@ def test_node_generator(self):
|
50 | 52 | ]
|
51 | 53 | for i, item in enumerate(node_generator(node0)):
|
52 | 54 | self.assertEqual(item, expected_node_path_tuples[i])
|
| 55 | + |
| 56 | + |
| 57 | +class TestMemoizeDecorator(TestCase): |
| 58 | + |
| 59 | + # In Python 2.x, globals should be module-scoped. By defining and |
| 60 | + # instantiating a class, we *access* the global first before attempting |
| 61 | + # to update a value. I.e., you *cannot* simply mutate the global value |
| 62 | + # on it's own. |
| 63 | + class Namespace(object): |
| 64 | + pass |
| 65 | + |
| 66 | + def test_memoize(self): |
| 67 | + name_space = self.Namespace() |
| 68 | + name_space.call_count = 0 |
| 69 | + |
| 70 | + @memoize() |
| 71 | + def add(a, b): |
| 72 | + name_space.call_count += 1 |
| 73 | + return a + b |
| 74 | + |
| 75 | + tests = [[(1, 1), 2], [(2, 3), 5], [(3, -3), 0]] |
| 76 | + |
| 77 | + self.assertEqual(name_space.call_count, 0) |
| 78 | + for i, (inputs, result) in enumerate(tests, 1): |
| 79 | + for _ in range(10): |
| 80 | + self.assertEqual(add(*inputs), result) |
| 81 | + self.assertEqual(name_space.call_count, i) |
| 82 | + |
| 83 | + def test_memoize_maxsize(self): |
| 84 | + name_space = self.Namespace() |
| 85 | + name_space.call_count = 0 |
| 86 | + |
| 87 | + maxsize = 10 |
| 88 | + |
| 89 | + @memoize(maxsize=maxsize) |
| 90 | + def identity(a): |
| 91 | + name_space.call_count += 1 |
| 92 | + return a |
| 93 | + |
| 94 | + # Function hasn't been called yet, we should get *up to* maxsize cache. |
| 95 | + for i in range(maxsize): |
| 96 | + self.assertEqual(identity(i), i) |
| 97 | + self.assertEqual(name_space.call_count, i + 1) |
| 98 | + |
| 99 | + # Nothing should have been discarded yet. no additional calls. |
| 100 | + for i in range(maxsize): |
| 101 | + self.assertEqual(identity(i), i) |
| 102 | + self.assertEqual(name_space.call_count, maxsize) |
| 103 | + |
| 104 | + # Make a new call... |
| 105 | + self.assertEqual(identity(maxsize), maxsize) |
| 106 | + self.assertEqual(name_space.call_count, maxsize + 1) |
| 107 | + |
| 108 | + # All but the first call should be remembered. |
| 109 | + for i in range(1, maxsize + 1): |
| 110 | + self.assertEqual(identity(i), i) |
| 111 | + self.assertEqual(name_space.call_count, maxsize + 1) |
| 112 | + |
| 113 | + # The *initial* call should now be forgotten for each new call. |
| 114 | + for i in range(maxsize): |
| 115 | + self.assertEqual(identity(i), i) |
| 116 | + self.assertEqual(name_space.call_count, maxsize + 1 + i + 1) |
| 117 | + |
| 118 | + def test_memoize_maxsize_none(self): |
| 119 | + name_space = self.Namespace() |
| 120 | + name_space.call_count = 0 |
| 121 | + |
| 122 | + @memoize(maxsize=None) |
| 123 | + def identity(a): |
| 124 | + name_space.call_count += 1 |
| 125 | + return a |
| 126 | + |
| 127 | + # Function hasn't been called yet, we should get *up to* maxsize cache. |
| 128 | + for i in range(400): |
| 129 | + self.assertEqual(identity(i), i) |
| 130 | + self.assertEqual(name_space.call_count, i + 1) |
| 131 | + |
| 132 | + # Nothing should have been discarded. no additional calls. |
| 133 | + for i in range(400): |
| 134 | + self.assertEqual(identity(i), i) |
| 135 | + self.assertEqual(name_space.call_count, 400) |
| 136 | + |
| 137 | + def test_memoize_function_info(self): |
| 138 | + # We use the decorator module to assure that function info is not |
| 139 | + # overwritten by the decorator. |
| 140 | + |
| 141 | + @memoize() |
| 142 | + def foo(a, b, c='see?'): |
| 143 | + """Foo is foo.""" |
| 144 | + pass |
| 145 | + |
| 146 | + self.assertEqual(foo.__doc__, 'Foo is foo.') |
| 147 | + self.assertEqual(foo.__name__, 'foo') |
| 148 | + self.assertEqual(getargspec(foo).args, ['a', 'b', 'c']) |
| 149 | + self.assertEqual(getargspec(foo).defaults, ('see?',)) |
0 commit comments