Merge lp:~gandelman-a/ubuntu/precise/python-dingus/lp879051 into lp:ubuntu/precise/python-dingus
- Precise (12.04)
- lp879051
- Merge into precise
Proposed by
Adam Gandelman
Status: | Merged |
---|---|
Merged at revision: | 4 |
Proposed branch: | lp:~gandelman-a/ubuntu/precise/python-dingus/lp879051 |
Merge into: | lp:ubuntu/precise/python-dingus |
Diff against target: |
1889 lines (+679/-863) 33 files modified
.pc/.version (+1/-0) .pc/applied-patches (+1/-0) .pc/debian-changes-0.3.2-1/dingus.egg-info/SOURCES.txt (+7/-0) .pc/debian-changes-0.3.2-1/setup.py (+22/-0) PKG-INFO (+119/-5) README (+0/-76) README.txt (+114/-0) debian/changelog (+14/-0) debian/control (+1/-1) debian/docs (+1/-2) debian/patches/debian-changes-0.3.2-1 (+64/-0) debian/patches/series (+1/-0) debian/source/format (+1/-0) dingus.egg-info/PKG-INFO (+119/-5) dingus.egg-info/SOURCES.txt (+2/-17) dingus.py (+192/-57) examples/__init__.py (+0/-1) examples/googler/__init__.py (+0/-1) examples/googler/googler.py (+0/-21) examples/googler/runtests.py (+0/-12) examples/googler/test_googler.py (+0/-56) examples/urllib2/__init__.py (+0/-1) examples/urllib2/runtests.py (+0/-12) examples/urllib2/test_urllib2.py (+0/-67) patches/series (+1/-0) patches/setup_cleanup (+12/-0) setup.py (+7/-5) tests/runtests.py (+0/-14) tests/test_call.py (+0/-22) tests/test_call_list.py (+0/-113) tests/test_dingus.py (+0/-290) tests/test_dingus_test_case.py (+0/-65) tests/test_exception_raiser.py (+0/-20) |
To merge this branch: | bzr merge lp:~gandelman-a/ubuntu/precise/python-dingus/lp879051 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Daniel Holbach (community) | Approve | ||
Ubuntu branches | Pending | ||
Review via email: mp+79992@code.launchpad.net |
Commit message
Description of the change
python-dingus (0.3.2-1ubuntu1) precise; urgency=low
* Merge from debian testing (LP: #879051). Remaining changes:
- dh_python2 transition
-- Adam Gandelman <email address hidden> Thu, 20 Oct 2011 12:17:50 -0700
python-dingus (0.3.2-1) unstable; urgency=low
* New upstream release
* Update Standards version, no changes needed.
-- David Watson <email address hidden> Sun, 07 Aug 2011 09:16:45 +0100
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added directory '.pc' |
2 | === added file '.pc/.version' |
3 | --- .pc/.version 1970-01-01 00:00:00 +0000 |
4 | +++ .pc/.version 2011-10-20 19:36:43 +0000 |
5 | @@ -0,0 +1,1 @@ |
6 | +2 |
7 | |
8 | === added file '.pc/applied-patches' |
9 | --- .pc/applied-patches 1970-01-01 00:00:00 +0000 |
10 | +++ .pc/applied-patches 2011-10-20 19:36:43 +0000 |
11 | @@ -0,0 +1,1 @@ |
12 | +debian-changes-0.3.2-1 |
13 | |
14 | === added directory '.pc/debian-changes-0.3.2-1' |
15 | === added directory '.pc/debian-changes-0.3.2-1/dingus.egg-info' |
16 | === added file '.pc/debian-changes-0.3.2-1/dingus.egg-info/SOURCES.txt' |
17 | --- .pc/debian-changes-0.3.2-1/dingus.egg-info/SOURCES.txt 1970-01-01 00:00:00 +0000 |
18 | +++ .pc/debian-changes-0.3.2-1/dingus.egg-info/SOURCES.txt 2011-10-20 19:36:43 +0000 |
19 | @@ -0,0 +1,7 @@ |
20 | +README.txt |
21 | +dingus.py |
22 | +setup.py |
23 | +dingus.egg-info/PKG-INFO |
24 | +dingus.egg-info/SOURCES.txt |
25 | +dingus.egg-info/dependency_links.txt |
26 | +dingus.egg-info/top_level.txt |
27 | \ No newline at end of file |
28 | |
29 | === added directory '.pc/debian-changes-0.3.2-1/patches' |
30 | === added file '.pc/debian-changes-0.3.2-1/patches/series' |
31 | === added file '.pc/debian-changes-0.3.2-1/patches/setup_cleanup' |
32 | === added file '.pc/debian-changes-0.3.2-1/setup.py' |
33 | --- .pc/debian-changes-0.3.2-1/setup.py 1970-01-01 00:00:00 +0000 |
34 | +++ .pc/debian-changes-0.3.2-1/setup.py 2011-10-20 19:36:43 +0000 |
35 | @@ -0,0 +1,22 @@ |
36 | +from setuptools import setup |
37 | + |
38 | +setup(name='dingus', |
39 | + version='0.3.2', |
40 | + description='A record-then-assert mocking library', |
41 | + long_description=file('README.txt').read(), |
42 | + author='Gary Bernhardt', |
43 | + author_email='gary.bernhardt@gmail.com', |
44 | + py_modules=['dingus'], |
45 | + data_files=[('', ['README.txt'])], |
46 | + license='MIT', |
47 | + url='https://github.com/garybernhardt/dingus', |
48 | + keywords='testing test mocking mock double stub fake record assert', |
49 | + classifiers=["Development Status :: 4 - Beta", |
50 | + "Intended Audience :: Developers", |
51 | + "License :: OSI Approved :: MIT License", |
52 | + "Operating System :: OS Independent", |
53 | + "Programming Language :: Python", |
54 | + "Topic :: Software Development :: Testing", |
55 | + ], |
56 | + ) |
57 | + |
58 | |
59 | === modified file 'PKG-INFO' |
60 | --- PKG-INFO 2009-10-22 11:00:55 +0000 |
61 | +++ PKG-INFO 2011-10-20 19:36:43 +0000 |
62 | @@ -1,15 +1,129 @@ |
63 | Metadata-Version: 1.0 |
64 | Name: dingus |
65 | -Version: 0.1 |
66 | +Version: 0.3.2 |
67 | Summary: A record-then-assert mocking library |
68 | -Home-page: http://bitbucket.org/garybernhardt/dingus |
69 | +Home-page: https://github.com/garybernhardt/dingus |
70 | Author: Gary Bernhardt |
71 | Author-email: gary.bernhardt@gmail.com |
72 | License: MIT |
73 | -Description: UNKNOWN |
74 | -Keywords: testing test mocking mock double stub fake |
75 | +Description: ======== |
76 | + DINGUSES |
77 | + ======== |
78 | + |
79 | + A dingus is sort of like a mock object. The main difference is that you don't |
80 | + set up expectations ahead of time. You just run your code, using a dingus in |
81 | + place of another object or class, and it will record what happens to it. Then, |
82 | + once your code has been exercised, you can make assertions about what it did |
83 | + to the dingus. |
84 | + |
85 | + A new dingus is created from the Dingus class. You can give dinguses names, |
86 | + which helps with debugging your tests, especially when there are multiple |
87 | + dinguses in play. |
88 | + |
89 | + >>> from dingus import Dingus |
90 | + >>> d = Dingus('root') |
91 | + >>> d |
92 | + <Dingus root> |
93 | + |
94 | + Accessing any attribute of a dingus will return a new dingus. |
95 | + |
96 | + >>> d.something |
97 | + <Dingus root.something> |
98 | + |
99 | + There are a few exceptions for special dingus methods. We'll see some in a |
100 | + bit. |
101 | + |
102 | + A dingus can also be called like a function or method. It doesn't care how |
103 | + many arguments you give it or what those arguments are. Calls to a dingus will |
104 | + always return the same object, regardless of the arguments. |
105 | + |
106 | + >>> d() |
107 | + <Dingus root()> |
108 | + >>> d('argument') |
109 | + <Dingus root()> |
110 | + >>> d(55) |
111 | + <Dingus root()> |
112 | + |
113 | + ======================== |
114 | + RECORDING AND ASSERTIONS |
115 | + ======================== |
116 | + |
117 | + At any time we can get a list of calls that have been made to a dingus. Each |
118 | + entry in the call list contains: |
119 | + |
120 | + * the name of the method called (or "()" if the dingus itself was called) |
121 | + * The arguments, or () if none |
122 | + * The keyword argumnets, or {} if none |
123 | + * The value that was returned to the caller |
124 | + |
125 | + Here is a list of the calls we've made to d so far: |
126 | + |
127 | + >>> from pprint import pprint |
128 | + >>> pprint(d.calls) |
129 | + [('()', (), {}, <Dingus root()>), |
130 | + ('()', ('argument',), {}, <Dingus root()>), |
131 | + ('()', (55,), {}, <Dingus root()>)] |
132 | + |
133 | + You can filter calls by name, arguments, and keyword arguments: |
134 | + |
135 | + >>> pprint(d.calls('()', 55)) |
136 | + [('()', (55,), {}, <Dingus root()>)] |
137 | + |
138 | + If you don't care about a particular argument's value, you can use the value |
139 | + DontCare when filtering: |
140 | + |
141 | + >>> from dingus import DontCare |
142 | + >>> pprint(d.calls('()', DontCare)) |
143 | + [('()', ('argument',), {}, <Dingus root()>), |
144 | + ('()', (55,), {}, <Dingus root()>)] |
145 | + |
146 | + Dinguses can do more than just have attributes accessed and be called. They |
147 | + support many Python operators. The goal is to allow, and record, any |
148 | + interaction: |
149 | + |
150 | + >>> d = Dingus('root') |
151 | + >>> (2 ** d.something)['hello']() / 100 * 'foo' |
152 | + <Dingus root.something.__rpow__[hello]().__div__.__mul__> |
153 | + |
154 | + (Hopefully your real-world dingus recordings won't look like this!) |
155 | + |
156 | + ======== |
157 | + PATCHING |
158 | + ======== |
159 | + |
160 | + Dingus provides a context manager for patching objects during tests. For |
161 | + example: |
162 | + |
163 | + >>> from dingus import patch |
164 | + >>> import urllib2 |
165 | + >>> with patch('urllib2.urlopen'): |
166 | + ... print urllib2.urlopen.__class__ |
167 | + <class 'dingus.Dingus'> |
168 | + >>> print urllib2.urlopen.__class__ |
169 | + <type 'function'> |
170 | + |
171 | + You can also use this as a decorator on your test methods: |
172 | + |
173 | + >>> @patch('urllib2.urlopen') |
174 | + ... def test_something(self): |
175 | + ... pass |
176 | + ... |
177 | + |
178 | + =============== |
179 | + DANGEROUS MAGIC |
180 | + =============== |
181 | + |
182 | + Dingus can also automatically replace a module's globals when running tests. |
183 | + This allows you to write fully isolated unit tests. See |
184 | + examples/urllib2/test\_urllib2.py for an example. The author no longer |
185 | + recommends this feature, as it can encourage very brittle tests. You should |
186 | + feel the pain of manually mocking dependencies; the pain will tell you when a |
187 | + class collaborates with too many others. |
188 | + |
189 | + |
190 | +Keywords: testing test mocking mock double stub fake record assert |
191 | Platform: UNKNOWN |
192 | -Classifier: Development Status :: 2 - Pre-Alpha |
193 | +Classifier: Development Status :: 4 - Beta |
194 | Classifier: Intended Audience :: Developers |
195 | Classifier: License :: OSI Approved :: MIT License |
196 | Classifier: Operating System :: OS Independent |
197 | |
198 | === removed file 'README' |
199 | --- README 2009-10-22 11:00:55 +0000 |
200 | +++ README 1970-01-01 00:00:00 +0000 |
201 | @@ -1,76 +0,0 @@ |
202 | -A dingus is sort of like a mock object. The main difference is that you don't |
203 | -set up expectations ahead of time. You just run your code, using a dingus in |
204 | -place of another object or class, and it will record what happens to it. Then, |
205 | -once your code has been exercised, you can make assertions about what it did |
206 | -to the dingus. |
207 | - |
208 | -A new dingus is created from the Dingus class. You can give dinguses names, |
209 | -which helps with debugging your tests, especially when there are multiple |
210 | -dinguses in play. |
211 | - |
212 | - >>> from dingus import Dingus |
213 | - >>> d = Dingus('root') |
214 | - >>> d |
215 | - <Dingus root> |
216 | - |
217 | -Accessing any attribute of a dingus will return a new dingus. |
218 | - |
219 | - >>> d.something |
220 | - <Dingus root.something> |
221 | - |
222 | -There are a few exceptions for special dingus methods. We'll see some in a |
223 | -bit. |
224 | - |
225 | -A dingus can also be called like a function or method. It doesn't care how |
226 | -many arguments you give it or what those arguments are. Calls to a dingus will |
227 | -always return the same object, regardless of the arguments. |
228 | - |
229 | - >>> d() |
230 | - <Dingus root()> |
231 | - >>> d('argument') |
232 | - <Dingus root()> |
233 | - >>> d(55) |
234 | - <Dingus root()> |
235 | - |
236 | -At any time we can get a list of calls that have been made to a dingus. Each |
237 | -entry in the call list contains: |
238 | - * the name of the method called (or "()" if the dingus itself was called) |
239 | - * The arguments, or () if none |
240 | - * The keyword argumnets, or {} if none |
241 | - * The value that was returned to the caller |
242 | - |
243 | -Here is a list of the calls we've made to d so far: |
244 | - |
245 | - >>> from pprint import pprint |
246 | - >>> pprint(d.calls) |
247 | - [('()', (), {}, <Dingus root()>), |
248 | - ('()', ('argument',), {}, <Dingus root()>), |
249 | - ('()', (55,), {}, <Dingus root()>)] |
250 | - |
251 | -You can filter calls by name, arguments, and keyword arguments: |
252 | - |
253 | - >>> pprint(d.calls('()', 55)) |
254 | - [('()', (55,), {}, <Dingus root()>)] |
255 | - |
256 | -If you don't care about a particular argument's value, you can use the value |
257 | -DontCare when filtering: |
258 | - |
259 | - >>> from dingus import DontCare |
260 | - >>> pprint(d.calls('()', DontCare)) |
261 | - [('()', ('argument',), {}, <Dingus root()>), |
262 | - ('()', (55,), {}, <Dingus root()>)] |
263 | - |
264 | -Dinguses can do more than just have attributes accessed and be called. They |
265 | -support many Python operators. The goal is to allow, and record, any |
266 | -interaction: |
267 | - |
268 | - >>> d = Dingus('root') |
269 | - >>> (2 ** d.something)['hello']() / 100 * 'foo' |
270 | - <Dingus root.something.__rpow__[hello]().__div__.__mul__> |
271 | - |
272 | -(Hopefully your real-world dingus recordings won't look like this!) |
273 | - |
274 | -Dingus can also automatically replace a module's globals when running tests. |
275 | -This allows you to write fully isolated unit tests. See |
276 | -examples/urllib2/test_urllib2.py for an example. |
277 | - |
278 | |
279 | === added file 'README.txt' |
280 | --- README.txt 1970-01-01 00:00:00 +0000 |
281 | +++ README.txt 2011-10-20 19:36:43 +0000 |
282 | @@ -0,0 +1,114 @@ |
283 | +======== |
284 | +DINGUSES |
285 | +======== |
286 | + |
287 | +A dingus is sort of like a mock object. The main difference is that you don't |
288 | +set up expectations ahead of time. You just run your code, using a dingus in |
289 | +place of another object or class, and it will record what happens to it. Then, |
290 | +once your code has been exercised, you can make assertions about what it did |
291 | +to the dingus. |
292 | + |
293 | +A new dingus is created from the Dingus class. You can give dinguses names, |
294 | +which helps with debugging your tests, especially when there are multiple |
295 | +dinguses in play. |
296 | + |
297 | + >>> from dingus import Dingus |
298 | + >>> d = Dingus('root') |
299 | + >>> d |
300 | + <Dingus root> |
301 | + |
302 | +Accessing any attribute of a dingus will return a new dingus. |
303 | + |
304 | + >>> d.something |
305 | + <Dingus root.something> |
306 | + |
307 | +There are a few exceptions for special dingus methods. We'll see some in a |
308 | +bit. |
309 | + |
310 | +A dingus can also be called like a function or method. It doesn't care how |
311 | +many arguments you give it or what those arguments are. Calls to a dingus will |
312 | +always return the same object, regardless of the arguments. |
313 | + |
314 | + >>> d() |
315 | + <Dingus root()> |
316 | + >>> d('argument') |
317 | + <Dingus root()> |
318 | + >>> d(55) |
319 | + <Dingus root()> |
320 | + |
321 | +======================== |
322 | +RECORDING AND ASSERTIONS |
323 | +======================== |
324 | + |
325 | +At any time we can get a list of calls that have been made to a dingus. Each |
326 | +entry in the call list contains: |
327 | + |
328 | +* the name of the method called (or "()" if the dingus itself was called) |
329 | +* The arguments, or () if none |
330 | +* The keyword argumnets, or {} if none |
331 | +* The value that was returned to the caller |
332 | + |
333 | +Here is a list of the calls we've made to d so far: |
334 | + |
335 | + >>> from pprint import pprint |
336 | + >>> pprint(d.calls) |
337 | + [('()', (), {}, <Dingus root()>), |
338 | + ('()', ('argument',), {}, <Dingus root()>), |
339 | + ('()', (55,), {}, <Dingus root()>)] |
340 | + |
341 | +You can filter calls by name, arguments, and keyword arguments: |
342 | + |
343 | + >>> pprint(d.calls('()', 55)) |
344 | + [('()', (55,), {}, <Dingus root()>)] |
345 | + |
346 | +If you don't care about a particular argument's value, you can use the value |
347 | +DontCare when filtering: |
348 | + |
349 | + >>> from dingus import DontCare |
350 | + >>> pprint(d.calls('()', DontCare)) |
351 | + [('()', ('argument',), {}, <Dingus root()>), |
352 | + ('()', (55,), {}, <Dingus root()>)] |
353 | + |
354 | +Dinguses can do more than just have attributes accessed and be called. They |
355 | +support many Python operators. The goal is to allow, and record, any |
356 | +interaction: |
357 | + |
358 | + >>> d = Dingus('root') |
359 | + >>> (2 ** d.something)['hello']() / 100 * 'foo' |
360 | + <Dingus root.something.__rpow__[hello]().__div__.__mul__> |
361 | + |
362 | +(Hopefully your real-world dingus recordings won't look like this!) |
363 | + |
364 | +======== |
365 | +PATCHING |
366 | +======== |
367 | + |
368 | +Dingus provides a context manager for patching objects during tests. For |
369 | +example: |
370 | + |
371 | + >>> from dingus import patch |
372 | + >>> import urllib2 |
373 | + >>> with patch('urllib2.urlopen'): |
374 | + ... print urllib2.urlopen.__class__ |
375 | + <class 'dingus.Dingus'> |
376 | + >>> print urllib2.urlopen.__class__ |
377 | + <type 'function'> |
378 | + |
379 | +You can also use this as a decorator on your test methods: |
380 | + |
381 | + >>> @patch('urllib2.urlopen') |
382 | + ... def test_something(self): |
383 | + ... pass |
384 | + ... |
385 | + |
386 | +=============== |
387 | +DANGEROUS MAGIC |
388 | +=============== |
389 | + |
390 | +Dingus can also automatically replace a module's globals when running tests. |
391 | +This allows you to write fully isolated unit tests. See |
392 | +examples/urllib2/test\_urllib2.py for an example. The author no longer |
393 | +recommends this feature, as it can encourage very brittle tests. You should |
394 | +feel the pain of manually mocking dependencies; the pain will tell you when a |
395 | +class collaborates with too many others. |
396 | + |
397 | |
398 | === modified file 'debian/changelog' |
399 | --- debian/changelog 2011-08-31 08:36:44 +0000 |
400 | +++ debian/changelog 2011-10-20 19:36:43 +0000 |
401 | @@ -1,3 +1,17 @@ |
402 | +python-dingus (0.3.2-1ubuntu1) precise; urgency=low |
403 | + |
404 | + * Merge from debian testing (LP: #879051). Remaining changes: |
405 | + - dh_python2 transition |
406 | + |
407 | + -- Adam Gandelman <adamg@canonical.com> Thu, 20 Oct 2011 12:17:50 -0700 |
408 | + |
409 | +python-dingus (0.3.2-1) unstable; urgency=low |
410 | + |
411 | + * New upstream release |
412 | + * Update Standards version, no changes needed. |
413 | + |
414 | + -- David Watson <dwatson@debian.org> Sun, 07 Aug 2011 09:16:45 +0100 |
415 | + |
416 | python-dingus (0.1-2ubuntu1) oneiric; urgency=low |
417 | |
418 | * dh_python2 transition. |
419 | |
420 | === modified file 'debian/control' |
421 | --- debian/control 2011-08-31 08:36:44 +0000 |
422 | +++ debian/control 2011-10-20 19:36:43 +0000 |
423 | @@ -11,7 +11,7 @@ |
424 | Package: python-dingus |
425 | Architecture: all |
426 | Depends: ${misc:Depends}, ${python:Depends} |
427 | -Description: A record-then-assert mocking library |
428 | +Description: Record-then-assert mocking library |
429 | A dingus is sort of like a mock object. The main difference is that you don't |
430 | set up expectations ahead of time. You just run your code, using a dingus in |
431 | place of another object or class, and it will record what happens to it. Then, |
432 | |
433 | === modified file 'debian/docs' |
434 | --- debian/docs 2009-10-22 11:00:55 +0000 |
435 | +++ debian/docs 2011-10-20 19:36:43 +0000 |
436 | @@ -1,2 +1,1 @@ |
437 | -README |
438 | -examples/ |
439 | +README.txt |
440 | |
441 | === added directory 'debian/patches' |
442 | === added file 'debian/patches/debian-changes-0.3.2-1' |
443 | --- debian/patches/debian-changes-0.3.2-1 1970-01-01 00:00:00 +0000 |
444 | +++ debian/patches/debian-changes-0.3.2-1 2011-10-20 19:36:43 +0000 |
445 | @@ -0,0 +1,64 @@ |
446 | +Description: Upstream changes introduced in version 0.3.2-1 |
447 | + This patch has been created by dpkg-source during the package build. |
448 | + Here's the last changelog entry, hopefully it gives details on why |
449 | + those changes were made: |
450 | + . |
451 | + python-dingus (0.3.2-1) unstable; urgency=low |
452 | + . |
453 | + * New upstream release |
454 | + * Update Standards version, no changes needed. |
455 | + . |
456 | + The person named in the Author field signed this changelog entry. |
457 | +Author: David Watson <dwatson@debian.org> |
458 | + |
459 | +--- |
460 | +The information above should follow the Patch Tagging Guidelines, please |
461 | +checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here |
462 | +are templates for supplementary fields that you might want to add: |
463 | + |
464 | +Origin: <vendor|upstream|other>, <url of original patch> |
465 | +Bug: <url in upstream bugtracker> |
466 | +Bug-Debian: http://bugs.debian.org/<bugnumber> |
467 | +Bug-Ubuntu: https://launchpad.net/bugs/<bugnumber> |
468 | +Forwarded: <no|not-needed|url proving that it has been forwarded> |
469 | +Reviewed-By: <name and email of someone who approved the patch> |
470 | +Last-Update: <YYYY-MM-DD> |
471 | + |
472 | +--- python-dingus-0.3.2.orig/setup.py |
473 | ++++ python-dingus-0.3.2/setup.py |
474 | +@@ -7,7 +7,6 @@ setup(name='dingus', |
475 | + author='Gary Bernhardt', |
476 | + author_email='gary.bernhardt@gmail.com', |
477 | + py_modules=['dingus'], |
478 | +- data_files=[('', ['README.txt'])], |
479 | + license='MIT', |
480 | + url='https://github.com/garybernhardt/dingus', |
481 | + keywords='testing test mocking mock double stub fake record assert', |
482 | +--- python-dingus-0.3.2.orig/dingus.egg-info/SOURCES.txt |
483 | ++++ python-dingus-0.3.2/dingus.egg-info/SOURCES.txt |
484 | +@@ -1,5 +1,6 @@ |
485 | + README.txt |
486 | + dingus.py |
487 | ++setup.cfg |
488 | + setup.py |
489 | + dingus.egg-info/PKG-INFO |
490 | + dingus.egg-info/SOURCES.txt |
491 | +--- /dev/null |
492 | ++++ python-dingus-0.3.2/patches/setup_cleanup |
493 | +@@ -0,0 +1,12 @@ |
494 | ++Index: python-dingus-0.3.2/setup.py |
495 | ++=================================================================== |
496 | ++--- python-dingus-0.3.2.orig/setup.py 2011-08-07 09:37:57.900948735 +0100 |
497 | +++++ python-dingus-0.3.2/setup.py 2011-08-07 09:38:03.340954228 +0100 |
498 | ++@@ -7,7 +7,6 @@ |
499 | ++ author='Gary Bernhardt', |
500 | ++ author_email='gary.bernhardt@gmail.com', |
501 | ++ py_modules=['dingus'], |
502 | ++- data_files=[('', ['README.txt'])], |
503 | ++ license='MIT', |
504 | ++ url='https://github.com/garybernhardt/dingus', |
505 | ++ keywords='testing test mocking mock double stub fake record assert', |
506 | +--- /dev/null |
507 | ++++ python-dingus-0.3.2/patches/series |
508 | +@@ -0,0 +1 @@ |
509 | ++setup_cleanup |
510 | |
511 | === added file 'debian/patches/series' |
512 | --- debian/patches/series 1970-01-01 00:00:00 +0000 |
513 | +++ debian/patches/series 2011-10-20 19:36:43 +0000 |
514 | @@ -0,0 +1,1 @@ |
515 | +debian-changes-0.3.2-1 |
516 | |
517 | === added directory 'debian/source' |
518 | === added file 'debian/source/format' |
519 | --- debian/source/format 1970-01-01 00:00:00 +0000 |
520 | +++ debian/source/format 2011-10-20 19:36:43 +0000 |
521 | @@ -0,0 +1,1 @@ |
522 | +3.0 (quilt) |
523 | |
524 | === modified file 'dingus.egg-info/PKG-INFO' |
525 | --- dingus.egg-info/PKG-INFO 2009-10-22 11:00:55 +0000 |
526 | +++ dingus.egg-info/PKG-INFO 2011-10-20 19:36:43 +0000 |
527 | @@ -1,15 +1,129 @@ |
528 | Metadata-Version: 1.0 |
529 | Name: dingus |
530 | -Version: 0.1 |
531 | +Version: 0.3.2 |
532 | Summary: A record-then-assert mocking library |
533 | -Home-page: http://bitbucket.org/garybernhardt/dingus |
534 | +Home-page: https://github.com/garybernhardt/dingus |
535 | Author: Gary Bernhardt |
536 | Author-email: gary.bernhardt@gmail.com |
537 | License: MIT |
538 | -Description: UNKNOWN |
539 | -Keywords: testing test mocking mock double stub fake |
540 | +Description: ======== |
541 | + DINGUSES |
542 | + ======== |
543 | + |
544 | + A dingus is sort of like a mock object. The main difference is that you don't |
545 | + set up expectations ahead of time. You just run your code, using a dingus in |
546 | + place of another object or class, and it will record what happens to it. Then, |
547 | + once your code has been exercised, you can make assertions about what it did |
548 | + to the dingus. |
549 | + |
550 | + A new dingus is created from the Dingus class. You can give dinguses names, |
551 | + which helps with debugging your tests, especially when there are multiple |
552 | + dinguses in play. |
553 | + |
554 | + >>> from dingus import Dingus |
555 | + >>> d = Dingus('root') |
556 | + >>> d |
557 | + <Dingus root> |
558 | + |
559 | + Accessing any attribute of a dingus will return a new dingus. |
560 | + |
561 | + >>> d.something |
562 | + <Dingus root.something> |
563 | + |
564 | + There are a few exceptions for special dingus methods. We'll see some in a |
565 | + bit. |
566 | + |
567 | + A dingus can also be called like a function or method. It doesn't care how |
568 | + many arguments you give it or what those arguments are. Calls to a dingus will |
569 | + always return the same object, regardless of the arguments. |
570 | + |
571 | + >>> d() |
572 | + <Dingus root()> |
573 | + >>> d('argument') |
574 | + <Dingus root()> |
575 | + >>> d(55) |
576 | + <Dingus root()> |
577 | + |
578 | + ======================== |
579 | + RECORDING AND ASSERTIONS |
580 | + ======================== |
581 | + |
582 | + At any time we can get a list of calls that have been made to a dingus. Each |
583 | + entry in the call list contains: |
584 | + |
585 | + * the name of the method called (or "()" if the dingus itself was called) |
586 | + * The arguments, or () if none |
587 | + * The keyword argumnets, or {} if none |
588 | + * The value that was returned to the caller |
589 | + |
590 | + Here is a list of the calls we've made to d so far: |
591 | + |
592 | + >>> from pprint import pprint |
593 | + >>> pprint(d.calls) |
594 | + [('()', (), {}, <Dingus root()>), |
595 | + ('()', ('argument',), {}, <Dingus root()>), |
596 | + ('()', (55,), {}, <Dingus root()>)] |
597 | + |
598 | + You can filter calls by name, arguments, and keyword arguments: |
599 | + |
600 | + >>> pprint(d.calls('()', 55)) |
601 | + [('()', (55,), {}, <Dingus root()>)] |
602 | + |
603 | + If you don't care about a particular argument's value, you can use the value |
604 | + DontCare when filtering: |
605 | + |
606 | + >>> from dingus import DontCare |
607 | + >>> pprint(d.calls('()', DontCare)) |
608 | + [('()', ('argument',), {}, <Dingus root()>), |
609 | + ('()', (55,), {}, <Dingus root()>)] |
610 | + |
611 | + Dinguses can do more than just have attributes accessed and be called. They |
612 | + support many Python operators. The goal is to allow, and record, any |
613 | + interaction: |
614 | + |
615 | + >>> d = Dingus('root') |
616 | + >>> (2 ** d.something)['hello']() / 100 * 'foo' |
617 | + <Dingus root.something.__rpow__[hello]().__div__.__mul__> |
618 | + |
619 | + (Hopefully your real-world dingus recordings won't look like this!) |
620 | + |
621 | + ======== |
622 | + PATCHING |
623 | + ======== |
624 | + |
625 | + Dingus provides a context manager for patching objects during tests. For |
626 | + example: |
627 | + |
628 | + >>> from dingus import patch |
629 | + >>> import urllib2 |
630 | + >>> with patch('urllib2.urlopen'): |
631 | + ... print urllib2.urlopen.__class__ |
632 | + <class 'dingus.Dingus'> |
633 | + >>> print urllib2.urlopen.__class__ |
634 | + <type 'function'> |
635 | + |
636 | + You can also use this as a decorator on your test methods: |
637 | + |
638 | + >>> @patch('urllib2.urlopen') |
639 | + ... def test_something(self): |
640 | + ... pass |
641 | + ... |
642 | + |
643 | + =============== |
644 | + DANGEROUS MAGIC |
645 | + =============== |
646 | + |
647 | + Dingus can also automatically replace a module's globals when running tests. |
648 | + This allows you to write fully isolated unit tests. See |
649 | + examples/urllib2/test\_urllib2.py for an example. The author no longer |
650 | + recommends this feature, as it can encourage very brittle tests. You should |
651 | + feel the pain of manually mocking dependencies; the pain will tell you when a |
652 | + class collaborates with too many others. |
653 | + |
654 | + |
655 | +Keywords: testing test mocking mock double stub fake record assert |
656 | Platform: UNKNOWN |
657 | -Classifier: Development Status :: 2 - Pre-Alpha |
658 | +Classifier: Development Status :: 4 - Beta |
659 | Classifier: Intended Audience :: Developers |
660 | Classifier: License :: OSI Approved :: MIT License |
661 | Classifier: Operating System :: OS Independent |
662 | |
663 | === modified file 'dingus.egg-info/SOURCES.txt' |
664 | --- dingus.egg-info/SOURCES.txt 2009-10-22 11:00:55 +0000 |
665 | +++ dingus.egg-info/SOURCES.txt 2011-10-20 19:36:43 +0000 |
666 | @@ -1,23 +1,8 @@ |
667 | -README |
668 | +README.txt |
669 | dingus.py |
670 | setup.cfg |
671 | setup.py |
672 | dingus.egg-info/PKG-INFO |
673 | dingus.egg-info/SOURCES.txt |
674 | dingus.egg-info/dependency_links.txt |
675 | -dingus.egg-info/top_level.txt |
676 | -examples/__init__.py |
677 | -examples/googler/__init__.py |
678 | -examples/googler/googler.py |
679 | -examples/googler/runtests.py |
680 | -examples/googler/test_googler.py |
681 | -examples/urllib2/__init__.py |
682 | -examples/urllib2/runtests.py |
683 | -examples/urllib2/test_urllib2.py |
684 | -tests/__init__.py |
685 | -tests/runtests.py |
686 | -tests/test_call.py |
687 | -tests/test_call_list.py |
688 | -tests/test_dingus.py |
689 | -tests/test_dingus_test_case.py |
690 | -tests/test_exception_raiser.py |
691 | \ No newline at end of file |
692 | +dingus.egg-info/top_level.txt |
693 | \ No newline at end of file |
694 | |
695 | === modified file 'dingus.py' |
696 | --- dingus.py 2009-10-22 11:00:55 +0000 |
697 | +++ dingus.py 2011-10-20 19:36:43 +0000 |
698 | @@ -4,51 +4,50 @@ |
699 | |
700 | |
701 | import sys |
702 | -import new |
703 | - |
704 | - |
705 | -def DingusTestCase(class_under_test): |
706 | +from functools import wraps |
707 | + |
708 | +def DingusTestCase(object_under_test, exclude=None): |
709 | + if isinstance(exclude, basestring): |
710 | + raise ValueError("Strings not allowed for exclude. " + |
711 | + "Use a list: exclude=['identifier']") |
712 | + exclude = [] if exclude is None else exclude |
713 | + |
714 | + def get_names_under_test(): |
715 | + module = sys.modules[object_under_test.__module__] |
716 | + for name, value in module.__dict__.iteritems(): |
717 | + if value is object_under_test or name in exclude: |
718 | + yield name |
719 | + |
720 | class TestCase(object): |
721 | def setup(self): |
722 | - module_name = class_under_test.__module__ |
723 | + module_name = object_under_test.__module__ |
724 | self._dingus_module = sys.modules[module_name] |
725 | - self._dingus_replace_module_globals(self._dingus_module, |
726 | - class_under_test) |
727 | + self._dingus_replace_module_globals(self._dingus_module) |
728 | |
729 | def teardown(self): |
730 | self._dingus_restore_module(self._dingus_module) |
731 | |
732 | - def _dingus_wipe_module(self, module): |
733 | + def _dingus_replace_module_globals(self, module): |
734 | old_module_dict = module.__dict__.copy() |
735 | - module.__dict__.clear() |
736 | - module.__dict__.update(__builtins__) |
737 | - module.__dict__['__dingused_dict__'] = old_module_dict |
738 | - |
739 | - |
740 | - def _dingus_replace_module_globals(self, module, class_under_test): |
741 | module_keys = set(module.__dict__.iterkeys()) |
742 | - builtin_keys = set(__builtins__.iterkeys()) |
743 | |
744 | - test_class_name = class_under_test.__name__ |
745 | - replaced_keys = (module_keys - |
746 | - builtin_keys - |
747 | - set([test_class_name])) |
748 | - self._dingus_wipe_module(module) |
749 | + dunders = set(k for k in module_keys |
750 | + if k.startswith('__') and k.endswith('__')) |
751 | + replaced_keys = (module_keys - dunders - set(names_under_test)) |
752 | for key in replaced_keys: |
753 | module.__dict__[key] = Dingus() |
754 | - module.__dict__[test_class_name] = class_under_test |
755 | + module.__dict__['__dingused_dict__'] = old_module_dict |
756 | |
757 | def _dingus_restore_module(self, module): |
758 | old_module_dict = module.__dict__['__dingused_dict__'] |
759 | module.__dict__.clear() |
760 | module.__dict__.update(old_module_dict) |
761 | |
762 | - |
763 | - TestCase.__name__ = '%sDingusTestCase' % class_under_test.__module__ |
764 | + names_under_test = list(get_names_under_test()) |
765 | + TestCase.__name__ = '%s_DingusTestCase' % '_'.join(names_under_test) |
766 | return TestCase |
767 | |
768 | |
769 | - |
770 | # These sentinels are used for argument defaults because the user might want |
771 | # to pass in None, which is different in some cases than passing nothing. |
772 | class NoReturnValue(object): |
773 | @@ -57,6 +56,65 @@ |
774 | pass |
775 | |
776 | |
777 | +def patch(object_path, new_object=NoArgument): |
778 | + module_name, attribute_name = object_path.rsplit('.', 1) |
779 | + return _Patcher(module_name, attribute_name, new_object) |
780 | + |
781 | + |
782 | +class _Patcher: |
783 | + def __init__(self, module_name, attribute_name, new_object): |
784 | + self.module_name = module_name |
785 | + self.attribute_name = attribute_name |
786 | + self.module = _importer(self.module_name) |
787 | + if new_object is NoArgument: |
788 | + full_name = '%s.%s' % (module_name, attribute_name) |
789 | + self.new_object = Dingus(full_name) |
790 | + else: |
791 | + self.new_object = new_object |
792 | + |
793 | + def __call__(self, fn): |
794 | + @wraps(fn) |
795 | + def new_fn(*args, **kwargs): |
796 | + self.patch_object() |
797 | + try: |
798 | + return fn(*args, **kwargs) |
799 | + finally: |
800 | + self.restore_object() |
801 | + return new_fn |
802 | + |
803 | + def __enter__(self): |
804 | + self.patch_object() |
805 | + |
806 | + def __exit__(self, exc_type, exc_value, traceback): |
807 | + self.restore_object() |
808 | + |
809 | + def patch_object(self): |
810 | + self.original_object = getattr(self.module, self.attribute_name) |
811 | + setattr(self.module, self.attribute_name, self.new_object) |
812 | + |
813 | + def restore_object(self): |
814 | + setattr(self.module, self.attribute_name, self.original_object) |
815 | + |
816 | + |
817 | +def _importer(target): |
818 | + components = target.split('.') |
819 | + import_path = components.pop(0) |
820 | + thing = __import__(import_path) |
821 | + |
822 | + for comp in components: |
823 | + import_path += ".%s" % comp |
824 | + thing = _dot_lookup(thing, comp, import_path) |
825 | + return thing |
826 | + |
827 | + |
828 | +def _dot_lookup(thing, comp, import_path): |
829 | + try: |
830 | + return getattr(thing, comp) |
831 | + except AttributeError: |
832 | + __import__(import_path) |
833 | + return getattr(thing, comp) |
834 | + |
835 | + |
836 | class DontCare(object): |
837 | pass |
838 | |
839 | @@ -70,6 +128,9 @@ |
840 | self.args = self[1] |
841 | self.kwargs = self[2] |
842 | self.return_value = self[3] |
843 | + |
844 | + def __getnewargs__(self): |
845 | + return (self.name, self.args, self.kwargs, self.return_value) |
846 | |
847 | |
848 | class CallList(list): |
849 | @@ -83,24 +144,41 @@ |
850 | return all(args[i] in (DontCare, call.args[i]) |
851 | for i in range(len(call.args))) |
852 | |
853 | + @staticmethod |
854 | + def _match_kwargs(call, kwargs): |
855 | + if not kwargs: |
856 | + return True |
857 | + elif len(kwargs) != len(call.kwargs): |
858 | + return False |
859 | + else: |
860 | + return all(name in kwargs and kwargs[name] in (DontCare, val) |
861 | + for name, val in call.kwargs.iteritems()) |
862 | + |
863 | def one(self): |
864 | if len(self) == 1: |
865 | return self[0] |
866 | else: |
867 | return None |
868 | |
869 | - def __call__(self, name=NoArgument, *args, **kwargs): |
870 | + def once(self): |
871 | + return self.one() |
872 | + |
873 | + def __call__(self, __name=NoArgument, *args, **kwargs): |
874 | return CallList([call for call in self |
875 | - if (name is NoArgument or name == call.name) |
876 | + if (__name is NoArgument or __name == call.name) |
877 | and self._match_args(call, args) |
878 | - and (not kwargs or kwargs == call.kwargs)]) |
879 | + and self._match_kwargs(call, kwargs)]) |
880 | + |
881 | + |
882 | +def returner(return_value): |
883 | + return Dingus(return_value=return_value) |
884 | |
885 | |
886 | class Dingus(object): |
887 | - def __init__(self, name=None, full_name=None, **kwargs): |
888 | + def __init__(self, dingus_name=None, full_name=None, **kwargs): |
889 | self._parent = None |
890 | self.reset() |
891 | - name = 'dingus_%i' % id(self) if name is None else name |
892 | + name = 'dingus_%i' % id(self) if dingus_name is None else dingus_name |
893 | full_name = name if full_name is None else full_name |
894 | self._short_name = name |
895 | self._full_name = full_name |
896 | @@ -108,7 +186,13 @@ |
897 | self._full_name = full_name |
898 | |
899 | for attr_name, attr_value in kwargs.iteritems(): |
900 | - setattr(self, attr_name, attr_value) |
901 | + if attr_name.endswith('__returns'): |
902 | + attr_name = attr_name.replace('__returns', '') |
903 | + returner = self._create_child(attr_name) |
904 | + returner.return_value = attr_value |
905 | + setattr(self, attr_name, returner) |
906 | + else: |
907 | + setattr(self, attr_name, attr_value) |
908 | |
909 | self._replace_init_method() |
910 | |
911 | @@ -126,7 +210,7 @@ |
912 | separator = ('' if (name.startswith('()') or name.startswith('[')) |
913 | else '.') |
914 | full_name = self._full_name + separator + name |
915 | - child = Dingus(name, full_name) |
916 | + child = self.__class__(name, full_name) |
917 | child._parent = self |
918 | return child |
919 | |
920 | @@ -146,9 +230,6 @@ |
921 | return_value = property(_get_return_value, _set_return_value) |
922 | |
923 | def __call__(self, *args, **kwargs): |
924 | - if self.return_value is NoReturnValue: |
925 | - self.return_value = self._create_child('()') |
926 | - |
927 | self._log_call('()', args, kwargs, self.return_value) |
928 | if self._parent: |
929 | self._parent._log_call(self._short_name, |
930 | @@ -162,50 +243,97 @@ |
931 | self.calls.append(Call(name, args, kwargs, return_value)) |
932 | |
933 | def _should_ignore_attribute(self, name): |
934 | - return name == '__pyobjc_object__' |
935 | + return name in ['__pyobjc_object__', '__getnewargs__'] |
936 | + |
937 | + def __getstate__(self): |
938 | + # Python cannot pickle a instancemethod |
939 | + # http://bugs.python.org/issue558238 |
940 | + return [ (attr, value) for attr, value in self.__dict__.items() if attr != "__init__"] |
941 | + |
942 | + def __setstate__(self, state): |
943 | + self.__dict__.update(state) |
944 | + self._replace_init_method() |
945 | + |
946 | + def _existing_or_new_child(self, child_name, default_value=NoArgument): |
947 | + if child_name not in self._children: |
948 | + value = (self._create_child(child_name) |
949 | + if default_value is NoArgument |
950 | + else default_value) |
951 | + self._children[child_name] = value |
952 | + |
953 | + return self._children[child_name] |
954 | + |
955 | + def _remove_child_if_exists(self, child_name): |
956 | + if child_name in self._children: |
957 | + del self._children[child_name] |
958 | |
959 | def __getattr__(self, name): |
960 | if self._should_ignore_attribute(name): |
961 | raise AttributeError(name) |
962 | - |
963 | - if name not in self._children: |
964 | - self._children[name] = self._create_child(name) |
965 | - |
966 | - return self._children[name] |
967 | + return self._existing_or_new_child(name) |
968 | + |
969 | + def __delattr__(self, name): |
970 | + self._log_call('__delattr__', (name,), {}, None) |
971 | |
972 | def __getitem__(self, index): |
973 | - child_name = '[%s]' % index |
974 | - return_value = self._children.setdefault( |
975 | - child_name, self._create_child('[%s]' % index)) |
976 | + child_name = '[%s]' % (index,) |
977 | + return_value = self._existing_or_new_child(child_name) |
978 | self._log_call('__getitem__', (index,), {}, return_value) |
979 | return return_value |
980 | |
981 | def __setitem__(self, index, value): |
982 | - child_name = '[%s]' % index |
983 | + child_name = '[%s]' % (index,) |
984 | self._log_call('__setitem__', (index, value), {}, None) |
985 | - self._children[child_name] = value |
986 | + self._remove_child_if_exists(child_name) |
987 | + self._existing_or_new_child(child_name, value) |
988 | |
989 | - def _create_operator(name): |
990 | + def _create_infix_operator(name): |
991 | def operator_fn(self, other): |
992 | - if name not in self._children: |
993 | - self._children[name] = self._create_child(name) |
994 | - return self._children[name] |
995 | + return_value = self._existing_or_new_child(name) |
996 | + self._log_call(name, (other,), {}, return_value) |
997 | + return return_value |
998 | operator_fn.__name__ = name |
999 | return operator_fn |
1000 | |
1001 | - def _operators(): |
1002 | - operator_names = ['add', 'and', 'div', 'lshift', 'mod', 'mul', 'or', |
1003 | - 'pow', 'rshift', 'sub', 'xor'] |
1004 | - reverse_operator_names = ['r%s' % name for name in operator_names] |
1005 | - for operator_name in operator_names + reverse_operator_names: |
1006 | + _BASE_OPERATOR_NAMES = ['add', 'and', 'div', 'lshift', 'mod', 'mul', 'or', |
1007 | + 'pow', 'rshift', 'sub', 'xor'] |
1008 | + |
1009 | + def _infix_operator_names(base_operator_names): |
1010 | + # This function has to have base_operator_names passed in because |
1011 | + # Python's scoping rules prevent it from seeing the class-level |
1012 | + # _BASE_OPERATOR_NAMES. |
1013 | + |
1014 | + reverse_operator_names = ['r%s' % name for name in base_operator_names] |
1015 | + for operator_name in base_operator_names + reverse_operator_names: |
1016 | operator_fn_name = '__%s__' % operator_name |
1017 | yield operator_fn_name |
1018 | |
1019 | - # Define each operator |
1020 | - for operator_fn_name in _operators(): |
1021 | - exec('%s = _create_operator("%s")' % (operator_fn_name, |
1022 | + # Define each infix operator |
1023 | + for operator_fn_name in _infix_operator_names(_BASE_OPERATOR_NAMES): |
1024 | + exec('%s = _create_infix_operator("%s")' % (operator_fn_name, |
1025 | operator_fn_name)) |
1026 | |
1027 | + def _augmented_operator_names(base_operator_names): |
1028 | + # Augmented operators are things like +=. They behavior differently |
1029 | + # than normal infix operators because they return self instead of a |
1030 | + # new object. |
1031 | + |
1032 | + return ['__i%s__' % operator_name |
1033 | + for operator_name in base_operator_names] |
1034 | + |
1035 | + def _create_augmented_operator(name): |
1036 | + def operator_fn(self, other): |
1037 | + return_value = self |
1038 | + self._log_call(name, (other,), {}, return_value) |
1039 | + return return_value |
1040 | + operator_fn.__name__ = name |
1041 | + return operator_fn |
1042 | + |
1043 | + # Define each augmenting operator |
1044 | + for operator_fn_name in _augmented_operator_names(_BASE_OPERATOR_NAMES): |
1045 | + exec('%s = _create_augmented_operator("%s")' % (operator_fn_name, |
1046 | + operator_fn_name)) |
1047 | + |
1048 | def __str__(self): |
1049 | return '<Dingus %s>' % self._full_name |
1050 | __repr__ = __str__ |
1051 | @@ -213,6 +341,13 @@ |
1052 | def __len__(self): |
1053 | return 1 |
1054 | |
1055 | + def __iter__(self): |
1056 | + return iter([self._existing_or_new_child('__iter__')]) |
1057 | + |
1058 | + # We don't want to define __deepcopy__ at all. If there isn't one, deepcopy |
1059 | + # will clone the whole object, which is what we want. |
1060 | + __deepcopy__ = None |
1061 | + |
1062 | |
1063 | def exception_raiser(exception): |
1064 | def raise_exception(*args, **kwargs): |
1065 | |
1066 | === removed directory 'examples' |
1067 | === removed file 'examples/__init__.py' |
1068 | --- examples/__init__.py 2009-10-22 11:00:55 +0000 |
1069 | +++ examples/__init__.py 1970-01-01 00:00:00 +0000 |
1070 | @@ -1,1 +0,0 @@ |
1071 | - |
1072 | |
1073 | === removed directory 'examples/googler' |
1074 | === removed file 'examples/googler/__init__.py' |
1075 | --- examples/googler/__init__.py 2009-10-22 11:00:55 +0000 |
1076 | +++ examples/googler/__init__.py 1970-01-01 00:00:00 +0000 |
1077 | @@ -1,1 +0,0 @@ |
1078 | - |
1079 | |
1080 | === removed file 'examples/googler/googler.py' |
1081 | --- examples/googler/googler.py 2009-10-22 11:00:55 +0000 |
1082 | +++ examples/googler/googler.py 1970-01-01 00:00:00 +0000 |
1083 | @@ -1,21 +0,0 @@ |
1084 | -import urllib2 |
1085 | - |
1086 | - |
1087 | -class Googler(object): |
1088 | - BASE_QUERY_URL = 'http://www.google.com/search?q=' |
1089 | - USER_AGENT = ('Mozilla/5.0' + |
1090 | - '(X11; U; Linux i686; en-US; rv:1.7.8)' + |
1091 | - 'Gecko/20050524 Fedora/1.5 Firefox/1.5') |
1092 | - |
1093 | - def __init__(self, terms): |
1094 | - query_string = '+'.join(terms) |
1095 | - request = urllib2.Request('%s%s' % (self.BASE_QUERY_URL, |
1096 | - query_string)) |
1097 | - request.add_header('User-Agent', self.USER_AGENT) |
1098 | - connection = urllib2.urlopen(request) |
1099 | - self.response = connection.read() |
1100 | - |
1101 | - |
1102 | -if __name__ == '__main__': |
1103 | - print Googler(['lulz', 'megalulz']).response |
1104 | - |
1105 | |
1106 | === removed file 'examples/googler/runtests.py' |
1107 | --- examples/googler/runtests.py 2009-10-22 11:00:55 +0000 |
1108 | +++ examples/googler/runtests.py 1970-01-01 00:00:00 +0000 |
1109 | @@ -1,12 +0,0 @@ |
1110 | -#!/usr/bin/env python |
1111 | - |
1112 | -import sys |
1113 | - |
1114 | -import nose |
1115 | - |
1116 | - |
1117 | -if __name__ == '__main__': |
1118 | - nose_args = sys.argv + [r'-m', |
1119 | - r'((?:^|[b_.-])(:?[Tt]est|When|should))'] |
1120 | - nose.run(argv=nose_args) |
1121 | - |
1122 | |
1123 | === removed file 'examples/googler/test_googler.py' |
1124 | --- examples/googler/test_googler.py 2009-10-22 11:00:55 +0000 |
1125 | +++ examples/googler/test_googler.py 1970-01-01 00:00:00 +0000 |
1126 | @@ -1,56 +0,0 @@ |
1127 | -from dingus import Dingus, DingusTestCase, DontCare |
1128 | -import googler |
1129 | -from googler import Googler |
1130 | - |
1131 | - |
1132 | -class WhenCreatingRequest(DingusTestCase(Googler)): |
1133 | - def setup(self): |
1134 | - super(WhenCreatingRequest, self).setup() |
1135 | - self.query_term = 'query term' |
1136 | - self.googler = Googler([self.query_term]) |
1137 | - |
1138 | - def should_use_google_search_url(self): |
1139 | - query_url = 'http://www.google.com/search?q=%s' % self.query_term |
1140 | - assert googler.urllib2.calls('Request', query_url) |
1141 | - |
1142 | - |
1143 | -class WhenCreatingRequestWithTwoTerms(DingusTestCase(Googler)): |
1144 | - def setup(self): |
1145 | - super(WhenCreatingRequestWithTwoTerms, self).setup() |
1146 | - self.terms = ['term1', 'term2'] |
1147 | - self.googler = Googler(self.terms) |
1148 | - |
1149 | - def should_combine_terms_in_search_url(self): |
1150 | - query_string = '+'.join(self.terms) |
1151 | - query_url = 'http://www.google.com/search?q=%s' % query_string |
1152 | - assert googler.urllib2.calls('Request', query_url) |
1153 | - |
1154 | - |
1155 | -class WhenSendingRequest(DingusTestCase(Googler)): |
1156 | - def setup(self): |
1157 | - super(WhenSendingRequest, self).setup() |
1158 | - self.request = googler.urllib2.Request.return_value |
1159 | - Googler(['query term']) |
1160 | - |
1161 | - def should_connect_to_google(self): |
1162 | - assert googler.urllib2.calls('urlopen', self.request) |
1163 | - |
1164 | - def should_add_fake_user_agent_to_evade_filters(self): |
1165 | - call = self.request.calls('add_header', |
1166 | - 'User-Agent', |
1167 | - DontCare).one() |
1168 | - assert 'Mozilla' in call.args[1] |
1169 | - |
1170 | - |
1171 | -class WhenConnected(DingusTestCase(Googler)): |
1172 | - def setup(self): |
1173 | - super(WhenConnected, self).setup() |
1174 | - self.connection = googler.urllib2.urlopen.return_value |
1175 | - self.googler = Googler(['query term']) |
1176 | - |
1177 | - def should_read_result(self): |
1178 | - assert self.connection.calls('read') |
1179 | - |
1180 | - def should_store_result_in_attribute(self): |
1181 | - assert self.googler.response is self.connection.read.return_value |
1182 | - |
1183 | |
1184 | === removed directory 'examples/urllib2' |
1185 | === removed file 'examples/urllib2/__init__.py' |
1186 | --- examples/urllib2/__init__.py 2009-10-22 11:00:55 +0000 |
1187 | +++ examples/urllib2/__init__.py 1970-01-01 00:00:00 +0000 |
1188 | @@ -1,1 +0,0 @@ |
1189 | - |
1190 | |
1191 | === removed file 'examples/urllib2/runtests.py' |
1192 | --- examples/urllib2/runtests.py 2009-10-22 11:00:55 +0000 |
1193 | +++ examples/urllib2/runtests.py 1970-01-01 00:00:00 +0000 |
1194 | @@ -1,12 +0,0 @@ |
1195 | -#!/usr/bin/env python |
1196 | - |
1197 | -import sys |
1198 | - |
1199 | -import nose |
1200 | - |
1201 | - |
1202 | -if __name__ == '__main__': |
1203 | - nose_args = sys.argv + [r'-m', |
1204 | - r'((?:^|[b_.-])(:?[Tt]est|When|should))'] |
1205 | - nose.run(argv=nose_args) |
1206 | - |
1207 | |
1208 | === removed file 'examples/urllib2/test_urllib2.py' |
1209 | --- examples/urllib2/test_urllib2.py 2009-10-22 11:00:55 +0000 |
1210 | +++ examples/urllib2/test_urllib2.py 1970-01-01 00:00:00 +0000 |
1211 | @@ -1,67 +0,0 @@ |
1212 | -from dingus import DingusTestCase, DontCare |
1213 | -import urllib2 |
1214 | -from urllib2 import urlopen |
1215 | - |
1216 | - |
1217 | -# We want to unit test the urlopen function. It's very small (as you can see |
1218 | -# by looking at the source at ${PYTHON_INSTALL}/lib/python2.5/urllib2.py |
1219 | -# |
1220 | -# (This example assumes Python 2.5. Hopefully it also works for your version.) |
1221 | -# |
1222 | -# Dingus allows us to test urlopen without actually touching the network, or |
1223 | -# any other classes and functions at all. When we define the test class, we |
1224 | -# inherit from "DingusTestCase(urlopen)". DingusTestCase will define setup and |
1225 | -# teardown method that replace every object in urllib2 with a dingus |
1226 | -# (except urlopen, which is the "object under test". It does this by looking |
1227 | -# at the module that urlopen was defined in, making a backup copy of its |
1228 | -# contents, then replacing everything with a dingus. So, instead of making |
1229 | -# network connections as it usually would, urlopen will be making calls into |
1230 | -# the dinguses, which will record the calls so that we can make assertions |
1231 | -# about them later. |
1232 | -class WhenOpeningURLs(DingusTestCase(urlopen)): |
1233 | - def setup(self): |
1234 | - # We have to call DingusTestCase's setup method so that it can |
1235 | - # modify the urllib2 module's contents. |
1236 | - super(WhenOpeningURLs, self).setup() |
1237 | - |
1238 | - # We set up the object under test here by calling urlopen with a URL. |
1239 | - self.url = 'http://www.example.com' |
1240 | - self.opened_url = urlopen(self.url) |
1241 | - |
1242 | - # First, we expect urlopen to try to open the URL. |
1243 | - def should_open_provided_url(self): |
1244 | - # Normally urlopen would use a prexisting "opener" object that would |
1245 | - # touch the network, disk, etc., but DingusTestCase has replaced it |
1246 | - # with a dingus. We first grab that _opener object so we can make |
1247 | - # assertions about it. |
1248 | - opener = urllib2._opener |
1249 | - |
1250 | - # We want to assert that urlopen should call "open" on the opener, |
1251 | - # passing the URL we gave it. "open" also takes another argument, but |
1252 | - # we don't care about that for this test. We pass in DontCare for |
1253 | - # things we don't care about, and the dingus will ignore that argument |
1254 | - # for the purposes of this assertion. |
1255 | - assert opener.calls('open', self.url, DontCare).one() |
1256 | - |
1257 | - # Note that we never told the _opener dingus that it should have an |
1258 | - # "open" method. A dingus has *all* methods - it will try to allow |
1259 | - # anything to be done to it. |
1260 | - |
1261 | - def should_return_opened_url(self): |
1262 | - # Now we want to assert that the opened object is returned to the |
1263 | - # caller. The line of code from urllib2 that we're testing is: |
1264 | - # return _opener.open(url, data) |
1265 | - # We need to make sure that urlopen returned the result of that. We do |
1266 | - # that by accessing _opener.open.return_value. _opener.open is the |
1267 | - # dingus that replaced the original _opener.open method. The |
1268 | - # return_value is a special attribute of all dinguses that gets |
1269 | - # returned when the dingus is called as a function. |
1270 | - assert self.opened_url is urllib2._opener.open.return_value |
1271 | - |
1272 | - # We could also define a teardown method for this test class, but that's |
1273 | - # rarely needed when writing fully isolated tests like this one. |
1274 | - # DingusTestCase does define a teardown method, though - it reverses the |
1275 | - # changes it made to the module under test, removing the dinguses and |
1276 | - # restoring the module's original contents. This class inherited it, so we |
1277 | - # don't have to call it manually. |
1278 | - |
1279 | |
1280 | === added directory 'patches' |
1281 | === added file 'patches/series' |
1282 | --- patches/series 1970-01-01 00:00:00 +0000 |
1283 | +++ patches/series 2011-10-20 19:36:43 +0000 |
1284 | @@ -0,0 +1,1 @@ |
1285 | +setup_cleanup |
1286 | |
1287 | === added file 'patches/setup_cleanup' |
1288 | --- patches/setup_cleanup 1970-01-01 00:00:00 +0000 |
1289 | +++ patches/setup_cleanup 2011-10-20 19:36:43 +0000 |
1290 | @@ -0,0 +1,12 @@ |
1291 | +Index: python-dingus-0.3.2/setup.py |
1292 | +=================================================================== |
1293 | +--- python-dingus-0.3.2.orig/setup.py 2011-08-07 09:37:57.900948735 +0100 |
1294 | ++++ python-dingus-0.3.2/setup.py 2011-08-07 09:38:03.340954228 +0100 |
1295 | +@@ -7,7 +7,6 @@ |
1296 | + author='Gary Bernhardt', |
1297 | + author_email='gary.bernhardt@gmail.com', |
1298 | + py_modules=['dingus'], |
1299 | +- data_files=[('', ['README.txt'])], |
1300 | + license='MIT', |
1301 | + url='https://github.com/garybernhardt/dingus', |
1302 | + keywords='testing test mocking mock double stub fake record assert', |
1303 | |
1304 | === modified file 'setup.py' |
1305 | --- setup.py 2009-10-22 11:00:55 +0000 |
1306 | +++ setup.py 2011-10-20 19:36:43 +0000 |
1307 | @@ -1,15 +1,16 @@ |
1308 | -from setuptools import setup, find_packages |
1309 | +from setuptools import setup |
1310 | |
1311 | setup(name='dingus', |
1312 | - version='0.1', |
1313 | + version='0.3.2', |
1314 | description='A record-then-assert mocking library', |
1315 | + long_description=file('README.txt').read(), |
1316 | author='Gary Bernhardt', |
1317 | author_email='gary.bernhardt@gmail.com', |
1318 | py_modules=['dingus'], |
1319 | license='MIT', |
1320 | - url='http://bitbucket.org/garybernhardt/dingus', |
1321 | - keywords='testing test mocking mock double stub fake', |
1322 | - classifiers=["Development Status :: 2 - Pre-Alpha", |
1323 | + url='https://github.com/garybernhardt/dingus', |
1324 | + keywords='testing test mocking mock double stub fake record assert', |
1325 | + classifiers=["Development Status :: 4 - Beta", |
1326 | "Intended Audience :: Developers", |
1327 | "License :: OSI Approved :: MIT License", |
1328 | "Operating System :: OS Independent", |
1329 | @@ -17,3 +18,4 @@ |
1330 | "Topic :: Software Development :: Testing", |
1331 | ], |
1332 | ) |
1333 | + |
1334 | |
1335 | === removed directory 'tests' |
1336 | === removed file 'tests/__init__.py' |
1337 | === removed file 'tests/runtests.py' |
1338 | --- tests/runtests.py 2009-10-22 11:00:55 +0000 |
1339 | +++ tests/runtests.py 1970-01-01 00:00:00 +0000 |
1340 | @@ -1,14 +0,0 @@ |
1341 | -#!/usr/bin/env python |
1342 | - |
1343 | -import sys |
1344 | - |
1345 | -import nose |
1346 | - |
1347 | - |
1348 | -if __name__ == '__main__': |
1349 | - nose_args = sys.argv + [r'-m', |
1350 | - r'((?:^|[b_.-])(:?[Tt]est|When|should))', |
1351 | - r'--with-doctest', |
1352 | - r'--doctest-extension='] |
1353 | - nose.run(argv=nose_args) |
1354 | - |
1355 | |
1356 | === removed file 'tests/test_call.py' |
1357 | --- tests/test_call.py 2009-10-22 11:00:55 +0000 |
1358 | +++ tests/test_call.py 1970-01-01 00:00:00 +0000 |
1359 | @@ -1,22 +0,0 @@ |
1360 | -from dingus import Call |
1361 | - |
1362 | - |
1363 | -class WhenInstantiated: |
1364 | - def setup(self): |
1365 | - self.call = Call('test name', |
1366 | - 'test args', |
1367 | - 'test kwargs', |
1368 | - 'test return_value') |
1369 | - |
1370 | - def should_have_name(self): |
1371 | - assert self.call.name == 'test name' |
1372 | - |
1373 | - def should_have_args(self): |
1374 | - assert self.call.args == 'test args' |
1375 | - |
1376 | - def should_have_kwargs(self): |
1377 | - assert self.call.kwargs == 'test kwargs' |
1378 | - |
1379 | - def should_have_return_value(self): |
1380 | - assert self.call.return_value == 'test return_value' |
1381 | - |
1382 | |
1383 | === removed file 'tests/test_call_list.py' |
1384 | --- tests/test_call_list.py 2009-10-22 11:00:55 +0000 |
1385 | +++ tests/test_call_list.py 1970-01-01 00:00:00 +0000 |
1386 | @@ -1,113 +0,0 @@ |
1387 | -from nose.tools import assert_raises |
1388 | - |
1389 | -from dingus import Call, CallList, DontCare |
1390 | - |
1391 | - |
1392 | -class WhenEmpty: |
1393 | - def setup(self): |
1394 | - self.calls = CallList() |
1395 | - |
1396 | - def should_be_false_in_boolean_context(self): |
1397 | - assert not self.calls |
1398 | - |
1399 | - def should_not_have_one_element(self): |
1400 | - assert not self.calls.one() |
1401 | - |
1402 | - |
1403 | -class WhenPopulatedWithACall: |
1404 | - def setup(self): |
1405 | - self.calls = CallList() |
1406 | - self.calls.append(Call('test name', |
1407 | - 'test args', |
1408 | - 'test kwargs', |
1409 | - 'test return_value')) |
1410 | - |
1411 | - def should_be_true_in_boolean_context(self): |
1412 | - assert self.calls |
1413 | - |
1414 | - def should_have_exactly_one_call(self): |
1415 | - assert self.calls.one() |
1416 | - |
1417 | - def should_not_return_call_when_querying_for_wrong_name(self): |
1418 | - assert not self.calls('wrong name') |
1419 | - |
1420 | - def should_not_return_call_when_querying_for_wrong_args(self): |
1421 | - assert not self.calls('test name', 'wrong args') |
1422 | - |
1423 | - def should_not_return_call_when_querying_for_wrong_kwargs(self): |
1424 | - assert not self.calls('test name', wrong_key='wrong_value') |
1425 | - |
1426 | - |
1427 | -class WhenPopulatedWithTwoCalls: |
1428 | - def setup(self): |
1429 | - self.calls = CallList() |
1430 | - for _ in range(2): |
1431 | - self.calls.append(Call('name', (), {}, None)) |
1432 | - |
1433 | - def should_not_have_one_element(self): |
1434 | - assert not self.calls.one() |
1435 | - |
1436 | - |
1437 | -class WhenTwoCallsDifferByName: |
1438 | - def setup(self): |
1439 | - self.calls = CallList() |
1440 | - self.calls.append(Call('name1', (), {}, None)) |
1441 | - self.calls.append(Call('name2', (), {}, None)) |
1442 | - |
1443 | - def should_filter_on_name(self): |
1444 | - assert self.calls('name1').one() |
1445 | - |
1446 | - |
1447 | -class WhenTwoCallsDifferByArgs: |
1448 | - def setup(self): |
1449 | - self.calls = CallList() |
1450 | - self.calls.append(Call('name', ('arg1',), {}, None)) |
1451 | - self.calls.append(Call('name', ('arg2',), {}, None)) |
1452 | - |
1453 | - def should_filter_on_args(self): |
1454 | - assert self.calls('name', 'arg1').one() |
1455 | - |
1456 | - |
1457 | -class WhenCallsDifferInAllWays: |
1458 | - def setup(self): |
1459 | - self.calls = CallList() |
1460 | - for name in ('name1', 'name2'): |
1461 | - for args in (('arg1',), ('arg2',)): |
1462 | - for kwargs in ({'kwarg1': 1}, {'kwarg2': 2}): |
1463 | - call = Call(name, args, kwargs, 'return value') |
1464 | - self.calls.append(call) |
1465 | - self.call_count = len(self.calls) |
1466 | - |
1467 | - def should_filter_on_name(self): |
1468 | - assert len(self.calls('name1')) == self.call_count / 2 |
1469 | - |
1470 | - def should_filter_on_args(self): |
1471 | - assert len(self.calls('name1', 'arg1')) == self.call_count / 4 |
1472 | - |
1473 | - def should_filter_on_kwargs(self): |
1474 | - assert len(self.calls('name1', kwarg1=1)) == self.call_count / 4 |
1475 | - |
1476 | - |
1477 | -class WhenCallsHaveMultipleArguments: |
1478 | - def setup(self): |
1479 | - self.calls = CallList() |
1480 | - for arg1 in (1, 2): |
1481 | - for arg2 in (1, 2): |
1482 | - self.calls.append(Call('name', |
1483 | - (arg1, arg2), |
1484 | - {}, |
1485 | - 'return_value')) |
1486 | - self.call_count = len(self.calls) |
1487 | - |
1488 | - def should_be_able_to_ignore_all_arguments(self): |
1489 | - assert len(self.calls('name', DontCare, DontCare)) == self.call_count |
1490 | - |
1491 | - def should_be_able_to_ignore_first_argument(self): |
1492 | - assert len(self.calls('name', 1, DontCare)) == self.call_count / 2 |
1493 | - |
1494 | - def should_be_able_to_ignore_second_argument(self): |
1495 | - assert len(self.calls('name', DontCare, 1)) == self.call_count / 2 |
1496 | - |
1497 | - def should_be_able_to_specify_both_arguments(self): |
1498 | - assert len(self.calls('name', 1, 1)) == self.call_count / 4 |
1499 | - |
1500 | |
1501 | === removed file 'tests/test_dingus.py' |
1502 | --- tests/test_dingus.py 2009-10-22 11:00:55 +0000 |
1503 | +++ tests/test_dingus.py 1970-01-01 00:00:00 +0000 |
1504 | @@ -1,290 +0,0 @@ |
1505 | -import operator |
1506 | -from functools import partial |
1507 | - |
1508 | -from nose.tools import assert_raises |
1509 | - |
1510 | -from dingus import Dingus |
1511 | - |
1512 | - |
1513 | -class WhenCreatingNewDingus: |
1514 | - def setup(self): |
1515 | - self.dingus = Dingus() |
1516 | - |
1517 | - def should_not_have_any_recorded_calls(self): |
1518 | - assert not self.dingus.calls() |
1519 | - |
1520 | - def should_have_a_name(self): |
1521 | - assert self.dingus.__name__ == 'dingus_%i' % id(self.dingus) |
1522 | - |
1523 | - |
1524 | -class WhenCreatingNewDingusWithAName: |
1525 | - def setup(self): |
1526 | - self.dingus = Dingus('something') |
1527 | - |
1528 | - def should_have_a_name(self): |
1529 | - assert self.dingus.__name__ == 'something' |
1530 | - |
1531 | - def should_include_name_in_repr(self): |
1532 | - assert repr(self.dingus) == '<Dingus something>' |
1533 | - |
1534 | - def should_include_attribute_name_in_childrens_repr(self): |
1535 | - assert repr(self.dingus.child) == '<Dingus something.child>' |
1536 | - |
1537 | - def should_include_attribute_name_in_repr_of_children_from_calling(self): |
1538 | - assert repr(self.dingus()) == '<Dingus something()>' |
1539 | - |
1540 | - def should_include_attribute_name_in_repr_of_children_from_indexing(self): |
1541 | - assert repr(self.dingus()['5']) == '<Dingus something()[5]>' |
1542 | - |
1543 | - |
1544 | -class WhenCallingDingusAsFunction: |
1545 | - def setup(self): |
1546 | - self.dingus = Dingus() |
1547 | - self.dingus('arg', kwarg=None) |
1548 | - |
1549 | - def should_record_call(self): |
1550 | - assert self.dingus.calls() |
1551 | - |
1552 | - def should_have_exactly_one_call(self): |
1553 | - assert self.dingus.calls().one() |
1554 | - |
1555 | - def should_record_args(self): |
1556 | - assert self.dingus.calls.one().args == ('arg',) |
1557 | - |
1558 | - def should_record_kwargs(self): |
1559 | - assert self.dingus.calls.one().kwargs == {'kwarg': None} |
1560 | - |
1561 | - |
1562 | -class WhenCallingAttributeChild: |
1563 | - def setup(self): |
1564 | - self.parent = Dingus() |
1565 | - self.child = self.parent.child |
1566 | - self.child('arg', kwarg=None) |
1567 | - |
1568 | - def should_record_call_on_child(self): |
1569 | - assert self.child.calls.one() |
1570 | - |
1571 | - def should_record_call_on_parent(self): |
1572 | - assert self.parent.calls('child').one() |
1573 | - |
1574 | - def should_record_args(self): |
1575 | - assert self.parent.calls('child').one().args == ('arg',) |
1576 | - |
1577 | - def should_record_kwargs(self): |
1578 | - assert self.parent.calls('child').one().kwargs == {'kwarg': None} |
1579 | - |
1580 | - |
1581 | -class WhenCallingAttributeGrandchild: |
1582 | - def setup(self): |
1583 | - self.grandparent = Dingus() |
1584 | - self.parent = self.grandparent.parent |
1585 | - self.child = self.parent.child |
1586 | - self.child('arg', kwarg=None) |
1587 | - |
1588 | - def should_not_record_call_on_grandparent(self): |
1589 | - assert not self.grandparent.calls('parent.child') |
1590 | - |
1591 | - def should_record_call_on_parent(self): |
1592 | - assert self.parent.calls('child').one() |
1593 | - |
1594 | - |
1595 | -class WhenCallingAttributesOfReturnedValues: |
1596 | - def setup(self): |
1597 | - self.grandparent = Dingus() |
1598 | - self.parent = self.grandparent() |
1599 | - self.child = self.parent.child |
1600 | - self.child('arg', kwarg=None) |
1601 | - |
1602 | - def should_record_call_on_grandparent(self): |
1603 | - assert self.grandparent.calls('()').one() |
1604 | - |
1605 | - def should_record_child_call_on_child(self): |
1606 | - assert self.child.calls('()').one() |
1607 | - |
1608 | - def should_record_child_call_on_parent(self): |
1609 | - assert self.parent.calls('child').one() |
1610 | - |
1611 | - def should_not_record_child_call_on_grandparent(self): |
1612 | - assert not self.grandparent.calls('().child') |
1613 | - |
1614 | - |
1615 | -class WhenCallingItemChild: |
1616 | - def should_record_call(self): |
1617 | - parent = Dingus() |
1618 | - parent['child']() |
1619 | - assert parent.calls('[child]').one() |
1620 | - |
1621 | - |
1622 | -class WhenCallingListItemOfDingus: |
1623 | - def setup(self): |
1624 | - self.parent = Dingus() |
1625 | - self.child = self.parent[0] |
1626 | - self.child() |
1627 | - |
1628 | - def should_record_call_on_parent(self): |
1629 | - assert self.parent.calls('[0]').one() |
1630 | - |
1631 | - def should_record_call_on_child(self): |
1632 | - assert self.child.calls('()').one() |
1633 | - |
1634 | - |
1635 | -class WhenAccessingMagicAttributes: |
1636 | - def should_raise_attribute_error_for_pyobjc_object(self): |
1637 | - # PyObjC uses __pyobjc_object__ to get an ObjC object from a Python |
1638 | - # object. Returning a Mock will cause a crash. |
1639 | - assert_raises(AttributeError, lambda: Dingus().__pyobjc_object__) |
1640 | - |
1641 | - |
1642 | -class WhenApplyingBinaryOperators: |
1643 | - operator_names = ['add', 'and_', 'div', 'lshift', 'mod', 'mul', 'or_', |
1644 | - 'pow', 'rshift', 'sub', 'xor'] |
1645 | - |
1646 | - def assert_returns_new_dingus(self, op): |
1647 | - left, right = Dingus.many(2) |
1648 | - result = op(left, right) |
1649 | - assert result is not left and result is not right |
1650 | - |
1651 | - def should_always_return_new_dingus(self): |
1652 | - for operator_name in self.operator_names: |
1653 | - op = getattr(operator, operator_name) |
1654 | - yield self.assert_returns_new_dingus, op |
1655 | - |
1656 | - |
1657 | -class WhenComputingLength: |
1658 | - def should_be_one(self): |
1659 | - assert len(Dingus()) == 1 |
1660 | - |
1661 | - |
1662 | -class WhenAccessingReturnValueBeforeCalling: |
1663 | - def setup(self): |
1664 | - self.dingus = Dingus() |
1665 | - |
1666 | - def should_have_return_value_before_calling(self): |
1667 | - assert self.dingus.return_value |
1668 | - |
1669 | - def should_return_same_return_value_that_existed_before_calling(self): |
1670 | - original_return_value = self.dingus.return_value |
1671 | - return_value = self.dingus() |
1672 | - assert return_value is original_return_value |
1673 | - |
1674 | - def should_have_same_return_value_before_and_after_calling(self): |
1675 | - original_return_value = self.dingus.return_value |
1676 | - self.dingus() |
1677 | - assert self.dingus.return_value is original_return_value |
1678 | - |
1679 | - |
1680 | -class WhenSettingReturnValue: |
1681 | - def setup(self): |
1682 | - self.dingus = Dingus() |
1683 | - self.return_value = 5 |
1684 | - self.dingus.return_value = self.return_value |
1685 | - |
1686 | - def should_return_assigned_return_value(self): |
1687 | - assert self.dingus() is self.return_value |
1688 | - |
1689 | - def should_have_same_return_value_after_calling(self): |
1690 | - self.dingus() |
1691 | - assert self.dingus.return_value is self.return_value |
1692 | - |
1693 | - |
1694 | -class WhenSettingAttributes: |
1695 | - def setup(self): |
1696 | - self.dingus = Dingus() |
1697 | - self.attr = Dingus() |
1698 | - self.dingus.attr = self.attr |
1699 | - |
1700 | - def should_remember_attr(self): |
1701 | - assert self.dingus.attr is self.attr |
1702 | - |
1703 | - def should_not_return_attributes_as_items(self): |
1704 | - assert self.dingus['attr'] is not self.attr |
1705 | - |
1706 | - def should_return_distinct_dinguses_for_different_attributes(self): |
1707 | - assert self.dingus['attr'] is not self.dingus['attr2'] |
1708 | - |
1709 | - |
1710 | -class WhenAccessingItems: |
1711 | - def should_log_access(self): |
1712 | - dingus = Dingus() |
1713 | - dingus['item'] |
1714 | - assert dingus.calls('__getitem__', 'item').one() |
1715 | - |
1716 | - def should_log_access_after_initial_item_read(self): |
1717 | - dingus = Dingus() |
1718 | - for _ in range(2): |
1719 | - dingus['item'] |
1720 | - assert len(dingus.calls('__getitem__', 'item')) == 2 |
1721 | - |
1722 | - |
1723 | -class WhenSettingItems: |
1724 | - def setup(self): |
1725 | - self.dingus = Dingus() |
1726 | - self.item = Dingus() |
1727 | - self.dingus['item'] = self.item |
1728 | - |
1729 | - def should_remember_item(self): |
1730 | - assert self.dingus['item'] is self.item |
1731 | - |
1732 | - def should_log_access(self): |
1733 | - assert self.dingus.calls('__setitem__', 'item', self.item).one() |
1734 | - |
1735 | - def should_not_return_items_as_attributes(self): |
1736 | - assert self.dingus.item is not self.item |
1737 | - |
1738 | - def should_return_distinct_dinguses_for_different_items(self): |
1739 | - assert self.dingus['item'] is not self.dingus['item2'] |
1740 | - |
1741 | - |
1742 | -class WhenNothingIsSet: |
1743 | - def setup(self): |
1744 | - self.attribute_name = 'attr' |
1745 | - self.dingus = Dingus() |
1746 | - |
1747 | - def should_be_able_to_access_attributes_that_dont_exist(self): |
1748 | - assert isinstance(getattr(self.dingus, self.attribute_name), Dingus) |
1749 | - |
1750 | - def should_get_same_attribute_on_every_access(self): |
1751 | - get_attr = lambda: getattr(self.dingus, self.attribute_name) |
1752 | - assert get_attr() is get_attr() |
1753 | - |
1754 | - def should_be_able_to_acces_items_that_dont_exist(self): |
1755 | - assert isinstance(self.dingus[self.attribute_name], Dingus) |
1756 | - |
1757 | - def should_get_same_item_on_every_access(self): |
1758 | - get_item = lambda: self.dingus[self.attribute_name] |
1759 | - assert get_item() is get_item() |
1760 | - |
1761 | - def should_have_attributes_that_have_not_been_set(self): |
1762 | - assert hasattr(self.dingus, self.attribute_name) |
1763 | - |
1764 | - |
1765 | -class WhenSpecifyingAttributesViaKeywordArguments: |
1766 | - def should_set_specified_attributes(self): |
1767 | - attr = Dingus() |
1768 | - object_with_attr = Dingus(attr=attr) |
1769 | - assert object_with_attr.attr is attr |
1770 | - |
1771 | - |
1772 | -class WhenCallingInitMethod: |
1773 | - def should_record_call(self): |
1774 | - dingus = Dingus() |
1775 | - dingus.__init__() |
1776 | - assert dingus.calls('__init__').one() |
1777 | - |
1778 | - |
1779 | -class WhenCreatingMultipleDinguses: |
1780 | - def should_return_a_dingus_when_asked_for_one(self): |
1781 | - assert len(Dingus.many(1)) == 1 |
1782 | - |
1783 | - def should_return_two_dinguses_when_asked_for_two(self): |
1784 | - assert len(Dingus.many(2)) == 2 |
1785 | - |
1786 | - def should_return_dingus_instances_when_asked_for_multiple(self): |
1787 | - assert all(isinstance(dingus, Dingus) for dingus in Dingus.many(2)) |
1788 | - |
1789 | - def should_return_dinguses_in_tuple(self): |
1790 | - assert isinstance(Dingus.many(2), tuple) |
1791 | - |
1792 | - def should_return_nothing_when_asked_for_zero_dinguses(self): |
1793 | - assert not Dingus.many(0) |
1794 | - |
1795 | |
1796 | === removed file 'tests/test_dingus_test_case.py' |
1797 | --- tests/test_dingus_test_case.py 2009-10-22 11:00:55 +0000 |
1798 | +++ tests/test_dingus_test_case.py 1970-01-01 00:00:00 +0000 |
1799 | @@ -1,65 +0,0 @@ |
1800 | -import sys |
1801 | -import new |
1802 | - |
1803 | -from dingus import DingusTestCase, Dingus |
1804 | - |
1805 | - |
1806 | -class WhenRunningTestCaseOnAModule(object): |
1807 | - def setup(self): |
1808 | - self.module = self._create_fake_module() |
1809 | - self.class_under_test = self._create_class_under_test() |
1810 | - self.test_case_class = self._create_test_case_class() |
1811 | - |
1812 | - def _create_fake_module(self): |
1813 | - module = new.module('test_module') |
1814 | - module.value = 'value' |
1815 | - sys.modules[module.__name__] = module |
1816 | - return module |
1817 | - |
1818 | - def _create_class_under_test(self): |
1819 | - class ClassThatWouldBeUnderTest: |
1820 | - pass |
1821 | - ClassThatWouldBeUnderTest.__module__ = self.module.__name__ |
1822 | - self.module.ClassThatWouldBeUnderTest = ClassThatWouldBeUnderTest |
1823 | - return ClassThatWouldBeUnderTest |
1824 | - |
1825 | - def _create_test_case_class(self): |
1826 | - class TestCaseClass(DingusTestCase(self.class_under_test)): |
1827 | - pass |
1828 | - return TestCaseClass |
1829 | - |
1830 | - def teardown(self): |
1831 | - del sys.modules[self.module.__name__] |
1832 | - |
1833 | - |
1834 | -class WhenCallingSetupFunction(WhenRunningTestCaseOnAModule): |
1835 | - def setup(self): |
1836 | - super(WhenCallingSetupFunction, self).setup() |
1837 | - self.test_case_instance = self.test_case_class() |
1838 | - self.test_case_instance.setup() |
1839 | - |
1840 | - def teardown(self): |
1841 | - self.test_case_instance.teardown() |
1842 | - super(WhenCallingSetupFunction, self).teardown() |
1843 | - |
1844 | - def should_replace_module_attributes(self): |
1845 | - assert isinstance(self.module.value, Dingus) |
1846 | - |
1847 | - def should_leave_class_under_test_intact(self): |
1848 | - assert self.module.ClassThatWouldBeUnderTest is self.class_under_test |
1849 | - |
1850 | - |
1851 | -class WhenCallingTeardownFunction(WhenRunningTestCaseOnAModule): |
1852 | - def setup(self): |
1853 | - super(WhenCallingTeardownFunction, self).setup() |
1854 | - self.test_case_object = self.test_case_class() |
1855 | - self.original_module_dict = self.module.__dict__.copy() |
1856 | - self.test_case_object.setup() |
1857 | - self.test_case_object.teardown() |
1858 | - |
1859 | - def should_restore_module_attributes(self): |
1860 | - assert self.module.value is 'value' |
1861 | - |
1862 | - def should_leave_globals_as_they_were_before_dingusing(self): |
1863 | - assert self.module.__dict__ == self.original_module_dict |
1864 | - |
1865 | |
1866 | === removed file 'tests/test_exception_raiser.py' |
1867 | --- tests/test_exception_raiser.py 2009-10-22 11:00:55 +0000 |
1868 | +++ tests/test_exception_raiser.py 1970-01-01 00:00:00 +0000 |
1869 | @@ -1,20 +0,0 @@ |
1870 | -from nose.tools import assert_raises |
1871 | -from nose.tools import raises |
1872 | - |
1873 | -from dingus import exception_raiser |
1874 | - |
1875 | - |
1876 | -class WhenCalled: |
1877 | - def setup(self): |
1878 | - exception = ValueError() |
1879 | - self.raise_exception = exception_raiser(exception) |
1880 | - |
1881 | - def should_raise_provided_exception(self): |
1882 | - assert_raises(ValueError, self.raise_exception) |
1883 | - |
1884 | - def should_take_args(self): |
1885 | - assert_raises(ValueError, self.raise_exception, 1) |
1886 | - |
1887 | - def should_take_kwargs(self): |
1888 | - assert_raises(ValueError, self.raise_exception, kwarg=1) |
1889 | - |
Good work! Thanks! Do you think you can forward the changes to Debian?