1import webbrowser
2import unittest
3import os
4import sys
5import subprocess
6from unittest import mock
7from test import support
8from test.support import import_helper
9from test.support import os_helper
10
11if not support.has_subprocess_support:
12    raise unittest.SkipTest("test webserver requires subprocess")
13
14URL = 'http://www.example.com'
15CMD_NAME = 'test'
16
17
18class PopenMock(mock.MagicMock):
19
20    def poll(self):
21        return 0
22
23    def wait(self, seconds=None):
24        return 0
25
26
27class CommandTestMixin:
28
29    def _test(self, meth, *, args=[URL], kw={}, options, arguments):
30        """Given a web browser instance method name along with arguments and
31        keywords for same (which defaults to the single argument URL), creates
32        a browser instance from the class pointed to by self.browser, calls the
33        indicated instance method with the indicated arguments, and compares
34        the resulting options and arguments passed to Popen by the browser
35        instance against the 'options' and 'args' lists.  Options are compared
36        in a position independent fashion, and the arguments are compared in
37        sequence order to whatever is left over after removing the options.
38
39        """
40        popen = PopenMock()
41        support.patch(self, subprocess, 'Popen', popen)
42        browser = self.browser_class(name=CMD_NAME)
43        getattr(browser, meth)(*args, **kw)
44        popen_args = subprocess.Popen.call_args[0][0]
45        self.assertEqual(popen_args[0], CMD_NAME)
46        popen_args.pop(0)
47        for option in options:
48            self.assertIn(option, popen_args)
49            popen_args.pop(popen_args.index(option))
50        self.assertEqual(popen_args, arguments)
51
52
53class GenericBrowserCommandTest(CommandTestMixin, unittest.TestCase):
54
55    browser_class = webbrowser.GenericBrowser
56
57    def test_open(self):
58        self._test('open',
59                   options=[],
60                   arguments=[URL])
61
62
63class BackgroundBrowserCommandTest(CommandTestMixin, unittest.TestCase):
64
65    browser_class = webbrowser.BackgroundBrowser
66
67    def test_open(self):
68        self._test('open',
69                   options=[],
70                   arguments=[URL])
71
72
73class ChromeCommandTest(CommandTestMixin, unittest.TestCase):
74
75    browser_class = webbrowser.Chrome
76
77    def test_open(self):
78        self._test('open',
79                   options=[],
80                   arguments=[URL])
81
82    def test_open_with_autoraise_false(self):
83        self._test('open', kw=dict(autoraise=False),
84                   options=[],
85                   arguments=[URL])
86
87    def test_open_new(self):
88        self._test('open_new',
89                   options=['--new-window'],
90                   arguments=[URL])
91
92    def test_open_new_tab(self):
93        self._test('open_new_tab',
94                   options=[],
95                   arguments=[URL])
96
97
98class MozillaCommandTest(CommandTestMixin, unittest.TestCase):
99
100    browser_class = webbrowser.Mozilla
101
102    def test_open(self):
103        self._test('open',
104                   options=[],
105                   arguments=[URL])
106
107    def test_open_with_autoraise_false(self):
108        self._test('open', kw=dict(autoraise=False),
109                   options=[],
110                   arguments=[URL])
111
112    def test_open_new(self):
113        self._test('open_new',
114                   options=[],
115                   arguments=['-new-window', URL])
116
117    def test_open_new_tab(self):
118        self._test('open_new_tab',
119                   options=[],
120                   arguments=['-new-tab', URL])
121
122
123class NetscapeCommandTest(CommandTestMixin, unittest.TestCase):
124
125    browser_class = webbrowser.Netscape
126
127    def test_open(self):
128        self._test('open',
129                   options=['-raise', '-remote'],
130                   arguments=['openURL({})'.format(URL)])
131
132    def test_open_with_autoraise_false(self):
133        self._test('open', kw=dict(autoraise=False),
134                   options=['-noraise', '-remote'],
135                   arguments=['openURL({})'.format(URL)])
136
137    def test_open_new(self):
138        self._test('open_new',
139                   options=['-raise', '-remote'],
140                   arguments=['openURL({},new-window)'.format(URL)])
141
142    def test_open_new_tab(self):
143        self._test('open_new_tab',
144                   options=['-raise', '-remote'],
145                   arguments=['openURL({},new-tab)'.format(URL)])
146
147
148class GaleonCommandTest(CommandTestMixin, unittest.TestCase):
149
150    browser_class = webbrowser.Galeon
151
152    def test_open(self):
153        self._test('open',
154                   options=['-n'],
155                   arguments=[URL])
156
157    def test_open_with_autoraise_false(self):
158        self._test('open', kw=dict(autoraise=False),
159                   options=['-noraise', '-n'],
160                   arguments=[URL])
161
162    def test_open_new(self):
163        self._test('open_new',
164                   options=['-w'],
165                   arguments=[URL])
166
167    def test_open_new_tab(self):
168        self._test('open_new_tab',
169                   options=['-w'],
170                   arguments=[URL])
171
172
173class OperaCommandTest(CommandTestMixin, unittest.TestCase):
174
175    browser_class = webbrowser.Opera
176
177    def test_open(self):
178        self._test('open',
179                   options=[],
180                   arguments=[URL])
181
182    def test_open_with_autoraise_false(self):
183        self._test('open', kw=dict(autoraise=False),
184                   options=[],
185                   arguments=[URL])
186
187    def test_open_new(self):
188        self._test('open_new',
189                   options=['--new-window'],
190                   arguments=[URL])
191
192    def test_open_new_tab(self):
193        self._test('open_new_tab',
194                   options=[],
195                   arguments=[URL])
196
197
198class ELinksCommandTest(CommandTestMixin, unittest.TestCase):
199
200    browser_class = webbrowser.Elinks
201
202    def test_open(self):
203        self._test('open', options=['-remote'],
204                           arguments=['openURL({})'.format(URL)])
205
206    def test_open_with_autoraise_false(self):
207        self._test('open',
208                   options=['-remote'],
209                   arguments=['openURL({})'.format(URL)])
210
211    def test_open_new(self):
212        self._test('open_new',
213                   options=['-remote'],
214                   arguments=['openURL({},new-window)'.format(URL)])
215
216    def test_open_new_tab(self):
217        self._test('open_new_tab',
218                   options=['-remote'],
219                   arguments=['openURL({},new-tab)'.format(URL)])
220
221
222class BrowserRegistrationTest(unittest.TestCase):
223
224    def setUp(self):
225        # Ensure we don't alter the real registered browser details
226        self._saved_tryorder = webbrowser._tryorder
227        webbrowser._tryorder = []
228        self._saved_browsers = webbrowser._browsers
229        webbrowser._browsers = {}
230
231    def tearDown(self):
232        webbrowser._tryorder = self._saved_tryorder
233        webbrowser._browsers = self._saved_browsers
234
235    def _check_registration(self, preferred):
236        class ExampleBrowser:
237            pass
238
239        expected_tryorder = []
240        expected_browsers = {}
241
242        self.assertEqual(webbrowser._tryorder, expected_tryorder)
243        self.assertEqual(webbrowser._browsers, expected_browsers)
244
245        webbrowser.register('Example1', ExampleBrowser)
246        expected_tryorder = ['Example1']
247        expected_browsers['example1'] = [ExampleBrowser, None]
248        self.assertEqual(webbrowser._tryorder, expected_tryorder)
249        self.assertEqual(webbrowser._browsers, expected_browsers)
250
251        instance = ExampleBrowser()
252        if preferred is not None:
253            webbrowser.register('example2', ExampleBrowser, instance,
254                                preferred=preferred)
255        else:
256            webbrowser.register('example2', ExampleBrowser, instance)
257        if preferred:
258            expected_tryorder = ['example2', 'Example1']
259        else:
260            expected_tryorder = ['Example1', 'example2']
261        expected_browsers['example2'] = [ExampleBrowser, instance]
262        self.assertEqual(webbrowser._tryorder, expected_tryorder)
263        self.assertEqual(webbrowser._browsers, expected_browsers)
264
265    def test_register(self):
266        self._check_registration(preferred=False)
267
268    def test_register_default(self):
269        self._check_registration(preferred=None)
270
271    def test_register_preferred(self):
272        self._check_registration(preferred=True)
273
274
275class ImportTest(unittest.TestCase):
276    def test_register(self):
277        webbrowser = import_helper.import_fresh_module('webbrowser')
278        self.assertIsNone(webbrowser._tryorder)
279        self.assertFalse(webbrowser._browsers)
280
281        class ExampleBrowser:
282            pass
283        webbrowser.register('Example1', ExampleBrowser)
284        self.assertTrue(webbrowser._tryorder)
285        self.assertEqual(webbrowser._tryorder[-1], 'Example1')
286        self.assertTrue(webbrowser._browsers)
287        self.assertIn('example1', webbrowser._browsers)
288        self.assertEqual(webbrowser._browsers['example1'], [ExampleBrowser, None])
289
290    def test_get(self):
291        webbrowser = import_helper.import_fresh_module('webbrowser')
292        self.assertIsNone(webbrowser._tryorder)
293        self.assertFalse(webbrowser._browsers)
294
295        with self.assertRaises(webbrowser.Error):
296            webbrowser.get('fakebrowser')
297        self.assertIsNotNone(webbrowser._tryorder)
298
299    def test_synthesize(self):
300        webbrowser = import_helper.import_fresh_module('webbrowser')
301        name = os.path.basename(sys.executable).lower()
302        webbrowser.register(name, None, webbrowser.GenericBrowser(name))
303        webbrowser.get(sys.executable)
304
305    def test_environment(self):
306        webbrowser = import_helper.import_fresh_module('webbrowser')
307        try:
308            browser = webbrowser.get().name
309        except webbrowser.Error as err:
310            self.skipTest(str(err))
311        with os_helper.EnvironmentVarGuard() as env:
312            env["BROWSER"] = browser
313            webbrowser = import_helper.import_fresh_module('webbrowser')
314            webbrowser.get()
315
316    def test_environment_preferred(self):
317        webbrowser = import_helper.import_fresh_module('webbrowser')
318        try:
319            webbrowser.get()
320            least_preferred_browser = webbrowser.get(webbrowser._tryorder[-1]).name
321        except (webbrowser.Error, IndexError) as err:
322            self.skipTest(str(err))
323
324        with os_helper.EnvironmentVarGuard() as env:
325            env["BROWSER"] = least_preferred_browser
326            webbrowser = import_helper.import_fresh_module('webbrowser')
327            self.assertEqual(webbrowser.get().name, least_preferred_browser)
328
329        with os_helper.EnvironmentVarGuard() as env:
330            env["BROWSER"] = sys.executable
331            webbrowser = import_helper.import_fresh_module('webbrowser')
332            self.assertEqual(webbrowser.get().name, sys.executable)
333
334
335if __name__=='__main__':
336    unittest.main()
337