1
# Copyright (c) Twisted Matrix Laboratories.
2
# See LICENSE for details.
5
Tests for the subset of L{twisted.python.util} which has been ported to Python 3.
8
from __future__ import division, absolute_import
10
import sys, errno, warnings
12
from twisted.trial.unittest import SynchronousTestCase as TestCase
14
from twisted.python import _utilpy3 as util
17
class Record(util.FancyEqMixin):
19
Trivial user of L{FancyEqMixin} used by tests.
21
compareAttributes = ('a', 'b')
23
def __init__(self, a, b):
29
class DifferentRecord(util.FancyEqMixin):
31
Trivial user of L{FancyEqMixin} which is not related to L{Record}.
33
compareAttributes = ('a', 'b')
35
def __init__(self, a, b):
41
class DerivedRecord(Record):
43
A class with an inheritance relationship to L{Record}.
48
class EqualToEverything(object):
50
A class the instances of which consider themselves equal to everything.
52
def __eq__(self, other):
56
def __ne__(self, other):
61
class EqualToNothing(object):
63
A class the instances of which consider themselves equal to nothing.
65
def __eq__(self, other):
69
def __ne__(self, other):
74
class EqualityTests(TestCase):
76
Tests for L{FancyEqMixin}.
78
def test_identity(self):
80
Instances of a class which mixes in L{FancyEqMixin} but which
81
defines no comparison attributes compare by identity.
83
class Empty(util.FancyEqMixin):
86
self.assertFalse(Empty() == Empty())
87
self.assertTrue(Empty() != Empty())
89
self.assertTrue(empty == empty)
90
self.assertFalse(empty != empty)
93
def test_equality(self):
95
Instances of a class which mixes in L{FancyEqMixin} should compare
96
equal if all of their attributes compare equal. They should not
97
compare equal if any of their attributes do not compare equal.
99
self.assertTrue(Record(1, 2) == Record(1, 2))
100
self.assertFalse(Record(1, 2) == Record(1, 3))
101
self.assertFalse(Record(1, 2) == Record(2, 2))
102
self.assertFalse(Record(1, 2) == Record(3, 4))
105
def test_unequality(self):
107
Unequality between instances of a particular L{record} should be
108
defined as the negation of equality.
110
self.assertFalse(Record(1, 2) != Record(1, 2))
111
self.assertTrue(Record(1, 2) != Record(1, 3))
112
self.assertTrue(Record(1, 2) != Record(2, 2))
113
self.assertTrue(Record(1, 2) != Record(3, 4))
116
def test_differentClassesEquality(self):
118
Instances of different classes which mix in L{FancyEqMixin} should not
121
self.assertFalse(Record(1, 2) == DifferentRecord(1, 2))
124
def test_differentClassesInequality(self):
126
Instances of different classes which mix in L{FancyEqMixin} should
129
self.assertTrue(Record(1, 2) != DifferentRecord(1, 2))
132
def test_inheritedClassesEquality(self):
134
An instance of a class which derives from a class which mixes in
135
L{FancyEqMixin} should compare equal to an instance of the base class
136
if and only if all of their attributes compare equal.
138
self.assertTrue(Record(1, 2) == DerivedRecord(1, 2))
139
self.assertFalse(Record(1, 2) == DerivedRecord(1, 3))
140
self.assertFalse(Record(1, 2) == DerivedRecord(2, 2))
141
self.assertFalse(Record(1, 2) == DerivedRecord(3, 4))
144
def test_inheritedClassesInequality(self):
146
An instance of a class which derives from a class which mixes in
147
L{FancyEqMixin} should compare unequal to an instance of the base
148
class if any of their attributes compare unequal.
150
self.assertFalse(Record(1, 2) != DerivedRecord(1, 2))
151
self.assertTrue(Record(1, 2) != DerivedRecord(1, 3))
152
self.assertTrue(Record(1, 2) != DerivedRecord(2, 2))
153
self.assertTrue(Record(1, 2) != DerivedRecord(3, 4))
156
def test_rightHandArgumentImplementsEquality(self):
158
The right-hand argument to the equality operator is given a chance
159
to determine the result of the operation if it is of a type
160
unrelated to the L{FancyEqMixin}-based instance on the left-hand
163
self.assertTrue(Record(1, 2) == EqualToEverything())
164
self.assertFalse(Record(1, 2) == EqualToNothing())
167
def test_rightHandArgumentImplementsUnequality(self):
169
The right-hand argument to the non-equality operator is given a
170
chance to determine the result of the operation if it is of a type
171
unrelated to the L{FancyEqMixin}-based instance on the left-hand
174
self.assertFalse(Record(1, 2) != EqualToEverything())
175
self.assertTrue(Record(1, 2) != EqualToNothing())
179
class UnsignedIDTests(TestCase):
181
Tests for L{util.unsignedID} and L{util.setIDFunction}.
186
Save the value of L{util._idFunction} and arrange for it to be restored
189
self.addCleanup(setattr, util, '_idFunction', util._idFunction)
192
def test_setIDFunction(self):
194
L{util.setIDFunction} returns the last value passed to it.
197
previous = util.setIDFunction(value)
198
result = util.setIDFunction(previous)
199
self.assertIdentical(value, result)
202
def test_unsignedID(self):
204
L{util.unsignedID} uses the function passed to L{util.setIDFunction} to
205
determine the unique integer id of an object and then adjusts it to be
206
positive if necessary.
211
# A fake object identity mapping
212
objects = {foo: 17, bar: -73}
216
util.setIDFunction(fakeId)
218
self.assertEqual(util.unsignedID(foo), 17)
219
self.assertEqual(util.unsignedID(bar), (sys.maxsize + 1) * 2 - 73)
222
def test_defaultIDFunction(self):
224
L{util.unsignedID} uses the built in L{id} by default.
229
idValue += (sys.maxsize + 1) * 2
231
self.assertEqual(util.unsignedID(obj), idValue)
235
class UntilConcludesTests(TestCase):
237
Tests for L{untilConcludes}, an C{EINTR} helper.
239
def test_uninterruptably(self):
241
L{untilConcludes} calls the function passed to it until the function
242
does not raise either L{OSError} or L{IOError} with C{errno} of
243
C{EINTR}. It otherwise completes with the same result as the function
248
exc = self.exceptions.pop()
250
raise exc(errno.EINTR, "Interrupted system call!")
253
self.exceptions = [None]
255
self.assertEqual(util.untilConcludes(f, 1, 2), 3)
256
self.assertEqual(self.calls, 1)
258
self.exceptions = [None, OSError, IOError]
260
self.assertEqual(util.untilConcludes(f, 2, 3), 5)
261
self.assertEqual(self.calls, 3)
265
class SuppressedWarningsTests(TestCase):
267
Tests for L{util.runWithWarningsSuppressed}.
269
runWithWarningsSuppressed = staticmethod(util.runWithWarningsSuppressed)
271
def test_runWithWarningsSuppressedFiltered(self):
273
Warnings from the function called by C{runWithWarningsSuppressed} are
274
suppressed if they match the passed in filter.
276
filters = [(("ignore", ".*foo.*"), {}),
277
(("ignore", ".*bar.*"), {})]
278
self.runWithWarningsSuppressed(filters, warnings.warn, "ignore foo")
279
self.runWithWarningsSuppressed(filters, warnings.warn, "ignore bar")
280
self.assertEqual([], self.flushWarnings())
283
def test_runWithWarningsSuppressedUnfiltered(self):
285
Warnings from the function called by C{runWithWarningsSuppressed} are
286
not suppressed if they do not match the passed in filter.
288
filters = [(("ignore", ".*foo.*"), {}),
289
(("ignore", ".*bar.*"), {})]
290
self.runWithWarningsSuppressed(filters, warnings.warn, "don't ignore")
292
["don't ignore"], [w['message'] for w in self.flushWarnings()])
295
def test_passThrough(self):
297
C{runWithWarningsSuppressed} returns the result of the function it
300
self.assertEqual(self.runWithWarningsSuppressed([], lambda: 4), 4)
303
def test_noSideEffects(self):
305
Once C{runWithWarningsSuppressed} has returned, it no longer
308
filters = [(("ignore", ".*foo.*"), {}),
309
(("ignore", ".*bar.*"), {})]
310
self.runWithWarningsSuppressed(filters, lambda: None)
311
warnings.warn("ignore foo")
313
["ignore foo"], [w['message'] for w in self.flushWarnings()])
317
class FancyStrMixinTests(TestCase):
319
Tests for L{util.FancyStrMixin}.
322
def test_sequenceOfStrings(self):
324
If C{showAttributes} is set to a sequence of strings, C{__str__}
325
renders using those by looking them up as attributes on the object.
327
class Foo(util.FancyStrMixin):
328
showAttributes = ("first", "second")
331
self.assertEqual(str(Foo()), "<Foo first=1 second='hello'>")
334
def test_formatter(self):
336
If C{showAttributes} has an item that is a 2-tuple, C{__str__} renders
337
the first item in the tuple as a key and the result of calling the
338
second item with the value of the attribute named by the first item as
341
class Foo(util.FancyStrMixin):
344
("second", lambda value: repr(value[::-1])))
347
self.assertEqual("<Foo first='hello' second='dlrow'>", str(Foo()))
350
def test_override(self):
352
If C{showAttributes} has an item that is a 3-tuple, C{__str__} renders
353
the second item in the tuple as a key, and the contents of the
354
attribute named in the first item are rendered as the value. The value
355
is formatted using the third item in the tuple.
357
class Foo(util.FancyStrMixin):
358
showAttributes = ("first", ("second", "2nd", "%.1f"))
361
self.assertEqual(str(Foo()), "<Foo first=1 2nd=2.1>")
364
def test_fancybasename(self):
366
If C{fancybasename} is present, C{__str__} uses it instead of the class name.
368
class Foo(util.FancyStrMixin):
369
fancybasename = "Bar"
370
self.assertEqual(str(Foo()), "<Bar>")
375
C{__repr__} outputs the same content as C{__str__}.
377
class Foo(util.FancyStrMixin):
378
showAttributes = ("first", "second")
382
self.assertEqual(str(obj), repr(obj))
386
class NameToLabelTests(TestCase):
388
Tests for L{nameToLabel}.
391
def test_nameToLabel(self):
393
Test the various kinds of inputs L{nameToLabel} supports.
399
('fooBar', 'Foo Bar'),
400
('fooBarBaz', 'Foo Bar Baz'),
402
for inp, out in nameData:
403
got = util.nameToLabel(inp)
406
"nameToLabel(%r) == %r != %r" % (inp, got, out))
410
class InsensitiveDictTest(TestCase):
412
Tests for L{util.InsensitiveDict}.
415
def test_preserve(self):
417
L{util.InsensitiveDict} preserves the case of keys if constructed with
420
dct = util.InsensitiveDict({'Foo':'bar', 1:2, 'fnz':{1:2}}, preserve=1)
421
self.assertEqual(dct['fnz'], {1:2})
422
self.assertEqual(dct['foo'], 'bar')
423
self.assertEqual(dct.copy(), dct)
424
self.assertEqual(dct['foo'], dct.get('Foo'))
425
self.assertIn(1, dct)
426
self.assertIn('foo', dct)
427
# Make eval() work, urrrrgh:
428
InsensitiveDict = util.InsensitiveDict
429
self.assertEqual(eval(repr(dct)), dct)
430
keys=['Foo', 'fnz', 1]
432
self.assertIn(x, dct.keys())
433
self.assertIn((x, dct[x]), dct.items())
434
self.assertEqual(len(keys), len(dct))
437
self.assertEqual(dct.keys(), ['fnz'])
440
def test_noPreserve(self):
442
L{util.InsensitiveDict} does not preserves the case of keys if
443
constructed with C{preserve=False}.
445
dct = util.InsensitiveDict({'Foo':'bar', 1:2, 'fnz':{1:2}}, preserve=0)
446
keys=['foo', 'fnz', 1]
448
self.assertIn(x, dct.keys())
449
self.assertIn((x, dct[x]), dct.items())
450
self.assertEqual(len(keys), len(dct))
453
self.assertEqual(dct.keys(), ['fnz'])
456
def test_unicode(self):
458
Unicode keys are case insensitive.
460
d = util.InsensitiveDict(preserve=False)
462
self.assertEqual(d[u"FOO"], 1)
463
self.assertEqual(d.keys(), [u"foo"])
466
def test_bytes(self):
468
Bytes keys are case insensitive.
470
d = util.InsensitiveDict(preserve=False)
472
self.assertEqual(d[b"FOO"], 1)
473
self.assertEqual(d.keys(), [b"foo"])