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