• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (C) 2010 Google Inc. All rights reserved.
2#
3# Redistribution and use in source and binary forms, with or without
4# modification, are permitted provided that the following conditions are
5# met:
6#
7#    * Redistributions of source code must retain the above copyright
8# notice, this list of conditions and the following disclaimer.
9#    * Redistributions in binary form must reproduce the above
10# copyright notice, this list of conditions and the following disclaimer
11# in the documentation and/or other materials provided with the
12# distribution.
13#    * Neither the name of Google Inc. nor the names of its
14# contributors may be used to endorse or promote products derived from
15# this software without specific prior written permission.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29import optparse
30import sys
31import tempfile
32import unittest
33
34from webkitpy.common.system.executive import Executive, ScriptError
35from webkitpy.common.system import executive_mock
36from webkitpy.common.system.filesystem_mock import MockFileSystem
37from webkitpy.common.system import outputcapture
38from webkitpy.common.system.path import abspath_to_uri
39from webkitpy.thirdparty.mock import Mock
40from webkitpy.tool import mocktool
41
42import base
43import config
44import config_mock
45
46
47class PortTest(unittest.TestCase):
48    def test_format_wdiff_output_as_html(self):
49        output = "OUTPUT %s %s %s" % (base.Port._WDIFF_DEL, base.Port._WDIFF_ADD, base.Port._WDIFF_END)
50        html = base.Port()._format_wdiff_output_as_html(output)
51        expected_html = "<head><style>.del { background: #faa; } .add { background: #afa; }</style></head><pre>OUTPUT <span class=del> <span class=add> </span></pre>"
52        self.assertEqual(html, expected_html)
53
54    def test_wdiff_command(self):
55        port = base.Port()
56        port._path_to_wdiff = lambda: "/path/to/wdiff"
57        command = port._wdiff_command("/actual/path", "/expected/path")
58        expected_command = [
59            "/path/to/wdiff",
60            "--start-delete=##WDIFF_DEL##",
61            "--end-delete=##WDIFF_END##",
62            "--start-insert=##WDIFF_ADD##",
63            "--end-insert=##WDIFF_END##",
64            "/actual/path",
65            "/expected/path",
66        ]
67        self.assertEqual(command, expected_command)
68
69    def _file_with_contents(self, contents, encoding="utf-8"):
70        new_file = tempfile.NamedTemporaryFile()
71        new_file.write(contents.encode(encoding))
72        new_file.flush()
73        return new_file
74
75    def test_pretty_patch_os_error(self):
76        port = base.Port(executive=executive_mock.MockExecutive2(exception=OSError))
77        oc = outputcapture.OutputCapture()
78        oc.capture_output()
79        self.assertEqual(port.pretty_patch_text("patch.txt"),
80                         port._pretty_patch_error_html)
81
82        # This tests repeated calls to make sure we cache the result.
83        self.assertEqual(port.pretty_patch_text("patch.txt"),
84                         port._pretty_patch_error_html)
85        oc.restore_output()
86
87    def test_pretty_patch_script_error(self):
88        # FIXME: This is some ugly white-box test hacking ...
89        port = base.Port(executive=executive_mock.MockExecutive2(exception=ScriptError))
90        port._pretty_patch_available = True
91        self.assertEqual(port.pretty_patch_text("patch.txt"),
92                         port._pretty_patch_error_html)
93
94        # This tests repeated calls to make sure we cache the result.
95        self.assertEqual(port.pretty_patch_text("patch.txt"),
96                         port._pretty_patch_error_html)
97
98    def test_run_wdiff(self):
99        executive = Executive()
100        # This may fail on some systems.  We could ask the port
101        # object for the wdiff path, but since we don't know what
102        # port object to use, this is sufficient for now.
103        try:
104            wdiff_path = executive.run_command(["which", "wdiff"]).rstrip()
105        except Exception, e:
106            wdiff_path = None
107
108        port = base.Port()
109        port._path_to_wdiff = lambda: wdiff_path
110
111        if wdiff_path:
112            # "with tempfile.NamedTemporaryFile() as actual" does not seem to work in Python 2.5
113            actual = self._file_with_contents(u"foo")
114            expected = self._file_with_contents(u"bar")
115            wdiff = port._run_wdiff(actual.name, expected.name)
116            expected_wdiff = "<head><style>.del { background: #faa; } .add { background: #afa; }</style></head><pre><span class=del>foo</span><span class=add>bar</span></pre>"
117            self.assertEqual(wdiff, expected_wdiff)
118            # Running the full wdiff_text method should give the same result.
119            port._wdiff_available = True  # In case it's somehow already disabled.
120            wdiff = port.wdiff_text(actual.name, expected.name)
121            self.assertEqual(wdiff, expected_wdiff)
122            # wdiff should still be available after running wdiff_text with a valid diff.
123            self.assertTrue(port._wdiff_available)
124            actual.close()
125            expected.close()
126
127            # Bogus paths should raise a script error.
128            self.assertRaises(ScriptError, port._run_wdiff, "/does/not/exist", "/does/not/exist2")
129            self.assertRaises(ScriptError, port.wdiff_text, "/does/not/exist", "/does/not/exist2")
130            # wdiff will still be available after running wdiff_text with invalid paths.
131            self.assertTrue(port._wdiff_available)
132            base._wdiff_available = True
133
134        # If wdiff does not exist _run_wdiff should throw an OSError.
135        port._path_to_wdiff = lambda: "/invalid/path/to/wdiff"
136        self.assertRaises(OSError, port._run_wdiff, "foo", "bar")
137
138        # wdiff_text should not throw an error if wdiff does not exist.
139        self.assertEqual(port.wdiff_text("foo", "bar"), "")
140        # However wdiff should not be available after running wdiff_text if wdiff is missing.
141        self.assertFalse(port._wdiff_available)
142
143    def test_diff_text(self):
144        port = base.Port()
145        # Make sure that we don't run into decoding exceptions when the
146        # filenames are unicode, with regular or malformed input (expected or
147        # actual input is always raw bytes, not unicode).
148        port.diff_text('exp', 'act', 'exp.txt', 'act.txt')
149        port.diff_text('exp', 'act', u'exp.txt', 'act.txt')
150        port.diff_text('exp', 'act', u'a\xac\u1234\u20ac\U00008000', 'act.txt')
151
152        port.diff_text('exp' + chr(255), 'act', 'exp.txt', 'act.txt')
153        port.diff_text('exp' + chr(255), 'act', u'exp.txt', 'act.txt')
154
155        # Though expected and actual files should always be read in with no
156        # encoding (and be stored as str objects), test unicode inputs just to
157        # be safe.
158        port.diff_text(u'exp', 'act', 'exp.txt', 'act.txt')
159        port.diff_text(
160            u'a\xac\u1234\u20ac\U00008000', 'act', 'exp.txt', 'act.txt')
161
162        # And make sure we actually get diff output.
163        diff = port.diff_text('foo', 'bar', 'exp.txt', 'act.txt')
164        self.assertTrue('foo' in diff)
165        self.assertTrue('bar' in diff)
166        self.assertTrue('exp.txt' in diff)
167        self.assertTrue('act.txt' in diff)
168        self.assertFalse('nosuchthing' in diff)
169
170    def test_default_configuration_notfound(self):
171        # Test that we delegate to the config object properly.
172        port = base.Port(config=config_mock.MockConfig(default_configuration='default'))
173        self.assertEqual(port.default_configuration(), 'default')
174
175    def test_layout_tests_skipping(self):
176        port = base.Port()
177        port.skipped_layout_tests = lambda: ['foo/bar.html', 'media']
178        self.assertTrue(port.skips_layout_test('foo/bar.html'))
179        self.assertTrue(port.skips_layout_test('media/video-zoom.html'))
180        self.assertFalse(port.skips_layout_test('foo/foo.html'))
181
182    def test_setup_test_run(self):
183        port = base.Port()
184        # This routine is a no-op. We just test it for coverage.
185        port.setup_test_run()
186
187    def test_test_dirs(self):
188        port = base.Port()
189        dirs = port.test_dirs()
190        self.assertTrue('canvas' in dirs)
191        self.assertTrue('css2.1' in dirs)
192
193    def test_filename_to_uri(self):
194        port = base.Port()
195        layout_test_dir = port.layout_tests_dir()
196        test_file = port._filesystem.join(layout_test_dir, "foo", "bar.html")
197
198        # On Windows, absolute paths are of the form "c:\foo.txt". However,
199        # all current browsers (except for Opera) normalize file URLs by
200        # prepending an additional "/" as if the absolute path was
201        # "/c:/foo.txt". This means that all file URLs end up with "file:///"
202        # at the beginning.
203        if sys.platform == 'win32':
204            prefix = "file:///"
205            path = test_file.replace("\\", "/")
206        else:
207            prefix = "file://"
208            path = test_file
209
210        self.assertEqual(port.filename_to_uri(test_file),
211                         abspath_to_uri(test_file))
212
213    def test_get_option__set(self):
214        options, args = optparse.OptionParser().parse_args([])
215        options.foo = 'bar'
216        port = base.Port(options=options)
217        self.assertEqual(port.get_option('foo'), 'bar')
218
219    def test_get_option__unset(self):
220        port = base.Port()
221        self.assertEqual(port.get_option('foo'), None)
222
223    def test_get_option__default(self):
224        port = base.Port()
225        self.assertEqual(port.get_option('foo', 'bar'), 'bar')
226
227    def test_name__unset(self):
228        port = base.Port()
229        self.assertEqual(port.name(), None)
230
231    def test_name__set(self):
232        port = base.Port(port_name='foo')
233        self.assertEqual(port.name(), 'foo')
234
235    def test_additional_platform_directory(self):
236        filesystem = MockFileSystem()
237        options, args = optparse.OptionParser().parse_args([])
238        port = base.Port(port_name='foo', filesystem=filesystem, options=options)
239        port.baseline_search_path = lambda: []
240        layout_test_dir = port.layout_tests_dir()
241        test_file = filesystem.join(layout_test_dir, 'fast', 'test.html')
242
243        # No additional platform directory
244        self.assertEqual(
245            port.expected_baselines(test_file, '.txt'),
246            [(None, 'fast/test-expected.txt')])
247
248        # Simple additional platform directory
249        options.additional_platform_directory = ['/tmp/local-baselines']
250        filesystem.files = {
251            '/tmp/local-baselines/fast/test-expected.txt': 'foo',
252        }
253        self.assertEqual(
254            port.expected_baselines(test_file, '.txt'),
255            [('/tmp/local-baselines', 'fast/test-expected.txt')])
256
257        # Multiple additional platform directories
258        options.additional_platform_directory = ['/foo', '/tmp/local-baselines']
259        self.assertEqual(
260            port.expected_baselines(test_file, '.txt'),
261            [('/tmp/local-baselines', 'fast/test-expected.txt')])
262
263class VirtualTest(unittest.TestCase):
264    """Tests that various methods expected to be virtual are."""
265    def assertVirtual(self, method, *args, **kwargs):
266        self.assertRaises(NotImplementedError, method, *args, **kwargs)
267
268    def test_virtual_methods(self):
269        port = base.Port()
270        self.assertVirtual(port.baseline_path)
271        self.assertVirtual(port.baseline_search_path)
272        self.assertVirtual(port.check_build, None)
273        self.assertVirtual(port.check_image_diff)
274        self.assertVirtual(port.create_driver, 0)
275        self.assertVirtual(port.diff_image, None, None)
276        self.assertVirtual(port.path_to_test_expectations_file)
277        self.assertVirtual(port.default_results_directory)
278        self.assertVirtual(port.test_expectations)
279        self.assertVirtual(port._path_to_apache)
280        self.assertVirtual(port._path_to_apache_config_file)
281        self.assertVirtual(port._path_to_driver)
282        self.assertVirtual(port._path_to_helper)
283        self.assertVirtual(port._path_to_image_diff)
284        self.assertVirtual(port._path_to_lighttpd)
285        self.assertVirtual(port._path_to_lighttpd_modules)
286        self.assertVirtual(port._path_to_lighttpd_php)
287        self.assertVirtual(port._path_to_wdiff)
288        self.assertVirtual(port._shut_down_http_server, None)
289
290    def test_virtual_driver_method(self):
291        self.assertRaises(NotImplementedError, base.Driver, base.Port(),
292                          0)
293
294    def test_virtual_driver_methods(self):
295        class VirtualDriver(base.Driver):
296            def __init__(self):
297                pass
298
299        driver = VirtualDriver()
300        self.assertVirtual(driver.run_test, None)
301        self.assertVirtual(driver.poll)
302        self.assertVirtual(driver.stop)
303
304
305class DriverTest(unittest.TestCase):
306
307    def _assert_wrapper(self, wrapper_string, expected_wrapper):
308        wrapper = base.Driver._command_wrapper(wrapper_string)
309        self.assertEqual(wrapper, expected_wrapper)
310
311    def test_command_wrapper(self):
312        self._assert_wrapper(None, [])
313        self._assert_wrapper("valgrind", ["valgrind"])
314
315        # Validate that shlex works as expected.
316        command_with_spaces = "valgrind --smc-check=\"check with spaces!\" --foo"
317        expected_parse = ["valgrind", "--smc-check=check with spaces!", "--foo"]
318        self._assert_wrapper(command_with_spaces, expected_parse)
319
320
321if __name__ == '__main__':
322    unittest.main()
323