- commit
- 8309a9de6ebbbeb9d1a4be8862d6e9bc4ae74346
- parent
- 91eb438565b36d7049fa195cea606868cc2c82b3
- Author
- Tobias Bengfort <tobias.bengfort@gmx.net>
- Date
- 2014-10-04 08:23
Merge branch 'feature-tests'
Diffstat
| M | .gitignore | 1 | + |
| M | README.rst | 20 | ++++++++++++++++++++ |
| M | laneya/deferred.py | 56 | ++++++-------------------------------------------------- |
| M | setup.cfg | 12 | ++++++++++++ |
| A | tests/__init__.py | 0 | |
| A | tests/shared.py | 29 | +++++++++++++++++++++++++++++ |
| A | tests/test_deferred.py | 209 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | tox.ini | 23 | +++++++++++++++++++++++ |
8 files changed, 300 insertions, 50 deletions
diff --git a/.gitignore b/.gitignore
@@ -4,6 +4,7 @@ 4 4 *.pyc 5 5 .env 6 6 .tox -1 7 .cover 7 8 *.egg-info 8 9 *-orig 9 10 docs/build
diff --git a/README.rst b/README.rst
@@ -22,6 +22,7 @@ calling:: 22 22 laneya consists of two programs: A server called ``laneyad`` and a client 23 23 called ``laneya``. 24 24 -1 25 25 26 Build Documentation 26 27 ------------------- 27 28 @@ -37,4 +38,23 @@ To add a new module to the documentation, create a corresponding file in 37 38 ``docs/source/index.rst``. 38 39 39 40 -1 41 Run Tests -1 42 --------- -1 43 -1 44 You can automatically run all tests via tox:: -1 45 -1 46 pip install tox -1 47 tox -1 48 -1 49 This will setup virtual environments for multiple versions of python and run -1 50 all tests with each of these versions. -1 51 -1 52 Alternatively you can run the tests manually:: -1 53 -1 54 pip install flake8 nose coverage -1 55 flake8 -1 56 nosetests -1 57 xdg-open .cover/index.html -1 58 -1 59 40 60 .. _sphinx: http://sphinx-doc.org
diff --git a/laneya/deferred.py b/laneya/deferred.py
@@ -48,7 +48,7 @@ class Deferred(object): 48 48 for d, callback, errback in self.promise._children: 49 49 if status == RESOLVED: 50 50 callback(value).then(d.resolve, d.reject)51 -1 elif status == REJECTED:-1 51 else: # rejected 52 52 errback(value).then(d.resolve, d.reject) 53 53 else: 54 54 raise AlreadyDoneError @@ -93,6 +93,10 @@ class Promise(object): 93 93 self._children.append((d, _callback, _errback)) 94 94 return d.promise 95 95 -1 96 def _raise(self): -1 97 if self._status == REJECTED and isinstance(self._value, Exception): -1 98 raise self._value -1 99 96 100 97 101 def when(value=None): 98 102 """Wrap value in a promise if it is not already one.""" @@ -140,58 +144,10 @@ def all(*promises): 140 144 data['count'] -= 1 141 145 142 146 if data['count'] == 0:143 -1 try:144 -1 d.resolve(data['results'])145 -1 except AlreadyDoneError:146 -1 pass-1 147 d.resolve(data['results']) 147 148 return success 148 149 149 150 for i, promise in enumerate(promises): 150 151 promise.then(success_factory(i), d.reject) 151 152 152 153 return d.promise153 -1154 -1155 -1 if __name__ == '__main__':156 -1 def expect_factory(expected):157 -1 def expect(actual):158 -1 if actual == expected:159 -1 print(actual)160 -1 else:161 -1 print("%s != %s" % (actual, expected))162 -1 return expect163 -1164 -1 def fail(error):165 -1 raise Exception('fail')166 -1167 -1 d = Deferred()168 -1 d.resolve('huhu1')169 -1 d.promise.then(expect_factory('huhu1'), fail)170 -1171 -1 d = Deferred()172 -1 d.promise.then(expect_factory('huhu2'), fail)173 -1 d.resolve('huhu2')174 -1175 -1 d = Deferred()176 -1 d.reject('huhu3')177 -1 d.promise.then(fail, expect_factory('huhu3'))178 -1179 -1 d = Deferred()180 -1 d.promise.then(fail, expect_factory('huhu4'))181 -1 d.reject('huhu4')182 -1183 -1 d = Deferred()184 -1 d.reject('huhu5')185 -1 d.promise.then(fail).then(fail, expect_factory('huhu5'))186 -1187 -1 d = Deferred()188 -1 d.reject('huhu6')189 -1 d.promise.then(fail, when).then(expect_factory('huhu6'), fail)190 -1191 -1 when('huhu7').then(expect_factory('huhu7'), fail)192 -1193 -1 when(when('huhu8')).then(expect_factory('huhu8'), fail)194 -1195 -1 reject('huhu9').then(fail, expect_factory('huhu9'))196 -1197 -1 when(reject('huhu10')).then(fail, expect_factory('huhu10'))
diff --git a/setup.cfg b/setup.cfg
@@ -1,3 +1,15 @@ -1 1 [nosetests] -1 2 with-coverage=1 -1 3 cover-package=laneya -1 4 cover-inclusive=1 -1 5 cover-erase=1 -1 6 cover-branches=1 -1 7 cover-html=1 -1 8 cover-html-dir=.cover -1 9 -1 10 [flake8] -1 11 exclude=.env,.tox,.git,build,dist,docs -1 12 1 13 [build_sphinx] 2 14 source-dir = docs/source 3 15 build-dir = docs/build
diff --git a/tests/__init__.py b/tests/__init__.py
diff --git a/tests/shared.py b/tests/shared.py
@@ -0,0 +1,29 @@
-1 1 try:
-1 2 import unittest2 as unittest # flake8: noqa
-1 3 except ImportError:
-1 4 import unittest # flake8: noqa
-1 5
-1 6
-1 7 class SpyMixin:
-1 8 def __init__(self):
-1 9 self._spy_calls = {}
-1 10 self._key = 0
-1 11
-1 12 def create_spy(self):
-1 13 key = self._key
-1 14 self._key += 1
-1 15
-1 16 def spy(*args, **kwargs):
-1 17 if not key in self._spy_calls:
-1 18 self._spy_calls[key] = []
-1 19 self._spy_calls[key].append((args, kwargs))
-1 20
-1 21 spy.key = key
-1 22 return spy
-1 23
-1 24 def assertCalled(self, spy):
-1 25 self.assertIn(spy.key, self._spy_calls)
-1 26
-1 27 def assertCalledWith(self, spy, *args, **kwargs):
-1 28 self.assertCalled(spy)
-1 29 self.assertIn((args, kwargs), self._spy_calls[spy.key])
diff --git a/tests/test_deferred.py b/tests/test_deferred.py
@@ -0,0 +1,209 @@
-1 1 import shared
-1 2 from shared import unittest
-1 3
-1 4 from laneya import deferred as q
-1 5
-1 6
-1 7 class TestDeferred(unittest.TestCase, shared.SpyMixin):
-1 8 def __init__(self, *args, **kwargs):
-1 9 unittest.TestCase.__init__(self, *args, **kwargs)
-1 10 shared.SpyMixin.__init__(self)
-1 11
-1 12 def assertNeverCalled(self, *args, **kwargs):
-1 13 assert False
-1 14
-1 15 def test_deferred_resolve(self):
-1 16 spy = self.create_spy()
-1 17
-1 18 d = q.Deferred()
-1 19 d.resolve('foo')
-1 20 d.promise.then(spy, self.assertNeverCalled)._raise()
-1 21
-1 22 self.assertCalledWith(spy, 'foo')
-1 23
-1 24 def test_deferred_resolve_inverted(self):
-1 25 spy = self.create_spy()
-1 26
-1 27 d = q.Deferred()
-1 28 d.promise.then(spy, self.assertNeverCalled)._raise()
-1 29 d.resolve('foo')
-1 30
-1 31 self.assertCalledWith(spy, 'foo')
-1 32
-1 33 def test_deferred_resolve_done(self):
-1 34 spy = self.create_spy()
-1 35
-1 36 d = q.Deferred()
-1 37 d.promise.then(spy, self.assertNeverCalled)._raise()
-1 38 d.resolve('foo')
-1 39
-1 40 with self.assertRaises(q.AlreadyDoneError):
-1 41 d.resolve('bar')
-1 42
-1 43 with self.assertRaises(q.AlreadyDoneError):
-1 44 d.reject('bar')
-1 45
-1 46 self.assertCalledWith(spy, 'foo')
-1 47
-1 48 def test_deferred_reject(self):
-1 49 spy = self.create_spy()
-1 50
-1 51 d = q.Deferred()
-1 52 d.reject('foo')
-1 53 d.promise.then(self.assertNeverCalled, spy)._raise()
-1 54
-1 55 self.assertCalledWith(spy, 'foo')
-1 56
-1 57 def test_deferred_reject_inverted(self):
-1 58 spy = self.create_spy()
-1 59
-1 60 d = q.Deferred()
-1 61 d.promise.then(self.assertNeverCalled, spy)._raise()
-1 62 d.reject('foo')
-1 63
-1 64 self.assertCalledWith(spy, 'foo')
-1 65
-1 66 def test_deferred_reject_done(self):
-1 67 spy = self.create_spy()
-1 68
-1 69 d = q.Deferred()
-1 70 d.promise.then(self.assertNeverCalled, spy)._raise()
-1 71 d.reject('foo')
-1 72
-1 73 with self.assertRaises(q.AlreadyDoneError):
-1 74 d.resolve('bar')
-1 75
-1 76 with self.assertRaises(q.AlreadyDoneError):
-1 77 d.reject('bar')
-1 78
-1 79 self.assertCalledWith(spy, 'foo')
-1 80
-1 81 def test_success_propagation(self):
-1 82 spy = self.create_spy()
-1 83
-1 84 d = q.Deferred()
-1 85 d.resolve('foo')
-1 86 d.promise\
-1 87 .then(None, self.assertNeverCalled)\
-1 88 .then(spy, self.assertNeverCalled)\
-1 89 ._raise()
-1 90
-1 91 self.assertCalledWith(spy, 'foo')
-1 92
-1 93 def test_error_propagation(self):
-1 94 spy = self.create_spy()
-1 95
-1 96 d = q.Deferred()
-1 97 d.reject('foo')
-1 98 d.promise\
-1 99 .then(self.assertNeverCalled)\
-1 100 .then(self.assertNeverCalled, spy)\
-1 101 ._raise()
-1 102
-1 103 self.assertCalledWith(spy, 'foo')
-1 104
-1 105 def test_success_chaining(self):
-1 106 spy = self.create_spy()
-1 107 fn = lambda x: x + 'bar'
-1 108
-1 109 d = q.Deferred()
-1 110 d.resolve('foo')
-1 111 d.promise\
-1 112 .then(fn, self.assertNeverCalled)\
-1 113 .then(spy, self.assertNeverCalled)\
-1 114 ._raise()
-1 115
-1 116 self.assertCalledWith(spy, 'foobar')
-1 117
-1 118 def test_error_chaining(self):
-1 119 spy = self.create_spy()
-1 120 fn = lambda x: x + 'bar'
-1 121
-1 122 d = q.Deferred()
-1 123 d.reject('foo')
-1 124 d.promise\
-1 125 .then(self.assertNeverCalled, fn)\
-1 126 .then(spy, self.assertNeverCalled)\
-1 127 ._raise()
-1 128
-1 129 self.assertCalledWith(spy, 'foobar')
-1 130
-1 131 def test_when_with_value(self):
-1 132 spy = self.create_spy()
-1 133
-1 134 p = q.when('foo')
-1 135 p.then(spy, self.assertNeverCalled)._raise()
-1 136
-1 137 self.assertCalledWith(spy, 'foo')
-1 138
-1 139 def test_when_with_promise(self):
-1 140 p1 = q.Promise()
-1 141 p2 = q.when(p1)
-1 142
-1 143 self.assertEqual(p1, p2)
-1 144
-1 145 def test_reject(self):
-1 146 spy = self.create_spy()
-1 147
-1 148 p = q.reject('foo')
-1 149 p.then(self.assertNeverCalled, spy)._raise()
-1 150
-1 151 self.assertCalledWith(spy, 'foo')
-1 152
-1 153 def test_wrap_return(self):
-1 154 spy = self.create_spy()
-1 155 fn = lambda x: 'foo'
-1 156
-1 157 p = q.wrap(fn)('bar')
-1 158 p.then(spy, self.assertNeverCalled)._raise()
-1 159
-1 160 self.assertCalledWith(spy, 'foo')
-1 161
-1 162 def test_wrap_raise(self):
-1 163 spy = self.create_spy()
-1 164 err = Exception('foo')
-1 165
-1 166 def fn(x):
-1 167 raise err
-1 168
-1 169 p = q.wrap(fn)('bar')
-1 170 p.then(self.assertNeverCalled, spy)._raise()
-1 171
-1 172 self.assertCalledWith(spy, err)
-1 173
-1 174 def test_raise(self):
-1 175 with self.assertRaises(AssertionError):
-1 176 q.when('foo').then(self.assertNeverCalled)._raise()
-1 177
-1 178 def test_all_success(self):
-1 179 spy = self.create_spy()
-1 180
-1 181 d1 = q.Deferred()
-1 182 d2 = q.Deferred()
-1 183 d3 = q.Deferred()
-1 184
-1 185 d1.resolve('foo')
-1 186 d3.resolve('baz')
-1 187 d2.resolve('bar')
-1 188
-1 189 q.all(d1.promise, d2.promise, d3.promise)\
-1 190 .then(spy, self.assertNeverCalled)\
-1 191 ._raise()
-1 192
-1 193 self.assertCalledWith(spy, ['foo', 'bar', 'baz'])
-1 194
-1 195 def test_all_error(self):
-1 196 spy = self.create_spy()
-1 197
-1 198 d1 = q.Deferred()
-1 199 d2 = q.Deferred()
-1 200 d3 = q.Deferred()
-1 201
-1 202 d2.resolve('bar')
-1 203 d3.reject('baz')
-1 204
-1 205 q.all(d1.promise, d2.promise, d3.promise)\
-1 206 .then(self.assertNeverCalled, spy)\
-1 207 ._raise()
-1 208
-1 209 self.assertCalledWith(spy, 'baz')
diff --git a/tox.ini b/tox.ini
@@ -0,0 +1,23 @@ -1 1 # Tox (http://tox.testrun.org/) is a tool for running tests -1 2 # in multiple virtualenvs. This configuration file will run the -1 3 # test suite on all supported python versions. To use it, "pip install tox" -1 4 # and then run "tox" from this directory. -1 5 -1 6 [tox] -1 7 envlist = py26, py27 -1 8 -1 9 [testenv] -1 10 commands = -1 11 flake8 -1 12 nosetests laneya -1 13 deps = -1 14 flake8 -1 15 nose -1 16 coverage -1 17 -1 18 [testenv:py26] -1 19 deps = -1 20 flake8 -1 21 nose -1 22 coverage -1 23 unittest2