test_cli.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. # -*- coding: utf-8 -*-
  2. import pytest
  3. import re
  4. import os
  5. from click.testing import CliRunner
  6. from gtts.cli import tts_cli
  7. # Need to look into gTTS' log output to test proper instantiation
  8. # - Use testfixtures.LogCapture() b/c TestCase.assertLogs() needs py3.4+
  9. # - Clear 'gtts' logger handlers (set in gtts.cli) to reduce test noise
  10. import logging
  11. from testfixtures import LogCapture
  12. logger = logging.getLogger("gtts")
  13. logger.handlers = []
  14. """Test options and arguments"""
  15. def runner(args, input=None):
  16. return CliRunner().invoke(tts_cli, args, input)
  17. def runner_debug(args, input=None):
  18. return CliRunner().invoke(tts_cli, args + ["--debug"], input)
  19. # <text> tests
  20. def test_text_no_text_or_file():
  21. """One of <test> (arg) and <file> <opt> should be set"""
  22. result = runner_debug([])
  23. assert "<file> required" in result.output
  24. assert result.exit_code != 0
  25. def test_text_text_and_file(tmp_path):
  26. """<test> (arg) and <file> <opt> should not be set together"""
  27. filename = tmp_path / "test_and_file.txt"
  28. filename.touch()
  29. result = runner_debug(["--file", str(filename), "test"])
  30. assert "<file> can't be used together" in result.output
  31. assert result.exit_code != 0
  32. def test_text_empty(tmp_path):
  33. """Exit on no text to speak (via <file>)"""
  34. filename = tmp_path / "text_empty.txt"
  35. filename.touch()
  36. result = runner_debug(["--file", str(filename)])
  37. assert "No text to speak" in result.output
  38. assert result.exit_code != 0
  39. # <file> tests
  40. def test_file_not_exists():
  41. """<file> should exist"""
  42. result = runner_debug(["--file", "notexist.txt", "test"])
  43. assert "No such file or directory" in result.output
  44. assert result.exit_code != 0
  45. # <all> tests
  46. @pytest.mark.net
  47. def test_all():
  48. """Option <all> should return a list of languages"""
  49. result = runner(["--all"])
  50. # One or more of " xy: name" (\n optional to match the last)
  51. # Ex. "<start> xx: xxxxx\n xx-yy: xxxxx\n xx: xxxxx<end>"
  52. assert re.match(r"^(?:\s{2}(\w{2}|\w{2}-\w{2}): .+\n?)+$", result.output)
  53. assert result.exit_code == 0
  54. # <lang> tests
  55. @pytest.mark.net
  56. def test_lang_not_valid():
  57. """Invalid <lang> should display an error"""
  58. result = runner(["--lang", "xx", "test"])
  59. assert "xx' not in list of supported languages" in result.output
  60. assert result.exit_code != 0
  61. @pytest.mark.net
  62. def test_lang_nocheck():
  63. """Invalid <lang> (with <nocheck>) should display an error message from gtts"""
  64. with LogCapture() as lc:
  65. result = runner_debug(["--lang", "xx", "--nocheck", "test"])
  66. log = str(lc)
  67. assert "lang: xx" in log
  68. assert "lang_check: False" in log
  69. assert "Unsupported language 'xx'" in result.output
  70. assert result.exit_code != 0
  71. # Param set tests
  72. @pytest.mark.net
  73. def test_params_set():
  74. """Options should set gTTS instance arguments (read from debug log)"""
  75. with LogCapture() as lc:
  76. result = runner_debug(
  77. ["--lang", "fr", "--tld", "es", "--slow", "--nocheck", "test"]
  78. )
  79. log = str(lc)
  80. assert "lang: fr" in log
  81. assert "tld: es" in log
  82. assert "lang_check: False" in log
  83. assert "slow: True" in log
  84. assert "text: test" in log
  85. assert result.exit_code == 0
  86. # Test all input methods
  87. pwd = os.path.dirname(__file__)
  88. # Text for stdin ('-' for <text> or <file>)
  89. textstdin = """stdin
  90. test
  91. 123"""
  92. # Text for stdin ('-' for <text> or <file>) (Unicode)
  93. textstdin_unicode = u"""你吃饭了吗?
  94. 你最喜欢哪部电影?
  95. 我饿了,我要去做饭了。"""
  96. # Text for <text> and <file>
  97. text = """Can you make pink a little more pinkish can you make pink a little more pinkish, nor can you make the font bigger?
  98. How much will it cost the website doesn't have the theme i was going for."""
  99. textfile_ascii = os.path.join(pwd, "input_files", "test_cli_test_ascii.txt")
  100. # Text for <text> and <file> (Unicode)
  101. text_unicode = u"""这是一个三岁的小孩
  102. 在讲述她从一系列照片里看到的东西。
  103. 对这个世界, 她也许还有很多要学的东西,
  104. 但在一个重要的任务上, 她已经是专家了:
  105. 去理解她所看到的东西。"""
  106. textfile_utf8 = os.path.join(pwd, "input_files", "test_cli_test_utf8.txt")
  107. """
  108. Method that mimics's LogCapture's __str__ method to make
  109. the string in the comprehension a unicode literal for P2.7
  110. https://github.com/Simplistix/testfixtures/blob/32c87902cb111b7ede5a6abca9b597db551c88ef/testfixtures/logcapture.py#L149
  111. """
  112. def logcapture_str(lc):
  113. if not lc.records:
  114. return "No logging captured"
  115. return "\n".join([u"%s %s\n %s" % r for r in lc.actual()])
  116. @pytest.mark.net
  117. def test_stdin_text():
  118. with LogCapture() as lc:
  119. result = runner_debug(["-"], textstdin)
  120. log = logcapture_str(lc)
  121. assert "text: %s" % textstdin in log
  122. assert result.exit_code == 0
  123. @pytest.mark.net
  124. def test_stdin_text_unicode():
  125. with LogCapture() as lc:
  126. result = runner_debug(["-"], textstdin_unicode)
  127. log = logcapture_str(lc)
  128. assert "text: %s" % textstdin_unicode in log
  129. assert result.exit_code == 0
  130. @pytest.mark.net
  131. def test_stdin_file():
  132. with LogCapture() as lc:
  133. result = runner_debug(["--file", "-"], textstdin)
  134. log = logcapture_str(lc)
  135. assert "text: %s" % textstdin in log
  136. assert result.exit_code == 0
  137. @pytest.mark.net
  138. def test_stdin_file_unicode():
  139. with LogCapture() as lc:
  140. result = runner_debug(["--file", "-"], textstdin_unicode)
  141. log = logcapture_str(lc)
  142. assert "text: %s" % textstdin_unicode in log
  143. assert result.exit_code == 0
  144. @pytest.mark.net
  145. def test_text():
  146. with LogCapture() as lc:
  147. result = runner_debug([text])
  148. log = logcapture_str(lc)
  149. assert "text: %s" % text in log
  150. assert result.exit_code == 0
  151. @pytest.mark.net
  152. def test_text_unicode():
  153. with LogCapture() as lc:
  154. result = runner_debug([text_unicode])
  155. log = logcapture_str(lc)
  156. assert "text: %s" % text_unicode in log
  157. assert result.exit_code == 0
  158. @pytest.mark.net
  159. def test_file_ascii():
  160. with LogCapture() as lc:
  161. result = runner_debug(["--file", textfile_ascii])
  162. log = logcapture_str(lc)
  163. assert "text: %s" % text in log
  164. assert result.exit_code == 0
  165. @pytest.mark.net
  166. def test_file_utf8():
  167. with LogCapture() as lc:
  168. result = runner_debug(["--file", textfile_utf8])
  169. log = logcapture_str(lc)
  170. assert "text: %s" % text_unicode in log
  171. assert result.exit_code == 0
  172. @pytest.mark.net
  173. def test_stdout():
  174. result = runner(["test"])
  175. # The MP3 encoding (LAME 3.99.5) used to leave a signature in the raw output
  176. # This no longer appears to be the case
  177. assert result.exit_code == 0
  178. @pytest.mark.net
  179. def test_file(tmp_path):
  180. filename = tmp_path / "out.mp3"
  181. result = runner(["test", "--output", str(filename)])
  182. # Check if files created is > 2k
  183. assert filename.stat().st_size > 2000
  184. assert result.exit_code == 0
  185. if __name__ == "__main__":
  186. pytest.main(["-x", __file__])