Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_compat.py 18KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. Tests for L{twisted.python.compat}.
  5. """
  6. import codecs
  7. import io
  8. import sys
  9. import traceback
  10. from unittest import skipIf
  11. from twisted.python.compat import (
  12. _PYPY,
  13. _get_async_param,
  14. bytesEnviron,
  15. cmp,
  16. comparable,
  17. execfile,
  18. intToBytes,
  19. ioType,
  20. iterbytes,
  21. lazyByteSlice,
  22. nativeString,
  23. networkString,
  24. reraise,
  25. )
  26. from twisted.python.filepath import FilePath
  27. from twisted.python.runtime import platform
  28. from twisted.trial.unittest import SynchronousTestCase, TestCase
  29. class IOTypeTests(SynchronousTestCase):
  30. """
  31. Test cases for determining a file-like object's type.
  32. """
  33. def test_3StringIO(self):
  34. """
  35. An L{io.StringIO} accepts and returns text.
  36. """
  37. self.assertEqual(ioType(io.StringIO()), str)
  38. def test_3BytesIO(self):
  39. """
  40. An L{io.BytesIO} accepts and returns bytes.
  41. """
  42. self.assertEqual(ioType(io.BytesIO()), bytes)
  43. def test_3openTextMode(self):
  44. """
  45. A file opened via 'io.open' in text mode accepts and returns text.
  46. """
  47. with open(self.mktemp(), "w") as f:
  48. self.assertEqual(ioType(f), str)
  49. def test_3openBinaryMode(self):
  50. """
  51. A file opened via 'io.open' in binary mode accepts and returns bytes.
  52. """
  53. with open(self.mktemp(), "wb") as f:
  54. self.assertEqual(ioType(f), bytes)
  55. def test_codecsOpenBytes(self):
  56. """
  57. The L{codecs} module, oddly, returns a file-like object which returns
  58. bytes when not passed an 'encoding' argument.
  59. """
  60. with codecs.open(self.mktemp(), "wb") as f:
  61. self.assertEqual(ioType(f), bytes)
  62. def test_codecsOpenText(self):
  63. """
  64. When passed an encoding, however, the L{codecs} module returns unicode.
  65. """
  66. with codecs.open(self.mktemp(), "wb", encoding="utf-8") as f:
  67. self.assertEqual(ioType(f), str)
  68. def test_defaultToText(self):
  69. """
  70. When passed an object about which no sensible decision can be made, err
  71. on the side of unicode.
  72. """
  73. self.assertEqual(ioType(object()), str)
  74. class CompatTests(SynchronousTestCase):
  75. """
  76. Various utility functions in C{twisted.python.compat} provide same
  77. functionality as modern Python variants.
  78. """
  79. def test_set(self):
  80. """
  81. L{set} should behave like the expected set interface.
  82. """
  83. a = set()
  84. a.add("b")
  85. a.add("c")
  86. a.add("a")
  87. b = list(a)
  88. b.sort()
  89. self.assertEqual(b, ["a", "b", "c"])
  90. a.remove("b")
  91. b = list(a)
  92. b.sort()
  93. self.assertEqual(b, ["a", "c"])
  94. a.discard("d")
  95. b = {"r", "s"}
  96. d = a.union(b)
  97. b = list(d)
  98. b.sort()
  99. self.assertEqual(b, ["a", "c", "r", "s"])
  100. def test_frozenset(self):
  101. """
  102. L{frozenset} should behave like the expected frozenset interface.
  103. """
  104. a = frozenset(["a", "b"])
  105. self.assertRaises(AttributeError, getattr, a, "add")
  106. self.assertEqual(sorted(a), ["a", "b"])
  107. b = frozenset(["r", "s"])
  108. d = a.union(b)
  109. b = list(d)
  110. b.sort()
  111. self.assertEqual(b, ["a", "b", "r", "s"])
  112. class ExecfileCompatTests(SynchronousTestCase):
  113. """
  114. Tests for the Python 3-friendly L{execfile} implementation.
  115. """
  116. def writeScript(self, content):
  117. """
  118. Write L{content} to a new temporary file, returning the L{FilePath}
  119. for the new file.
  120. """
  121. path = self.mktemp()
  122. with open(path, "wb") as f:
  123. f.write(content.encode("ascii"))
  124. return FilePath(path.encode("utf-8"))
  125. def test_execfileGlobals(self):
  126. """
  127. L{execfile} executes the specified file in the given global namespace.
  128. """
  129. script = self.writeScript("foo += 1\n")
  130. globalNamespace = {"foo": 1}
  131. execfile(script.path, globalNamespace)
  132. self.assertEqual(2, globalNamespace["foo"])
  133. def test_execfileGlobalsAndLocals(self):
  134. """
  135. L{execfile} executes the specified file in the given global and local
  136. namespaces.
  137. """
  138. script = self.writeScript("foo += 1\n")
  139. globalNamespace = {"foo": 10}
  140. localNamespace = {"foo": 20}
  141. execfile(script.path, globalNamespace, localNamespace)
  142. self.assertEqual(10, globalNamespace["foo"])
  143. self.assertEqual(21, localNamespace["foo"])
  144. def test_execfileUniversalNewlines(self):
  145. """
  146. L{execfile} reads in the specified file using universal newlines so
  147. that scripts written on one platform will work on another.
  148. """
  149. for lineEnding in "\n", "\r", "\r\n":
  150. script = self.writeScript("foo = 'okay'" + lineEnding)
  151. globalNamespace = {"foo": None}
  152. execfile(script.path, globalNamespace)
  153. self.assertEqual("okay", globalNamespace["foo"])
  154. class PYPYTest(SynchronousTestCase):
  155. """
  156. Identification of PyPy.
  157. """
  158. def test_PYPY(self):
  159. """
  160. On PyPy, L{_PYPY} is True.
  161. """
  162. if "PyPy" in sys.version:
  163. self.assertTrue(_PYPY)
  164. else:
  165. self.assertFalse(_PYPY)
  166. @comparable
  167. class Comparable:
  168. """
  169. Objects that can be compared to each other, but not others.
  170. """
  171. def __init__(self, value):
  172. self.value = value
  173. def __cmp__(self, other):
  174. if not isinstance(other, Comparable):
  175. return NotImplemented
  176. return cmp(self.value, other.value)
  177. class ComparableTests(SynchronousTestCase):
  178. """
  179. L{comparable} decorated classes emulate Python 2's C{__cmp__} semantics.
  180. """
  181. def test_equality(self):
  182. """
  183. Instances of a class that is decorated by C{comparable} support
  184. equality comparisons.
  185. """
  186. # Make explicitly sure we're using ==:
  187. self.assertTrue(Comparable(1) == Comparable(1))
  188. self.assertFalse(Comparable(2) == Comparable(1))
  189. def test_nonEquality(self):
  190. """
  191. Instances of a class that is decorated by C{comparable} support
  192. inequality comparisons.
  193. """
  194. # Make explicitly sure we're using !=:
  195. self.assertFalse(Comparable(1) != Comparable(1))
  196. self.assertTrue(Comparable(2) != Comparable(1))
  197. def test_greaterThan(self):
  198. """
  199. Instances of a class that is decorated by C{comparable} support
  200. greater-than comparisons.
  201. """
  202. self.assertTrue(Comparable(2) > Comparable(1))
  203. self.assertFalse(Comparable(0) > Comparable(3))
  204. def test_greaterThanOrEqual(self):
  205. """
  206. Instances of a class that is decorated by C{comparable} support
  207. greater-than-or-equal comparisons.
  208. """
  209. self.assertTrue(Comparable(1) >= Comparable(1))
  210. self.assertTrue(Comparable(2) >= Comparable(1))
  211. self.assertFalse(Comparable(0) >= Comparable(3))
  212. def test_lessThan(self):
  213. """
  214. Instances of a class that is decorated by C{comparable} support
  215. less-than comparisons.
  216. """
  217. self.assertTrue(Comparable(0) < Comparable(3))
  218. self.assertFalse(Comparable(2) < Comparable(0))
  219. def test_lessThanOrEqual(self):
  220. """
  221. Instances of a class that is decorated by C{comparable} support
  222. less-than-or-equal comparisons.
  223. """
  224. self.assertTrue(Comparable(3) <= Comparable(3))
  225. self.assertTrue(Comparable(0) <= Comparable(3))
  226. self.assertFalse(Comparable(2) <= Comparable(0))
  227. class Python3ComparableTests(SynchronousTestCase):
  228. """
  229. Python 3-specific functionality of C{comparable}.
  230. """
  231. def test_notImplementedEquals(self):
  232. """
  233. Instances of a class that is decorated by C{comparable} support
  234. returning C{NotImplemented} from C{__eq__} if it is returned by the
  235. underlying C{__cmp__} call.
  236. """
  237. self.assertEqual(Comparable(1).__eq__(object()), NotImplemented)
  238. def test_notImplementedNotEquals(self):
  239. """
  240. Instances of a class that is decorated by C{comparable} support
  241. returning C{NotImplemented} from C{__ne__} if it is returned by the
  242. underlying C{__cmp__} call.
  243. """
  244. self.assertEqual(Comparable(1).__ne__(object()), NotImplemented)
  245. def test_notImplementedGreaterThan(self):
  246. """
  247. Instances of a class that is decorated by C{comparable} support
  248. returning C{NotImplemented} from C{__gt__} if it is returned by the
  249. underlying C{__cmp__} call.
  250. """
  251. self.assertEqual(Comparable(1).__gt__(object()), NotImplemented)
  252. def test_notImplementedLessThan(self):
  253. """
  254. Instances of a class that is decorated by C{comparable} support
  255. returning C{NotImplemented} from C{__lt__} if it is returned by the
  256. underlying C{__cmp__} call.
  257. """
  258. self.assertEqual(Comparable(1).__lt__(object()), NotImplemented)
  259. def test_notImplementedGreaterThanEquals(self):
  260. """
  261. Instances of a class that is decorated by C{comparable} support
  262. returning C{NotImplemented} from C{__ge__} if it is returned by the
  263. underlying C{__cmp__} call.
  264. """
  265. self.assertEqual(Comparable(1).__ge__(object()), NotImplemented)
  266. def test_notImplementedLessThanEquals(self):
  267. """
  268. Instances of a class that is decorated by C{comparable} support
  269. returning C{NotImplemented} from C{__le__} if it is returned by the
  270. underlying C{__cmp__} call.
  271. """
  272. self.assertEqual(Comparable(1).__le__(object()), NotImplemented)
  273. class CmpTests(SynchronousTestCase):
  274. """
  275. L{cmp} should behave like the built-in Python 2 C{cmp}.
  276. """
  277. def test_equals(self):
  278. """
  279. L{cmp} returns 0 for equal objects.
  280. """
  281. self.assertEqual(cmp("a", "a"), 0)
  282. self.assertEqual(cmp(1, 1), 0)
  283. self.assertEqual(cmp([1], [1]), 0)
  284. def test_greaterThan(self):
  285. """
  286. L{cmp} returns 1 if its first argument is bigger than its second.
  287. """
  288. self.assertEqual(cmp(4, 0), 1)
  289. self.assertEqual(cmp(b"z", b"a"), 1)
  290. def test_lessThan(self):
  291. """
  292. L{cmp} returns -1 if its first argument is smaller than its second.
  293. """
  294. self.assertEqual(cmp(0.1, 2.3), -1)
  295. self.assertEqual(cmp(b"a", b"d"), -1)
  296. class StringTests(SynchronousTestCase):
  297. """
  298. Compatibility functions and types for strings.
  299. """
  300. def assertNativeString(self, original, expected):
  301. """
  302. Raise an exception indicating a failed test if the output of
  303. C{nativeString(original)} is unequal to the expected string, or is not
  304. a native string.
  305. """
  306. self.assertEqual(nativeString(original), expected)
  307. self.assertIsInstance(nativeString(original), str)
  308. def test_nonASCIIBytesToString(self):
  309. """
  310. C{nativeString} raises a C{UnicodeError} if input bytes are not ASCII
  311. decodable.
  312. """
  313. self.assertRaises(UnicodeError, nativeString, b"\xFF")
  314. def test_nonASCIIUnicodeToString(self):
  315. """
  316. C{nativeString} raises a C{UnicodeError} if input Unicode is not ASCII
  317. encodable.
  318. """
  319. self.assertRaises(UnicodeError, nativeString, "\u1234")
  320. def test_bytesToString(self):
  321. """
  322. C{nativeString} converts bytes to the native string format, assuming
  323. an ASCII encoding if applicable.
  324. """
  325. self.assertNativeString(b"hello", "hello")
  326. def test_unicodeToString(self):
  327. """
  328. C{nativeString} converts unicode to the native string format, assuming
  329. an ASCII encoding if applicable.
  330. """
  331. self.assertNativeString("Good day", "Good day")
  332. def test_stringToString(self):
  333. """
  334. C{nativeString} leaves native strings as native strings.
  335. """
  336. self.assertNativeString("Hello!", "Hello!")
  337. def test_unexpectedType(self):
  338. """
  339. C{nativeString} raises a C{TypeError} if given an object that is not a
  340. string of some sort.
  341. """
  342. self.assertRaises(TypeError, nativeString, 1)
  343. class NetworkStringTests(SynchronousTestCase):
  344. """
  345. Tests for L{networkString}.
  346. """
  347. def test_str(self):
  348. """
  349. L{networkString} returns a C{unicode} object passed to it encoded into
  350. a C{bytes} instance.
  351. """
  352. self.assertEqual(b"foo", networkString("foo"))
  353. def test_unicodeOutOfRange(self):
  354. """
  355. L{networkString} raises L{UnicodeError} if passed a C{unicode} instance
  356. containing characters not encodable in ASCII.
  357. """
  358. self.assertRaises(UnicodeError, networkString, "\N{SNOWMAN}")
  359. def test_nonString(self):
  360. """
  361. L{networkString} raises L{TypeError} if passed a non-string object or
  362. the wrong type of string object.
  363. """
  364. self.assertRaises(TypeError, networkString, object())
  365. self.assertRaises(TypeError, networkString, b"bytes")
  366. class ReraiseTests(SynchronousTestCase):
  367. """
  368. L{reraise} re-raises exceptions on both Python 2 and Python 3.
  369. """
  370. def test_reraiseWithNone(self):
  371. """
  372. Calling L{reraise} with an exception instance and a traceback of
  373. L{None} re-raises it with a new traceback.
  374. """
  375. try:
  376. 1 / 0
  377. except BaseException:
  378. typ, value, tb = sys.exc_info()
  379. try:
  380. reraise(value, None)
  381. except BaseException:
  382. typ2, value2, tb2 = sys.exc_info()
  383. self.assertEqual(typ2, ZeroDivisionError)
  384. self.assertIs(value, value2)
  385. self.assertNotEqual(
  386. traceback.format_tb(tb)[-1], traceback.format_tb(tb2)[-1]
  387. )
  388. else:
  389. self.fail("The exception was not raised.")
  390. def test_reraiseWithTraceback(self):
  391. """
  392. Calling L{reraise} with an exception instance and a traceback
  393. re-raises the exception with the given traceback.
  394. """
  395. try:
  396. 1 / 0
  397. except BaseException:
  398. typ, value, tb = sys.exc_info()
  399. try:
  400. reraise(value, tb)
  401. except BaseException:
  402. typ2, value2, tb2 = sys.exc_info()
  403. self.assertEqual(typ2, ZeroDivisionError)
  404. self.assertIs(value, value2)
  405. self.assertEqual(traceback.format_tb(tb)[-1], traceback.format_tb(tb2)[-1])
  406. else:
  407. self.fail("The exception was not raised.")
  408. class Python3BytesTests(SynchronousTestCase):
  409. """
  410. Tests for L{iterbytes}, L{intToBytes}, L{lazyByteSlice}.
  411. """
  412. def test_iteration(self):
  413. """
  414. When L{iterbytes} is called with a bytestring, the returned object
  415. can be iterated over, resulting in the individual bytes of the
  416. bytestring.
  417. """
  418. input = b"abcd"
  419. result = list(iterbytes(input))
  420. self.assertEqual(result, [b"a", b"b", b"c", b"d"])
  421. def test_intToBytes(self):
  422. """
  423. When L{intToBytes} is called with an integer, the result is an
  424. ASCII-encoded string representation of the number.
  425. """
  426. self.assertEqual(intToBytes(213), b"213")
  427. def test_lazyByteSliceNoOffset(self):
  428. """
  429. L{lazyByteSlice} called with some bytes returns a semantically equal
  430. version of these bytes.
  431. """
  432. data = b"123XYZ"
  433. self.assertEqual(bytes(lazyByteSlice(data)), data)
  434. def test_lazyByteSliceOffset(self):
  435. """
  436. L{lazyByteSlice} called with some bytes and an offset returns a
  437. semantically equal version of these bytes starting at the given offset.
  438. """
  439. data = b"123XYZ"
  440. self.assertEqual(bytes(lazyByteSlice(data, 2)), data[2:])
  441. def test_lazyByteSliceOffsetAndLength(self):
  442. """
  443. L{lazyByteSlice} called with some bytes, an offset and a length returns
  444. a semantically equal version of these bytes starting at the given
  445. offset, up to the given length.
  446. """
  447. data = b"123XYZ"
  448. self.assertEqual(bytes(lazyByteSlice(data, 2, 3)), data[2:5])
  449. class BytesEnvironTests(TestCase):
  450. """
  451. Tests for L{BytesEnviron}.
  452. """
  453. @skipIf(platform.isWindows(), "Environment vars are always str on Windows.")
  454. def test_alwaysBytes(self):
  455. """
  456. The output of L{BytesEnviron} should always be a L{dict} with L{bytes}
  457. values and L{bytes} keys.
  458. """
  459. result = bytesEnviron()
  460. types = set()
  461. for key, val in result.items():
  462. types.add(type(key))
  463. types.add(type(val))
  464. self.assertEqual(list(types), [bytes])
  465. class GetAsyncParamTests(SynchronousTestCase):
  466. """
  467. Tests for L{twisted.python.compat._get_async_param}
  468. """
  469. def test_get_async_param(self):
  470. """
  471. L{twisted.python.compat._get_async_param} uses isAsync by default,
  472. or deprecated async keyword argument if isAsync is None.
  473. """
  474. self.assertEqual(_get_async_param(isAsync=False), False)
  475. self.assertEqual(_get_async_param(isAsync=True), True)
  476. self.assertEqual(_get_async_param(isAsync=None, **{"async": False}), False)
  477. self.assertEqual(_get_async_param(isAsync=None, **{"async": True}), True)
  478. self.assertRaises(TypeError, _get_async_param, False, {"async": False})
  479. def test_get_async_param_deprecation(self):
  480. """
  481. L{twisted.python.compat._get_async_param} raises a deprecation
  482. warning if async keyword argument is passed.
  483. """
  484. self.assertEqual(_get_async_param(isAsync=None, **{"async": False}), False)
  485. currentWarnings = self.flushWarnings(
  486. offendingFunctions=[self.test_get_async_param_deprecation]
  487. )
  488. self.assertEqual(
  489. currentWarnings[0]["message"],
  490. "'async' keyword argument is deprecated, please use isAsync",
  491. )