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_hypothesis.py 7.2KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. # -*- coding: utf-8 -*-
  2. """
  3. Tests for hyperlink.hypothesis.
  4. """
  5. try:
  6. import hypothesis
  7. del hypothesis
  8. except ImportError:
  9. pass
  10. else:
  11. from string import digits
  12. from typing import Sequence, Text
  13. try:
  14. from unittest.mock import patch
  15. except ImportError:
  16. from mock import patch # type: ignore[misc]
  17. from hypothesis import given, settings
  18. from hypothesis.strategies import SearchStrategy, data
  19. from idna import IDNAError, check_label, encode as idna_encode
  20. from .common import HyperlinkTestCase
  21. from .. import DecodedURL, EncodedURL
  22. from ..hypothesis import (
  23. DrawCallable,
  24. composite,
  25. decoded_urls,
  26. encoded_urls,
  27. hostname_labels,
  28. hostnames,
  29. idna_text,
  30. paths,
  31. port_numbers,
  32. )
  33. class TestHypothesisStrategies(HyperlinkTestCase):
  34. """
  35. Tests for hyperlink.hypothesis.
  36. """
  37. @given(idna_text())
  38. def test_idna_text_valid(self, text):
  39. # type: (Text) -> None
  40. """
  41. idna_text() generates IDNA-encodable text.
  42. """
  43. try:
  44. idna_encode(text)
  45. except IDNAError: # pragma: no cover
  46. raise AssertionError("Invalid IDNA text: {!r}".format(text))
  47. @given(data())
  48. def test_idna_text_min_max(self, data):
  49. # type: (SearchStrategy) -> None
  50. """
  51. idna_text() raises AssertionError if min_size is < 1.
  52. """
  53. self.assertRaises(AssertionError, data.draw, idna_text(min_size=0))
  54. self.assertRaises(AssertionError, data.draw, idna_text(max_size=0))
  55. @given(port_numbers())
  56. def test_port_numbers_bounds(self, port):
  57. # type: (int) -> None
  58. """
  59. port_numbers() generates integers between 1 and 65535, inclusive.
  60. """
  61. self.assertGreaterEqual(port, 1)
  62. self.assertLessEqual(port, 65535)
  63. @given(port_numbers(allow_zero=True))
  64. def test_port_numbers_bounds_allow_zero(self, port):
  65. # type: (int) -> None
  66. """
  67. port_numbers(allow_zero=True) generates integers between 0 and
  68. 65535, inclusive.
  69. """
  70. self.assertGreaterEqual(port, 0)
  71. self.assertLessEqual(port, 65535)
  72. @given(hostname_labels())
  73. def test_hostname_labels_valid_idn(self, label):
  74. # type: (Text) -> None
  75. """
  76. hostname_labels() generates IDN host name labels.
  77. """
  78. try:
  79. check_label(label)
  80. idna_encode(label)
  81. except UnicodeError: # pragma: no cover
  82. raise AssertionError("Invalid IDN label: {!r}".format(label))
  83. @given(data())
  84. @settings(max_examples=10)
  85. def test_hostname_labels_long_idn_punycode(self, data):
  86. # type: (SearchStrategy) -> None
  87. """
  88. hostname_labels() handles case where idna_text() generates text
  89. that encoded to punycode ends up as longer than allowed.
  90. """
  91. @composite
  92. def mock_idna_text(draw, min_size, max_size):
  93. # type: (DrawCallable, int, int) -> Text
  94. # We want a string that does not exceed max_size, but when
  95. # encoded to punycode, does exceed max_size.
  96. # So use a unicode character that is larger when encoded,
  97. # "á" being a great example, and use it max_size times, which
  98. # will be max_size * 3 in size when encoded.
  99. return u"\N{LATIN SMALL LETTER A WITH ACUTE}" * max_size
  100. with patch("hyperlink.hypothesis.idna_text", mock_idna_text):
  101. label = data.draw(hostname_labels())
  102. try:
  103. check_label(label)
  104. idna_encode(label)
  105. except UnicodeError: # pragma: no cover
  106. raise AssertionError(
  107. "Invalid IDN label: {!r}".format(label)
  108. )
  109. @given(hostname_labels(allow_idn=False))
  110. def test_hostname_labels_valid_ascii(self, label):
  111. # type: (Text) -> None
  112. """
  113. hostname_labels() generates a ASCII host name labels.
  114. """
  115. try:
  116. check_label(label)
  117. label.encode("ascii")
  118. except UnicodeError: # pragma: no cover
  119. raise AssertionError("Invalid ASCII label: {!r}".format(label))
  120. @given(hostnames())
  121. def test_hostnames_idn(self, hostname):
  122. # type: (Text) -> None
  123. """
  124. hostnames() generates a IDN host names.
  125. """
  126. try:
  127. for label in hostname.split(u"."):
  128. check_label(label)
  129. idna_encode(hostname)
  130. except UnicodeError: # pragma: no cover
  131. raise AssertionError(
  132. "Invalid IDN host name: {!r}".format(hostname)
  133. )
  134. @given(hostnames(allow_leading_digit=False))
  135. def test_hostnames_idn_nolead(self, hostname):
  136. # type: (Text) -> None
  137. """
  138. hostnames(allow_leading_digit=False) generates a IDN host names
  139. without leading digits.
  140. """
  141. self.assertTrue(hostname == hostname.lstrip(digits))
  142. @given(hostnames(allow_idn=False))
  143. def test_hostnames_ascii(self, hostname):
  144. # type: (Text) -> None
  145. """
  146. hostnames() generates a ASCII host names.
  147. """
  148. try:
  149. for label in hostname.split(u"."):
  150. check_label(label)
  151. hostname.encode("ascii")
  152. except UnicodeError: # pragma: no cover
  153. raise AssertionError(
  154. "Invalid ASCII host name: {!r}".format(hostname)
  155. )
  156. @given(hostnames(allow_leading_digit=False, allow_idn=False))
  157. def test_hostnames_ascii_nolead(self, hostname):
  158. # type: (Text) -> None
  159. """
  160. hostnames(allow_leading_digit=False, allow_idn=False) generates
  161. ASCII host names without leading digits.
  162. """
  163. self.assertTrue(hostname == hostname.lstrip(digits))
  164. @given(paths())
  165. def test_paths(self, path):
  166. # type: (Sequence[Text]) -> None
  167. """
  168. paths() generates sequences of URL path components.
  169. """
  170. text = u"/".join(path)
  171. try:
  172. text.encode("utf-8")
  173. except UnicodeError: # pragma: no cover
  174. raise AssertionError("Invalid URL path: {!r}".format(path))
  175. for segment in path:
  176. self.assertNotIn("#/?", segment)
  177. @given(encoded_urls())
  178. def test_encoded_urls(self, url):
  179. # type: (EncodedURL) -> None
  180. """
  181. encoded_urls() generates EncodedURLs.
  182. """
  183. self.assertIsInstance(url, EncodedURL)
  184. @given(decoded_urls())
  185. def test_decoded_urls(self, url):
  186. # type: (DecodedURL) -> None
  187. """
  188. decoded_urls() generates DecodedURLs.
  189. """
  190. self.assertIsInstance(url, DecodedURL)