OLD | NEW |
| (Empty) |
1 # -*- test-case-name: twisted.test.test_util -*- | |
2 # Copyright (c) 2001-2008 Twisted Matrix Laboratories. | |
3 # See LICENSE for details. | |
4 | |
5 import os.path, sys | |
6 import shutil, errno | |
7 try: | |
8 import pwd, grp | |
9 except ImportError: | |
10 pwd = grp = None | |
11 | |
12 from twisted.trial import unittest | |
13 | |
14 from twisted.python import util | |
15 from twisted.internet import reactor | |
16 from twisted.internet.interfaces import IReactorProcess | |
17 from twisted.internet.protocol import ProcessProtocol | |
18 from twisted.internet.defer import Deferred | |
19 from twisted.internet.error import ProcessDone | |
20 | |
21 | |
22 class UtilTestCase(unittest.TestCase): | |
23 | |
24 def testUniq(self): | |
25 l = ["a", 1, "ab", "a", 3, 4, 1, 2, 2, 4, 6] | |
26 self.assertEquals(util.uniquify(l), ["a", 1, "ab", 3, 4, 2, 6]) | |
27 | |
28 def testRaises(self): | |
29 self.failUnless(util.raises(ZeroDivisionError, divmod, 1, 0)) | |
30 self.failIf(util.raises(ZeroDivisionError, divmod, 0, 1)) | |
31 | |
32 try: | |
33 util.raises(TypeError, divmod, 1, 0) | |
34 except ZeroDivisionError: | |
35 pass | |
36 else: | |
37 raise unittest.FailTest, "util.raises didn't raise when it should ha
ve" | |
38 | |
39 def testUninterruptably(self): | |
40 def f(a, b): | |
41 self.calls += 1 | |
42 exc = self.exceptions.pop() | |
43 if exc is not None: | |
44 raise exc(errno.EINTR, "Interrupted system call!") | |
45 return a + b | |
46 | |
47 self.exceptions = [None] | |
48 self.calls = 0 | |
49 self.assertEquals(util.untilConcludes(f, 1, 2), 3) | |
50 self.assertEquals(self.calls, 1) | |
51 | |
52 self.exceptions = [None, OSError, IOError] | |
53 self.calls = 0 | |
54 self.assertEquals(util.untilConcludes(f, 2, 3), 5) | |
55 self.assertEquals(self.calls, 3) | |
56 | |
57 def testUnsignedID(self): | |
58 util.id = lambda x: x | |
59 try: | |
60 for i in range(1, 100): | |
61 self.assertEquals(util.unsignedID(i), i) | |
62 top = (sys.maxint + 1L) * 2L | |
63 for i in range(-100, -1): | |
64 self.assertEquals(util.unsignedID(i), top + i) | |
65 finally: | |
66 del util.id | |
67 | |
68 def testNameToLabel(self): | |
69 """ | |
70 Test the various kinds of inputs L{nameToLabel} supports. | |
71 """ | |
72 nameData = [ | |
73 ('f', 'F'), | |
74 ('fo', 'Fo'), | |
75 ('foo', 'Foo'), | |
76 ('fooBar', 'Foo Bar'), | |
77 ('fooBarBaz', 'Foo Bar Baz'), | |
78 ] | |
79 for inp, out in nameData: | |
80 got = util.nameToLabel(inp) | |
81 self.assertEquals( | |
82 got, out, | |
83 "nameToLabel(%r) == %r != %r" % (inp, got, out)) | |
84 | |
85 | |
86 def test_uidFromNumericString(self): | |
87 """ | |
88 When L{uidFromString} is called with a base-ten string representation | |
89 of an integer, it returns the integer. | |
90 """ | |
91 self.assertEqual(util.uidFromString("100"), 100) | |
92 | |
93 | |
94 def test_uidFromUsernameString(self): | |
95 """ | |
96 When L{uidFromString} is called with a base-ten string representation | |
97 of an integer, it returns the integer. | |
98 """ | |
99 pwent = pwd.getpwuid(os.getuid()) | |
100 self.assertEqual(util.uidFromString(pwent.pw_name), pwent.pw_uid) | |
101 if pwd is None: | |
102 test_uidFromUsernameString.skip = ( | |
103 "Username/UID conversion requires the pwd module.") | |
104 | |
105 | |
106 def test_gidFromNumericString(self): | |
107 """ | |
108 When L{gidFromString} is called with a base-ten string representation | |
109 of an integer, it returns the integer. | |
110 """ | |
111 self.assertEqual(util.gidFromString("100"), 100) | |
112 | |
113 | |
114 def test_gidFromGroupnameString(self): | |
115 """ | |
116 When L{gidFromString} is called with a base-ten string representation | |
117 of an integer, it returns the integer. | |
118 """ | |
119 grent = grp.getgrgid(os.getgid()) | |
120 self.assertEqual(util.gidFromString(grent.gr_name), grent.gr_gid) | |
121 if grp is None: | |
122 test_gidFromGroupnameString.skip = ( | |
123 "Group Name/GID conversion requires the grp module.") | |
124 | |
125 | |
126 | |
127 class TestMergeFunctionMetadata(unittest.TestCase): | |
128 """ | |
129 Tests for L{mergeFunctionMetadata}. | |
130 """ | |
131 | |
132 def test_mergedFunctionBehavesLikeMergeTarget(self): | |
133 """ | |
134 After merging C{foo}'s data into C{bar}, the returned function behaves | |
135 as if it is C{bar}. | |
136 """ | |
137 foo_object = object() | |
138 bar_object = object() | |
139 | |
140 def foo(): | |
141 return foo_object | |
142 | |
143 def bar(x, y, (a, b), c=10, *d, **e): | |
144 return bar_object | |
145 | |
146 baz = util.mergeFunctionMetadata(foo, bar) | |
147 self.assertIdentical(baz(1, 2, (3, 4), quux=10), bar_object) | |
148 | |
149 | |
150 def test_moduleIsMerged(self): | |
151 """ | |
152 Merging C{foo} into C{bar} returns a function with C{foo}'s | |
153 C{__module__}. | |
154 """ | |
155 def foo(): | |
156 pass | |
157 | |
158 def bar(): | |
159 pass | |
160 bar.__module__ = 'somewhere.else' | |
161 | |
162 baz = util.mergeFunctionMetadata(foo, bar) | |
163 self.assertEqual(baz.__module__, foo.__module__) | |
164 | |
165 | |
166 def test_docstringIsMerged(self): | |
167 """ | |
168 Merging C{foo} into C{bar} returns a function with C{foo}'s docstring. | |
169 """ | |
170 | |
171 def foo(): | |
172 """ | |
173 This is foo. | |
174 """ | |
175 | |
176 def bar(): | |
177 """ | |
178 This is bar. | |
179 """ | |
180 | |
181 baz = util.mergeFunctionMetadata(foo, bar) | |
182 self.assertEqual(baz.__doc__, foo.__doc__) | |
183 | |
184 | |
185 def test_nameIsMerged(self): | |
186 """ | |
187 Merging C{foo} into C{bar} returns a function with C{foo}'s name. | |
188 """ | |
189 | |
190 def foo(): | |
191 pass | |
192 | |
193 def bar(): | |
194 pass | |
195 | |
196 baz = util.mergeFunctionMetadata(foo, bar) | |
197 self.assertEqual(baz.__name__, foo.__name__) | |
198 | |
199 | |
200 def test_instanceDictionaryIsMerged(self): | |
201 """ | |
202 Merging C{foo} into C{bar} returns a function with C{bar}'s | |
203 dictionary, updated by C{foo}'s. | |
204 """ | |
205 | |
206 def foo(): | |
207 pass | |
208 foo.a = 1 | |
209 foo.b = 2 | |
210 | |
211 def bar(): | |
212 pass | |
213 bar.b = 3 | |
214 bar.c = 4 | |
215 | |
216 baz = util.mergeFunctionMetadata(foo, bar) | |
217 self.assertEqual(foo.a, baz.a) | |
218 self.assertEqual(foo.b, baz.b) | |
219 self.assertEqual(bar.c, baz.c) | |
220 | |
221 | |
222 | |
223 class OrderedDictTest(unittest.TestCase): | |
224 def testOrderedDict(self): | |
225 d = util.OrderedDict() | |
226 d['a'] = 'b' | |
227 d['b'] = 'a' | |
228 d[3] = 12 | |
229 d[1234] = 4321 | |
230 self.assertEquals(repr(d), "{'a': 'b', 'b': 'a', 3: 12, 1234: 4321}") | |
231 self.assertEquals(d.values(), ['b', 'a', 12, 4321]) | |
232 del d[3] | |
233 self.assertEquals(repr(d), "{'a': 'b', 'b': 'a', 1234: 4321}") | |
234 self.assertEquals(d, {'a': 'b', 'b': 'a', 1234:4321}) | |
235 self.assertEquals(d.keys(), ['a', 'b', 1234]) | |
236 self.assertEquals(list(d.iteritems()), | |
237 [('a', 'b'), ('b','a'), (1234, 4321)]) | |
238 item = d.popitem() | |
239 self.assertEquals(item, (1234, 4321)) | |
240 | |
241 def testInitialization(self): | |
242 d = util.OrderedDict({'monkey': 'ook', | |
243 'apple': 'red'}) | |
244 self.failUnless(d._order) | |
245 | |
246 d = util.OrderedDict(((1,1),(3,3),(2,2),(0,0))) | |
247 self.assertEquals(repr(d), "{1: 1, 3: 3, 2: 2, 0: 0}") | |
248 | |
249 class InsensitiveDictTest(unittest.TestCase): | |
250 def testPreserve(self): | |
251 InsensitiveDict=util.InsensitiveDict | |
252 dct=InsensitiveDict({'Foo':'bar', 1:2, 'fnz':{1:2}}, preserve=1) | |
253 self.assertEquals(dct['fnz'], {1:2}) | |
254 self.assertEquals(dct['foo'], 'bar') | |
255 self.assertEquals(dct.copy(), dct) | |
256 self.assertEquals(dct['foo'], dct.get('Foo')) | |
257 assert 1 in dct and 'foo' in dct | |
258 self.assertEquals(eval(repr(dct)), dct) | |
259 keys=['Foo', 'fnz', 1] | |
260 for x in keys: | |
261 assert x in dct.keys() | |
262 assert (x, dct[x]) in dct.items() | |
263 self.assertEquals(len(keys), len(dct)) | |
264 del dct[1] | |
265 del dct['foo'] | |
266 | |
267 def testNoPreserve(self): | |
268 InsensitiveDict=util.InsensitiveDict | |
269 dct=InsensitiveDict({'Foo':'bar', 1:2, 'fnz':{1:2}}, preserve=0) | |
270 keys=['foo', 'fnz', 1] | |
271 for x in keys: | |
272 assert x in dct.keys() | |
273 assert (x, dct[x]) in dct.items() | |
274 self.assertEquals(len(keys), len(dct)) | |
275 del dct[1] | |
276 del dct['foo'] | |
277 | |
278 | |
279 | |
280 | |
281 class PasswordTestingProcessProtocol(ProcessProtocol): | |
282 """ | |
283 Write the string C{"secret\n"} to a subprocess and then collect all of | |
284 its output and fire a Deferred with it when the process ends. | |
285 """ | |
286 def connectionMade(self): | |
287 self.output = [] | |
288 self.transport.write('secret\n') | |
289 | |
290 def childDataReceived(self, fd, output): | |
291 self.output.append((fd, output)) | |
292 | |
293 def processEnded(self, reason): | |
294 self.finished.callback((reason, self.output)) | |
295 | |
296 | |
297 class GetPasswordTest(unittest.TestCase): | |
298 if not IReactorProcess.providedBy(reactor): | |
299 skip = "Process support required to test getPassword" | |
300 | |
301 def test_stdin(self): | |
302 """ | |
303 Making sure getPassword accepts a password from standard input by | |
304 running a child process which uses getPassword to read in a string | |
305 which it then writes it out again. Write a string to the child | |
306 process and then read one and make sure it is the right string. | |
307 """ | |
308 p = PasswordTestingProcessProtocol() | |
309 p.finished = Deferred() | |
310 reactor.spawnProcess( | |
311 p, | |
312 sys.executable, | |
313 [sys.executable, | |
314 '-c', | |
315 ('import sys\n' | |
316 'from twisted.python.util import getPassword\n' | |
317 'sys.stdout.write(getPassword())\n' | |
318 'sys.stdout.flush()\n')], | |
319 env={'PYTHONPATH': os.pathsep.join(sys.path)}) | |
320 | |
321 def processFinished((reason, output)): | |
322 reason.trap(ProcessDone) | |
323 self.assertIn((1, 'secret'), output) | |
324 | |
325 return p.finished.addCallback(processFinished) | |
326 | |
327 | |
328 | |
329 class SearchUpwardsTest(unittest.TestCase): | |
330 def testSearchupwards(self): | |
331 os.makedirs('searchupwards/a/b/c') | |
332 file('searchupwards/foo.txt', 'w').close() | |
333 file('searchupwards/a/foo.txt', 'w').close() | |
334 file('searchupwards/a/b/c/foo.txt', 'w').close() | |
335 os.mkdir('searchupwards/bar') | |
336 os.mkdir('searchupwards/bam') | |
337 os.mkdir('searchupwards/a/bar') | |
338 os.mkdir('searchupwards/a/b/bam') | |
339 actual=util.searchupwards('searchupwards/a/b/c', | |
340 files=['foo.txt'], | |
341 dirs=['bar', 'bam']) | |
342 expected=os.path.abspath('searchupwards') + os.sep | |
343 self.assertEqual(actual, expected) | |
344 shutil.rmtree('searchupwards') | |
345 actual=util.searchupwards('searchupwards/a/b/c', | |
346 files=['foo.txt'], | |
347 dirs=['bar', 'bam']) | |
348 expected=None | |
349 self.assertEqual(actual, expected) | |
350 | |
351 class Foo: | |
352 def __init__(self, x): | |
353 self.x = x | |
354 | |
355 class DSU(unittest.TestCase): | |
356 def testDSU(self): | |
357 L = [Foo(x) for x in range(20, 9, -1)] | |
358 L2 = util.dsu(L, lambda o: o.x) | |
359 self.assertEquals(range(10, 21), [o.x for o in L2]) | |
360 | |
361 class IntervalDifferentialTestCase(unittest.TestCase): | |
362 def testDefault(self): | |
363 d = iter(util.IntervalDifferential([], 10)) | |
364 for i in range(100): | |
365 self.assertEquals(d.next(), (10, None)) | |
366 | |
367 def testSingle(self): | |
368 d = iter(util.IntervalDifferential([5], 10)) | |
369 for i in range(100): | |
370 self.assertEquals(d.next(), (5, 0)) | |
371 | |
372 def testPair(self): | |
373 d = iter(util.IntervalDifferential([5, 7], 10)) | |
374 for i in range(100): | |
375 self.assertEquals(d.next(), (5, 0)) | |
376 self.assertEquals(d.next(), (2, 1)) | |
377 self.assertEquals(d.next(), (3, 0)) | |
378 self.assertEquals(d.next(), (4, 1)) | |
379 self.assertEquals(d.next(), (1, 0)) | |
380 self.assertEquals(d.next(), (5, 0)) | |
381 self.assertEquals(d.next(), (1, 1)) | |
382 self.assertEquals(d.next(), (4, 0)) | |
383 self.assertEquals(d.next(), (3, 1)) | |
384 self.assertEquals(d.next(), (2, 0)) | |
385 self.assertEquals(d.next(), (5, 0)) | |
386 self.assertEquals(d.next(), (0, 1)) | |
387 | |
388 def testTriple(self): | |
389 d = iter(util.IntervalDifferential([2, 4, 5], 10)) | |
390 for i in range(100): | |
391 self.assertEquals(d.next(), (2, 0)) | |
392 self.assertEquals(d.next(), (2, 0)) | |
393 self.assertEquals(d.next(), (0, 1)) | |
394 self.assertEquals(d.next(), (1, 2)) | |
395 self.assertEquals(d.next(), (1, 0)) | |
396 self.assertEquals(d.next(), (2, 0)) | |
397 self.assertEquals(d.next(), (0, 1)) | |
398 self.assertEquals(d.next(), (2, 0)) | |
399 self.assertEquals(d.next(), (0, 2)) | |
400 self.assertEquals(d.next(), (2, 0)) | |
401 self.assertEquals(d.next(), (0, 1)) | |
402 self.assertEquals(d.next(), (2, 0)) | |
403 self.assertEquals(d.next(), (1, 2)) | |
404 self.assertEquals(d.next(), (1, 0)) | |
405 self.assertEquals(d.next(), (0, 1)) | |
406 self.assertEquals(d.next(), (2, 0)) | |
407 self.assertEquals(d.next(), (2, 0)) | |
408 self.assertEquals(d.next(), (0, 1)) | |
409 self.assertEquals(d.next(), (0, 2)) | |
410 | |
411 def testInsert(self): | |
412 d = iter(util.IntervalDifferential([], 10)) | |
413 self.assertEquals(d.next(), (10, None)) | |
414 d.addInterval(3) | |
415 self.assertEquals(d.next(), (3, 0)) | |
416 self.assertEquals(d.next(), (3, 0)) | |
417 d.addInterval(6) | |
418 self.assertEquals(d.next(), (3, 0)) | |
419 self.assertEquals(d.next(), (3, 0)) | |
420 self.assertEquals(d.next(), (0, 1)) | |
421 self.assertEquals(d.next(), (3, 0)) | |
422 self.assertEquals(d.next(), (3, 0)) | |
423 self.assertEquals(d.next(), (0, 1)) | |
424 | |
425 def testRemove(self): | |
426 d = iter(util.IntervalDifferential([3, 5], 10)) | |
427 self.assertEquals(d.next(), (3, 0)) | |
428 self.assertEquals(d.next(), (2, 1)) | |
429 self.assertEquals(d.next(), (1, 0)) | |
430 d.removeInterval(3) | |
431 self.assertEquals(d.next(), (4, 0)) | |
432 self.assertEquals(d.next(), (5, 0)) | |
433 d.removeInterval(5) | |
434 self.assertEquals(d.next(), (10, None)) | |
435 self.assertRaises(ValueError, d.removeInterval, 10) | |
436 | |
437 | |
438 | |
439 class Record(util.FancyEqMixin): | |
440 """ | |
441 Trivial user of L{FancyEqMixin} used by tests. | |
442 """ | |
443 compareAttributes = ('a', 'b') | |
444 | |
445 def __init__(self, a, b): | |
446 self.a = a | |
447 self.b = b | |
448 | |
449 | |
450 | |
451 class DifferentRecord(util.FancyEqMixin): | |
452 """ | |
453 Trivial user of L{FancyEqMixin} which is not related to L{Record}. | |
454 """ | |
455 compareAttributes = ('a', 'b') | |
456 | |
457 def __init__(self, a, b): | |
458 self.a = a | |
459 self.b = b | |
460 | |
461 | |
462 | |
463 class DerivedRecord(Record): | |
464 """ | |
465 A class with an inheritance relationship to L{Record}. | |
466 """ | |
467 | |
468 | |
469 | |
470 class EqualToEverything(object): | |
471 """ | |
472 A class the instances of which consider themselves equal to everything. | |
473 """ | |
474 def __eq__(self, other): | |
475 return True | |
476 | |
477 | |
478 def __ne__(self, other): | |
479 return False | |
480 | |
481 | |
482 | |
483 class EqualToNothing(object): | |
484 """ | |
485 A class the instances of which consider themselves equal to nothing. | |
486 """ | |
487 def __eq__(self, other): | |
488 return False | |
489 | |
490 | |
491 def __ne__(self, other): | |
492 return True | |
493 | |
494 | |
495 | |
496 class EqualityTests(unittest.TestCase): | |
497 """ | |
498 Tests for L{FancyEqMixin}. | |
499 """ | |
500 def test_identity(self): | |
501 """ | |
502 Instances of a class which mixes in L{FancyEqMixin} but which | |
503 defines no comparison attributes compare by identity. | |
504 """ | |
505 class Empty(util.FancyEqMixin): | |
506 pass | |
507 | |
508 self.assertFalse(Empty() == Empty()) | |
509 self.assertTrue(Empty() != Empty()) | |
510 empty = Empty() | |
511 self.assertTrue(empty == empty) | |
512 self.assertFalse(empty != empty) | |
513 | |
514 | |
515 def test_equality(self): | |
516 """ | |
517 Instances of a class which mixes in L{FancyEqMixin} should compare | |
518 equal if all of their attributes compare equal. They should not | |
519 compare equal if any of their attributes do not compare equal. | |
520 """ | |
521 self.assertTrue(Record(1, 2) == Record(1, 2)) | |
522 self.assertFalse(Record(1, 2) == Record(1, 3)) | |
523 self.assertFalse(Record(1, 2) == Record(2, 2)) | |
524 self.assertFalse(Record(1, 2) == Record(3, 4)) | |
525 | |
526 | |
527 def test_unequality(self): | |
528 """ | |
529 Unequality between instances of a particular L{record} should be | |
530 defined as the negation of equality. | |
531 """ | |
532 self.assertFalse(Record(1, 2) != Record(1, 2)) | |
533 self.assertTrue(Record(1, 2) != Record(1, 3)) | |
534 self.assertTrue(Record(1, 2) != Record(2, 2)) | |
535 self.assertTrue(Record(1, 2) != Record(3, 4)) | |
536 | |
537 | |
538 def test_differentClassesEquality(self): | |
539 """ | |
540 Instances of different classes which mix in L{FancyEqMixin} should not | |
541 compare equal. | |
542 """ | |
543 self.assertFalse(Record(1, 2) == DifferentRecord(1, 2)) | |
544 | |
545 | |
546 def test_differentClassesInequality(self): | |
547 """ | |
548 Instances of different classes which mix in L{FancyEqMixin} should | |
549 compare unequal. | |
550 """ | |
551 self.assertTrue(Record(1, 2) != DifferentRecord(1, 2)) | |
552 | |
553 | |
554 def test_inheritedClassesEquality(self): | |
555 """ | |
556 An instance of a class which derives from a class which mixes in | |
557 L{FancyEqMixin} should compare equal to an instance of the base class | |
558 if and only if all of their attributes compare equal. | |
559 """ | |
560 self.assertTrue(Record(1, 2) == DerivedRecord(1, 2)) | |
561 self.assertFalse(Record(1, 2) == DerivedRecord(1, 3)) | |
562 self.assertFalse(Record(1, 2) == DerivedRecord(2, 2)) | |
563 self.assertFalse(Record(1, 2) == DerivedRecord(3, 4)) | |
564 | |
565 | |
566 def test_inheritedClassesInequality(self): | |
567 """ | |
568 An instance of a class which derives from a class which mixes in | |
569 L{FancyEqMixin} should compare unequal to an instance of the base | |
570 class if any of their attributes compare unequal. | |
571 """ | |
572 self.assertFalse(Record(1, 2) != DerivedRecord(1, 2)) | |
573 self.assertTrue(Record(1, 2) != DerivedRecord(1, 3)) | |
574 self.assertTrue(Record(1, 2) != DerivedRecord(2, 2)) | |
575 self.assertTrue(Record(1, 2) != DerivedRecord(3, 4)) | |
576 | |
577 | |
578 def test_rightHandArgumentImplementsEquality(self): | |
579 """ | |
580 The right-hand argument to the equality operator is given a chance | |
581 to determine the result of the operation if it is of a type | |
582 unrelated to the L{FancyEqMixin}-based instance on the left-hand | |
583 side. | |
584 """ | |
585 self.assertTrue(Record(1, 2) == EqualToEverything()) | |
586 self.assertFalse(Record(1, 2) == EqualToNothing()) | |
587 | |
588 | |
589 def test_rightHandArgumentImplementsUnequality(self): | |
590 """ | |
591 The right-hand argument to the non-equality operator is given a | |
592 chance to determine the result of the operation if it is of a type | |
593 unrelated to the L{FancyEqMixin}-based instance on the left-hand | |
594 side. | |
595 """ | |
596 self.assertFalse(Record(1, 2) != EqualToEverything()) | |
597 self.assertTrue(Record(1, 2) != EqualToNothing()) | |
OLD | NEW |