1# -*- coding: utf-8 -*-
2import os
3import pytest
4from mock import Mock
5from six.moves import urllib
6
7from gtts.tts import gTTS, gTTSError
8from gtts.lang import _main_langs, _extra_langs
9
10# Testing all languages takes some time.
11# Set TEST_LANGS envvar to choose languages to test.
12#  * 'main': Languages extracted from the Web
13#  * 'extra': Languagee set in Languages.EXTRA_LANGS
14#  * 'all': All of the above
15#  * <csv>: Languages tags list to test
16# Unset TEST_LANGS to test everything ('all')
17# See: langs_dict()
18
19
20"""Construct a dict of suites of languages to test.
21{ '<suite name>' : <list or dict of language tags> }
22
23ex.: { 'fetch' : {'en': 'English', 'fr': 'French'},
24       'extra' : {'en': 'English', 'fr': 'French'} }
25ex.: { 'environ' : ['en', 'fr'] }
26"""
27env = os.environ.get('TEST_LANGS')
28if not env or env == 'all':
29    langs = _main_langs()
30    langs.update(_extra_langs())
31elif env == 'main':
32    langs = _main_langs()
33elif env == 'extra':
34    langs = _extra_langs()
35else:
36    env_langs = {l: l for l in env.split(',') if l}
37    langs = env_langs
38
39
40@pytest.mark.net
41@pytest.mark.parametrize('lang', langs.keys(), ids=list(langs.values()))
42def test_TTS(tmp_path, lang):
43    """Test all supported languages and file save"""
44
45    text = "This is a test"
46    """Create output .mp3 file successfully"""
47    for slow in (False, True):
48        filename = tmp_path / 'test_{}_.mp3'.format(lang)
49        # Create gTTS and save
50        tts = gTTS(text=text, lang=lang, slow=slow)
51        tts.save(filename)
52
53        # Check if files created is > 1.5
54        assert filename.stat().st_size > 1500
55
56
57@pytest.mark.net
58def test_unsupported_language_check():
59    """Raise ValueError on unsupported language (with language check)"""
60    lang = 'xx'
61    text = "Lorem ipsum"
62    check = True
63    with pytest.raises(ValueError):
64        gTTS(text=text, lang=lang, lang_check=check)
65
66
67def test_empty_string():
68    """Raise AssertionError on empty string"""
69    text = ""
70    with pytest.raises(AssertionError):
71        gTTS(text=text)
72
73
74def test_no_text_parts(tmp_path):
75    """Raises AssertionError on no content to send to API (no text_parts)"""
76    text = "                                                                                                          ..,\n"
77    with pytest.raises(AssertionError):
78        filename = tmp_path / 'no_content.txt'
79        tts = gTTS(text=text)
80        tts.save(filename)
81
82
83# Test write_to_fp()/save() cases not covered elsewhere in this file
84
85def test_bad_fp_type():
86    """Raise TypeError if fp is not a file-like object (no .write())"""
87    # Create gTTS and save
88    tts = gTTS(text='test')
89    with pytest.raises(TypeError):
90        tts.write_to_fp(5)
91
92
93@pytest.mark.net
94def test_save(tmp_path):
95    """Save .mp3 file successfully"""
96    filename = tmp_path / 'save.mp3'
97    # Create gTTS and save
98    tts = gTTS(text='test')
99    tts.save(filename)
100
101    # Check if file created is > 2k
102    assert filename.stat().st_size > 2000
103
104
105@pytest.mark.net
106def test_get_urls():
107    """Get request URLs list"""
108
109    tts = gTTS(text='test', tld='com', lang='en-uk')
110    urls = tts.get_urls()
111
112    # Check the url
113    r = urllib.parse.urlparse(urls[0])
114    assert r.scheme == 'https'
115    assert r.netloc == 'translate.google.com'
116    assert r.path == '/_/TranslateWebserverUi/data/batchexecute'
117
118
119@pytest.mark.net
120def test_get_bodies():
121    """get request bodies list"""
122    tts = gTTS(text='test', tld='com', lang='en-uk')
123    body = tts.get_bodies()[0]
124    assert 'test' in body
125    assert 'en-uk' in body
126
127
128def test_msg():
129    """Test gTTsError internal exception handling
130    Set exception message successfully"""
131    error1 = gTTSError('test')
132    assert 'test' == error1.msg
133
134    error2 = gTTSError()
135    assert error2.msg is None
136
137
138def test_infer_msg():
139    """Infer message sucessfully based on context"""
140
141    # Without response:
142
143    # Bad TLD
144    ttsTLD = Mock(tld='invalid')
145    errorTLD = gTTSError(tts=ttsTLD)
146    assert errorTLD.msg == "Failed to connect. Probable cause: Host 'https://translate.google.invalid/' is not reachable"
147
148    # With response:
149
150    # 403
151    tts403 = Mock()
152    response403 = Mock(status_code=403, reason='aaa')
153    error403 = gTTSError(tts=tts403, response=response403)
154    assert error403.msg == "403 (aaa) from TTS API. Probable cause: Bad token or upstream API changes"
155
156    # 200 (and not lang_check)
157    tts200 = Mock(lang='xx', lang_check=False)
158    response404 = Mock(status_code=200, reason='bbb')
159    error200 = gTTSError(tts=tts200, response=response404)
160    assert error200.msg == "200 (bbb) from TTS API. Probable cause: No audio stream in response. Unsupported language 'xx'"
161
162    # >= 500
163    tts500 = Mock()
164    response500 = Mock(status_code=500, reason='ccc')
165    error500 = gTTSError(tts=tts500, response=response500)
166    assert error500.msg == "500 (ccc) from TTS API. Probable cause: Uptream API error. Try again later."
167
168    # Unknown (ex. 100)
169    tts100 = Mock()
170    response100 = Mock(status_code=100, reason='ddd')
171    error100 = gTTSError(tts=tts100, response=response100)
172    assert error100.msg == "100 (ddd) from TTS API. Probable cause: Unknown"
173
174
175@pytest.mark.net
176def test_WebRequest(tmp_path):
177    """Test Web Requests"""
178
179    text = "Lorem ipsum"
180
181    """Raise gTTSError on unsupported language (without language check)"""
182    lang = 'xx'
183    check = False
184
185    with pytest.raises(gTTSError):
186        filename = tmp_path / 'xx.txt'
187        # Create gTTS
188        tts = gTTS(text=text, lang=lang, lang_check=check)
189        tts.save(filename)
190
191
192if __name__ == '__main__':
193    pytest.main(['-x', __file__])
194