test_qrcode.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. import io
  2. from unittest import mock
  3. import pytest
  4. import qrcode
  5. import qrcode.util
  6. from qrcode.exceptions import DataOverflowError
  7. from qrcode.image.base import BaseImage
  8. from qrcode.tests.consts import UNICODE_TEXT
  9. from qrcode.util import MODE_8BIT_BYTE, MODE_ALPHA_NUM, MODE_NUMBER, QRData
  10. def test_basic():
  11. qr = qrcode.QRCode(version=1)
  12. qr.add_data("a")
  13. qr.make(fit=False)
  14. def test_large():
  15. qr = qrcode.QRCode(version=27)
  16. qr.add_data("a")
  17. qr.make(fit=False)
  18. def test_invalid_version():
  19. with pytest.raises(ValueError):
  20. qrcode.QRCode(version=42)
  21. def test_invalid_border():
  22. with pytest.raises(ValueError):
  23. qrcode.QRCode(border=-1)
  24. def test_overflow():
  25. qr = qrcode.QRCode(version=1)
  26. qr.add_data("abcdefghijklmno")
  27. with pytest.raises(DataOverflowError):
  28. qr.make(fit=False)
  29. def test_add_qrdata():
  30. qr = qrcode.QRCode(version=1)
  31. data = QRData("a")
  32. qr.add_data(data)
  33. qr.make(fit=False)
  34. def test_fit():
  35. qr = qrcode.QRCode()
  36. qr.add_data("a")
  37. qr.make()
  38. assert qr.version == 1
  39. qr.add_data("bcdefghijklmno")
  40. qr.make()
  41. assert qr.version == 2
  42. def test_mode_number():
  43. qr = qrcode.QRCode()
  44. qr.add_data("1234567890123456789012345678901234", optimize=0)
  45. qr.make()
  46. assert qr.version == 1
  47. assert qr.data_list[0].mode == MODE_NUMBER
  48. def test_mode_alpha():
  49. qr = qrcode.QRCode()
  50. qr.add_data("ABCDEFGHIJ1234567890", optimize=0)
  51. qr.make()
  52. assert qr.version == 1
  53. assert qr.data_list[0].mode == MODE_ALPHA_NUM
  54. def test_regression_mode_comma():
  55. qr = qrcode.QRCode()
  56. qr.add_data(",", optimize=0)
  57. qr.make()
  58. assert qr.data_list[0].mode == MODE_8BIT_BYTE
  59. def test_mode_8bit():
  60. qr = qrcode.QRCode()
  61. qr.add_data("abcABC" + UNICODE_TEXT, optimize=0)
  62. qr.make()
  63. assert qr.version == 1
  64. assert qr.data_list[0].mode == MODE_8BIT_BYTE
  65. def test_mode_8bit_newline():
  66. qr = qrcode.QRCode()
  67. qr.add_data("ABCDEFGHIJ1234567890\n", optimize=0)
  68. qr.make()
  69. assert qr.data_list[0].mode == MODE_8BIT_BYTE
  70. def test_make_image_with_wrong_pattern():
  71. with pytest.raises(TypeError):
  72. qrcode.QRCode(mask_pattern="string pattern")
  73. with pytest.raises(ValueError):
  74. qrcode.QRCode(mask_pattern=-1)
  75. with pytest.raises(ValueError):
  76. qrcode.QRCode(mask_pattern=42)
  77. def test_mask_pattern_setter():
  78. qr = qrcode.QRCode()
  79. with pytest.raises(TypeError):
  80. qr.mask_pattern = "string pattern"
  81. with pytest.raises(ValueError):
  82. qr.mask_pattern = -1
  83. with pytest.raises(ValueError):
  84. qr.mask_pattern = 8
  85. def test_qrcode_bad_factory():
  86. with pytest.raises(TypeError):
  87. qrcode.QRCode(image_factory="not_BaseImage") # type: ignore
  88. with pytest.raises(AssertionError):
  89. qrcode.QRCode(image_factory=dict) # type: ignore
  90. def test_qrcode_factory():
  91. class MockFactory(BaseImage):
  92. drawrect = mock.Mock()
  93. new_image = mock.Mock()
  94. qr = qrcode.QRCode(image_factory=MockFactory)
  95. qr.add_data(UNICODE_TEXT)
  96. qr.make_image()
  97. assert MockFactory.new_image.called
  98. assert MockFactory.drawrect.called
  99. def test_optimize():
  100. qr = qrcode.QRCode()
  101. text = "A1abc12345def1HELLOa"
  102. qr.add_data(text, optimize=4)
  103. qr.make()
  104. assert [d.mode for d in qr.data_list] == [
  105. MODE_8BIT_BYTE,
  106. MODE_NUMBER,
  107. MODE_8BIT_BYTE,
  108. MODE_ALPHA_NUM,
  109. MODE_8BIT_BYTE,
  110. ]
  111. assert qr.version == 2
  112. def test_optimize_short():
  113. qr = qrcode.QRCode()
  114. text = "A1abc1234567def1HELLOa"
  115. qr.add_data(text, optimize=7)
  116. qr.make()
  117. assert len(qr.data_list) == 3
  118. assert [d.mode for d in qr.data_list] == [
  119. MODE_8BIT_BYTE,
  120. MODE_NUMBER,
  121. MODE_8BIT_BYTE,
  122. ]
  123. assert qr.version == 2
  124. def test_optimize_longer_than_data():
  125. qr = qrcode.QRCode()
  126. text = "ABCDEFGHIJK"
  127. qr.add_data(text, optimize=12)
  128. assert len(qr.data_list) == 1
  129. assert qr.data_list[0].mode == MODE_ALPHA_NUM
  130. def test_optimize_size():
  131. text = "A1abc12345123451234512345def1HELLOHELLOHELLOHELLOa" * 5
  132. qr = qrcode.QRCode()
  133. qr.add_data(text)
  134. qr.make()
  135. assert qr.version == 10
  136. qr = qrcode.QRCode()
  137. qr.add_data(text, optimize=0)
  138. qr.make()
  139. assert qr.version == 11
  140. def test_qrdata_repr():
  141. data = b"hello"
  142. data_obj = qrcode.util.QRData(data)
  143. assert repr(data_obj) == repr(data)
  144. def test_print_ascii_stdout():
  145. qr = qrcode.QRCode()
  146. with mock.patch("sys.stdout") as fake_stdout:
  147. fake_stdout.isatty.return_value = None
  148. with pytest.raises(OSError):
  149. qr.print_ascii(tty=True)
  150. assert fake_stdout.isatty.called
  151. def test_print_ascii():
  152. qr = qrcode.QRCode(border=0)
  153. f = io.StringIO()
  154. qr.print_ascii(out=f)
  155. printed = f.getvalue()
  156. f.close()
  157. expected = "\u2588\u2580\u2580\u2580\u2580\u2580\u2588"
  158. assert printed[: len(expected)] == expected
  159. f = io.StringIO()
  160. f.isatty = lambda: True
  161. qr.print_ascii(out=f, tty=True)
  162. printed = f.getvalue()
  163. f.close()
  164. expected = "\x1b[48;5;232m\x1b[38;5;255m" + "\xa0\u2584\u2584\u2584\u2584\u2584\xa0"
  165. assert printed[: len(expected)] == expected
  166. def test_print_tty_stdout():
  167. qr = qrcode.QRCode()
  168. with mock.patch("sys.stdout") as fake_stdout:
  169. fake_stdout.isatty.return_value = None
  170. pytest.raises(OSError, qr.print_tty)
  171. assert fake_stdout.isatty.called
  172. def test_print_tty():
  173. qr = qrcode.QRCode()
  174. f = io.StringIO()
  175. f.isatty = lambda: True
  176. qr.print_tty(out=f)
  177. printed = f.getvalue()
  178. f.close()
  179. BOLD_WHITE_BG = "\x1b[1;47m"
  180. BLACK_BG = "\x1b[40m"
  181. WHITE_BLOCK = BOLD_WHITE_BG + " " + BLACK_BG
  182. EOL = "\x1b[0m\n"
  183. expected = BOLD_WHITE_BG + " " * 23 + EOL + WHITE_BLOCK + " " * 7 + WHITE_BLOCK
  184. assert printed[: len(expected)] == expected
  185. def test_get_matrix():
  186. qr = qrcode.QRCode(border=0)
  187. qr.add_data("1")
  188. assert qr.get_matrix() == qr.modules
  189. def test_get_matrix_border():
  190. qr = qrcode.QRCode(border=1)
  191. qr.add_data("1")
  192. matrix = [row[1:-1] for row in qr.get_matrix()[1:-1]]
  193. assert matrix == qr.modules
  194. def test_negative_size_at_construction():
  195. with pytest.raises(ValueError):
  196. qrcode.QRCode(box_size=-1)
  197. def test_negative_size_at_usage():
  198. qr = qrcode.QRCode()
  199. qr.box_size = -1
  200. with pytest.raises(ValueError):
  201. qr.make_image()