Home | History | Annotate | Download | only in port
      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 
     29 import optparse
     30 import sys
     31 import tempfile
     32 import unittest
     33 
     34 from webkitpy.common.system.executive import Executive, ScriptError
     35 from webkitpy.common.system import executive_mock
     36 from webkitpy.common.system.filesystem_mock import MockFileSystem
     37 from webkitpy.common.system import outputcapture
     38 from webkitpy.common.system.path import abspath_to_uri
     39 from webkitpy.thirdparty.mock import Mock
     40 from webkitpy.tool import mocktool
     41 
     42 import base
     43 import config
     44 import config_mock
     45 
     46 
     47 class 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 
    263 class 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 
    305 class 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 
    321 if __name__ == '__main__':
    322     unittest.main()
    323