Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Tools / Scripts / webkitpy / layout_tests / port / base_unittest.py
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 logging
30 import optparse
31 import sys
32 import tempfile
33 import webkitpy.thirdparty.unittest2 as unittest
34
35 from webkitpy.common.system.executive import Executive, ScriptError
36 from webkitpy.common.system import executive_mock
37 from webkitpy.common.system.filesystem_mock import MockFileSystem
38 from webkitpy.common.system.outputcapture import OutputCapture
39 from webkitpy.common.system.path import abspath_to_uri
40 from webkitpy.thirdparty.mock import Mock
41 from webkitpy.tool.mocktool import MockOptions
42 from webkitpy.common.system.executive_mock import MockExecutive, MockExecutive2
43 from webkitpy.common.system.systemhost_mock import MockSystemHost
44
45 from webkitpy.layout_tests.port import Port, Driver, DriverOutput
46 from webkitpy.layout_tests.port.base import VirtualTestSuite
47 from webkitpy.layout_tests.port.test import add_unit_tests_to_mock_filesystem, TestPort
48
49 class PortTest(unittest.TestCase):
50     def make_port(self, executive=None, with_tests=False, port_name=None, **kwargs):
51         host = MockSystemHost()
52         if executive:
53             host.executive = executive
54         if with_tests:
55             add_unit_tests_to_mock_filesystem(host.filesystem)
56             return TestPort(host, **kwargs)
57         return Port(host, port_name or 'baseport', **kwargs)
58
59     def test_default_child_processes(self):
60         port = self.make_port()
61         self.assertIsNotNone(port.default_child_processes())
62
63     def test_format_wdiff_output_as_html(self):
64         output = "OUTPUT %s %s %s" % (Port._WDIFF_DEL, Port._WDIFF_ADD, Port._WDIFF_END)
65         html = self.make_port()._format_wdiff_output_as_html(output)
66         expected_html = "<head><style>.del { background: #faa; } .add { background: #afa; }</style></head><pre>OUTPUT <span class=del> <span class=add> </span></pre>"
67         self.assertEqual(html, expected_html)
68
69     def test_wdiff_command(self):
70         port = self.make_port()
71         port._path_to_wdiff = lambda: "/path/to/wdiff"
72         command = port._wdiff_command("/actual/path", "/expected/path")
73         expected_command = [
74             "/path/to/wdiff",
75             "--start-delete=##WDIFF_DEL##",
76             "--end-delete=##WDIFF_END##",
77             "--start-insert=##WDIFF_ADD##",
78             "--end-insert=##WDIFF_END##",
79             "/actual/path",
80             "/expected/path",
81         ]
82         self.assertEqual(command, expected_command)
83
84     def _file_with_contents(self, contents, encoding="utf-8"):
85         new_file = tempfile.NamedTemporaryFile()
86         new_file.write(contents.encode(encoding))
87         new_file.flush()
88         return new_file
89
90     def test_pretty_patch_os_error(self):
91         port = self.make_port(executive=executive_mock.MockExecutive2(exception=OSError))
92         oc = OutputCapture()
93         oc.capture_output()
94         self.assertEqual(port.pretty_patch_text("patch.txt"),
95                          port._pretty_patch_error_html)
96
97         # This tests repeated calls to make sure we cache the result.
98         self.assertEqual(port.pretty_patch_text("patch.txt"),
99                          port._pretty_patch_error_html)
100         oc.restore_output()
101
102     def test_pretty_patch_script_error(self):
103         # FIXME: This is some ugly white-box test hacking ...
104         port = self.make_port(executive=executive_mock.MockExecutive2(exception=ScriptError))
105         port._pretty_patch_available = True
106         self.assertEqual(port.pretty_patch_text("patch.txt"),
107                          port._pretty_patch_error_html)
108
109         # This tests repeated calls to make sure we cache the result.
110         self.assertEqual(port.pretty_patch_text("patch.txt"),
111                          port._pretty_patch_error_html)
112
113     def test_wdiff_text(self):
114         port = self.make_port()
115         port.wdiff_available = lambda: True
116         port._run_wdiff = lambda a, b: 'PASS'
117         self.assertEqual('PASS', port.wdiff_text(None, None))
118
119     def test_diff_text(self):
120         port = self.make_port()
121         # Make sure that we don't run into decoding exceptions when the
122         # filenames are unicode, with regular or malformed input (expected or
123         # actual input is always raw bytes, not unicode).
124         port.diff_text('exp', 'act', 'exp.txt', 'act.txt')
125         port.diff_text('exp', 'act', u'exp.txt', 'act.txt')
126         port.diff_text('exp', 'act', u'a\xac\u1234\u20ac\U00008000', 'act.txt')
127
128         port.diff_text('exp' + chr(255), 'act', 'exp.txt', 'act.txt')
129         port.diff_text('exp' + chr(255), 'act', u'exp.txt', 'act.txt')
130
131         # Though expected and actual files should always be read in with no
132         # encoding (and be stored as str objects), test unicode inputs just to
133         # be safe.
134         port.diff_text(u'exp', 'act', 'exp.txt', 'act.txt')
135         port.diff_text(
136             u'a\xac\u1234\u20ac\U00008000', 'act', 'exp.txt', 'act.txt')
137
138         # And make sure we actually get diff output.
139         diff = port.diff_text('foo', 'bar', 'exp.txt', 'act.txt')
140         self.assertIn('foo', diff)
141         self.assertIn('bar', diff)
142         self.assertIn('exp.txt', diff)
143         self.assertIn('act.txt', diff)
144         self.assertNotIn('nosuchthing', diff)
145
146     def test_setup_test_run(self):
147         port = self.make_port()
148         # This routine is a no-op. We just test it for coverage.
149         port.setup_test_run()
150
151     def test_test_dirs(self):
152         port = self.make_port()
153         port.host.filesystem.write_text_file(port.layout_tests_dir() + '/canvas/test', '')
154         port.host.filesystem.write_text_file(port.layout_tests_dir() + '/css2.1/test', '')
155         dirs = port.test_dirs()
156         self.assertIn('canvas', dirs)
157         self.assertIn('css2.1', dirs)
158
159     def test_skipped_perf_tests(self):
160         port = self.make_port()
161
162         def add_text_file(dirname, filename, content='some content'):
163             dirname = port.host.filesystem.join(port.perf_tests_dir(), dirname)
164             port.host.filesystem.maybe_make_directory(dirname)
165             port.host.filesystem.write_text_file(port.host.filesystem.join(dirname, filename), content)
166
167         add_text_file('inspector', 'test1.html')
168         add_text_file('inspector', 'unsupported_test1.html')
169         add_text_file('inspector', 'test2.html')
170         add_text_file('inspector/resources', 'resource_file.html')
171         add_text_file('unsupported', 'unsupported_test2.html')
172         add_text_file('', 'Skipped', '\n'.join(['Layout', '', 'SunSpider', 'Supported/some-test.html']))
173         self.assertEqual(port.skipped_perf_tests(), ['Layout', 'SunSpider', 'Supported/some-test.html'])
174
175     def test_get_option__set(self):
176         options, args = optparse.OptionParser().parse_args([])
177         options.foo = 'bar'
178         port = self.make_port(options=options)
179         self.assertEqual(port.get_option('foo'), 'bar')
180
181     def test_get_option__unset(self):
182         port = self.make_port()
183         self.assertIsNone(port.get_option('foo'))
184
185     def test_get_option__default(self):
186         port = self.make_port()
187         self.assertEqual(port.get_option('foo', 'bar'), 'bar')
188
189     def test_additional_platform_directory(self):
190         port = self.make_port(port_name='foo')
191         port.default_baseline_search_path = lambda: ['LayoutTests/platform/foo']
192         layout_test_dir = port.layout_tests_dir()
193         test_file = 'fast/test.html'
194
195         # No additional platform directory
196         self.assertEqual(
197             port.expected_baselines(test_file, '.txt'),
198             [(None, 'fast/test-expected.txt')])
199         self.assertEqual(port.baseline_path(), 'LayoutTests/platform/foo')
200
201         # Simple additional platform directory
202         port._options.additional_platform_directory = ['/tmp/local-baselines']
203         port._filesystem.write_text_file('/tmp/local-baselines/fast/test-expected.txt', 'foo')
204         self.assertEqual(
205             port.expected_baselines(test_file, '.txt'),
206             [('/tmp/local-baselines', 'fast/test-expected.txt')])
207         self.assertEqual(port.baseline_path(), '/tmp/local-baselines')
208
209         # Multiple additional platform directories
210         port._options.additional_platform_directory = ['/foo', '/tmp/local-baselines']
211         self.assertEqual(
212             port.expected_baselines(test_file, '.txt'),
213             [('/tmp/local-baselines', 'fast/test-expected.txt')])
214         self.assertEqual(port.baseline_path(), '/foo')
215
216     def test_nonexistant_expectations(self):
217         port = self.make_port(port_name='foo')
218         port.expectations_files = lambda: ['/mock-checkout/third_party/WebKit/LayoutTests/platform/exists/TestExpectations', '/mock-checkout/third_party/WebKit/LayoutTests/platform/nonexistant/TestExpectations']
219         port._filesystem.write_text_file('/mock-checkout/third_party/WebKit/LayoutTests/platform/exists/TestExpectations', '')
220         self.assertEqual('\n'.join(port.expectations_dict().keys()), '/mock-checkout/third_party/WebKit/LayoutTests/platform/exists/TestExpectations')
221
222     def test_additional_expectations(self):
223         port = self.make_port(port_name='foo')
224         port.port_name = 'foo'
225         port._filesystem.write_text_file('/mock-checkout/third_party/WebKit/LayoutTests/platform/foo/TestExpectations', '')
226         port._filesystem.write_text_file(
227             '/tmp/additional-expectations-1.txt', 'content1\n')
228         port._filesystem.write_text_file(
229             '/tmp/additional-expectations-2.txt', 'content2\n')
230
231         self.assertEqual('\n'.join(port.expectations_dict().values()), '')
232
233         port._options.additional_expectations = [
234             '/tmp/additional-expectations-1.txt']
235         self.assertEqual('\n'.join(port.expectations_dict().values()), 'content1\n')
236
237         port._options.additional_expectations = [
238             '/tmp/nonexistent-file', '/tmp/additional-expectations-1.txt']
239         self.assertEqual('\n'.join(port.expectations_dict().values()), 'content1\n')
240
241         port._options.additional_expectations = [
242             '/tmp/additional-expectations-1.txt', '/tmp/additional-expectations-2.txt']
243         self.assertEqual('\n'.join(port.expectations_dict().values()), 'content1\n\ncontent2\n')
244
245     def test_additional_env_var(self):
246         port = self.make_port(options=optparse.Values({'additional_env_var': ['FOO=BAR', 'BAR=FOO']}))
247         self.assertEqual(port.get_option('additional_env_var'), ['FOO=BAR', 'BAR=FOO'])
248         environment = port.setup_environ_for_server()
249         self.assertTrue(('FOO' in environment) & ('BAR' in environment))
250         self.assertEqual(environment['FOO'], 'BAR')
251         self.assertEqual(environment['BAR'], 'FOO')
252
253     def test_find_no_paths_specified(self):
254         port = self.make_port(with_tests=True)
255         layout_tests_dir = port.layout_tests_dir()
256         tests = port.tests([])
257         self.assertNotEqual(len(tests), 0)
258
259     def test_find_one_test(self):
260         port = self.make_port(with_tests=True)
261         tests = port.tests(['failures/expected/image.html'])
262         self.assertEqual(len(tests), 1)
263
264     def test_find_glob(self):
265         port = self.make_port(with_tests=True)
266         tests = port.tests(['failures/expected/im*'])
267         self.assertEqual(len(tests), 2)
268
269     def test_find_with_skipped_directories(self):
270         port = self.make_port(with_tests=True)
271         tests = port.tests(['userscripts'])
272         self.assertNotIn('userscripts/resources/iframe.html', tests)
273
274     def test_find_with_skipped_directories_2(self):
275         port = self.make_port(with_tests=True)
276         tests = port.tests(['userscripts/resources'])
277         self.assertEqual(tests, [])
278
279     def test_is_test_file(self):
280         filesystem = MockFileSystem()
281         self.assertTrue(Port.is_test_file(filesystem, '', 'foo.html'))
282         self.assertTrue(Port.is_test_file(filesystem, '', 'foo.svg'))
283         self.assertTrue(Port.is_test_file(filesystem, '', 'test-ref-test.html'))
284         self.assertFalse(Port.is_test_file(filesystem, '', 'foo.png'))
285         self.assertFalse(Port.is_test_file(filesystem, '', 'foo-expected.html'))
286         self.assertFalse(Port.is_test_file(filesystem, '', 'foo-expected.svg'))
287         self.assertFalse(Port.is_test_file(filesystem, '', 'foo-expected.xht'))
288         self.assertFalse(Port.is_test_file(filesystem, '', 'foo-expected-mismatch.html'))
289         self.assertFalse(Port.is_test_file(filesystem, '', 'foo-expected-mismatch.svg'))
290         self.assertFalse(Port.is_test_file(filesystem, '', 'foo-expected-mismatch.xhtml'))
291         self.assertFalse(Port.is_test_file(filesystem, '', 'foo-ref.html'))
292         self.assertFalse(Port.is_test_file(filesystem, '', 'foo-notref.html'))
293         self.assertFalse(Port.is_test_file(filesystem, '', 'foo-notref.xht'))
294         self.assertFalse(Port.is_test_file(filesystem, '', 'foo-ref.xhtml'))
295         self.assertFalse(Port.is_test_file(filesystem, '', 'ref-foo.html'))
296         self.assertFalse(Port.is_test_file(filesystem, '', 'notref-foo.xhr'))
297
298     def test_parse_reftest_list(self):
299         port = self.make_port(with_tests=True)
300         port.host.filesystem.files['bar/reftest.list'] = "\n".join(["== test.html test-ref.html",
301         "",
302         "# some comment",
303         "!= test-2.html test-notref.html # more comments",
304         "== test-3.html test-ref.html",
305         "== test-3.html test-ref2.html",
306         "!= test-3.html test-notref.html",
307         "fuzzy(80,500) == test-3 test-ref.html"])
308
309         # Note that we don't support the syntax in the last line; the code should ignore it, rather than crashing.
310
311         reftest_list = Port._parse_reftest_list(port.host.filesystem, 'bar')
312         self.assertEqual(reftest_list, {'bar/test.html': [('==', 'bar/test-ref.html')],
313             'bar/test-2.html': [('!=', 'bar/test-notref.html')],
314             'bar/test-3.html': [('==', 'bar/test-ref.html'), ('==', 'bar/test-ref2.html'), ('!=', 'bar/test-notref.html')]})
315
316     def test_reference_files(self):
317         port = self.make_port(with_tests=True)
318         self.assertEqual(port.reference_files('passes/svgreftest.svg'), [('==', port.layout_tests_dir() + '/passes/svgreftest-expected.svg')])
319         self.assertEqual(port.reference_files('passes/xhtreftest.svg'), [('==', port.layout_tests_dir() + '/passes/xhtreftest-expected.html')])
320         self.assertEqual(port.reference_files('passes/phpreftest.php'), [('!=', port.layout_tests_dir() + '/passes/phpreftest-expected-mismatch.svg')])
321
322     def test_operating_system(self):
323         self.assertEqual('mac', self.make_port().operating_system())
324
325     def test_http_server_supports_ipv6(self):
326         port = self.make_port()
327         self.assertTrue(port.http_server_supports_ipv6())
328         port.host.platform.os_name = 'cygwin'
329         self.assertFalse(port.http_server_supports_ipv6())
330         port.host.platform.os_name = 'win'
331         self.assertTrue(port.http_server_supports_ipv6())
332
333     def test_check_httpd_success(self):
334         port = self.make_port(executive=MockExecutive2())
335         port.path_to_apache = lambda: '/usr/sbin/httpd'
336         capture = OutputCapture()
337         capture.capture_output()
338         self.assertTrue(port.check_httpd())
339         _, _, logs = capture.restore_output()
340         self.assertEqual('', logs)
341
342     def test_httpd_returns_error_code(self):
343         port = self.make_port(executive=MockExecutive2(exit_code=1))
344         port.path_to_apache = lambda: '/usr/sbin/httpd'
345         capture = OutputCapture()
346         capture.capture_output()
347         self.assertFalse(port.check_httpd())
348         _, _, logs = capture.restore_output()
349         self.assertEqual('httpd seems broken. Cannot run http tests.\n', logs)
350
351     def test_test_exists(self):
352         port = self.make_port(with_tests=True)
353         self.assertTrue(port.test_exists('passes'))
354         self.assertTrue(port.test_exists('passes/text.html'))
355         self.assertFalse(port.test_exists('passes/does_not_exist.html'))
356
357         self.assertTrue(port.test_exists('virtual'))
358         self.assertFalse(port.test_exists('virtual/does_not_exist.html'))
359         self.assertTrue(port.test_exists('virtual/passes/text.html'))
360
361     def test_test_isfile(self):
362         port = self.make_port(with_tests=True)
363         self.assertFalse(port.test_isfile('passes'))
364         self.assertTrue(port.test_isfile('passes/text.html'))
365         self.assertFalse(port.test_isfile('passes/does_not_exist.html'))
366
367         self.assertFalse(port.test_isfile('virtual'))
368         self.assertTrue(port.test_isfile('virtual/passes/text.html'))
369         self.assertFalse(port.test_isfile('virtual/does_not_exist.html'))
370
371     def test_test_isdir(self):
372         port = self.make_port(with_tests=True)
373         self.assertTrue(port.test_isdir('passes'))
374         self.assertFalse(port.test_isdir('passes/text.html'))
375         self.assertFalse(port.test_isdir('passes/does_not_exist.html'))
376         self.assertFalse(port.test_isdir('passes/does_not_exist/'))
377
378         self.assertTrue(port.test_isdir('virtual'))
379         self.assertFalse(port.test_isdir('virtual/does_not_exist.html'))
380         self.assertFalse(port.test_isdir('virtual/does_not_exist/'))
381         self.assertFalse(port.test_isdir('virtual/passes/text.html'))
382
383     def test_tests(self):
384         port = self.make_port(with_tests=True)
385         tests = port.tests([])
386         self.assertIn('passes/text.html', tests)
387         self.assertIn('virtual/passes/text.html', tests)
388
389         tests = port.tests(['passes'])
390         self.assertIn('passes/text.html', tests)
391         self.assertIn('passes/passes/test-virtual-passes.html', tests)
392         self.assertNotIn('virtual/passes/text.html', tests)
393
394         tests = port.tests(['virtual/passes'])
395         self.assertNotIn('passes/text.html', tests)
396         self.assertIn('virtual/passes/test-virtual-passes.html', tests)
397         self.assertIn('virtual/passes/passes/test-virtual-passes.html', tests)
398         self.assertNotIn('virtual/passes/test-virtual-virtual/passes.html', tests)
399         self.assertNotIn('virtual/passes/virtual/passes/test-virtual-passes.html', tests)
400
401     def test_build_path(self):
402         port = self.make_port(options=optparse.Values({'build_directory': '/my-build-directory/'}))
403         self.assertEqual(port._build_path(), '/my-build-directory/Release')
404
405     def test_dont_require_http_server(self):
406         port = self.make_port()
407         self.assertEqual(port.requires_http_server(), False)
408
409
410 class NaturalCompareTest(unittest.TestCase):
411     def setUp(self):
412         self._port = TestPort(MockSystemHost())
413
414     def assert_cmp(self, x, y, result):
415         self.assertEqual(cmp(self._port._natural_sort_key(x), self._port._natural_sort_key(y)), result)
416
417     def test_natural_compare(self):
418         self.assert_cmp('a', 'a', 0)
419         self.assert_cmp('ab', 'a', 1)
420         self.assert_cmp('a', 'ab', -1)
421         self.assert_cmp('', '', 0)
422         self.assert_cmp('', 'ab', -1)
423         self.assert_cmp('1', '2', -1)
424         self.assert_cmp('2', '1', 1)
425         self.assert_cmp('1', '10', -1)
426         self.assert_cmp('2', '10', -1)
427         self.assert_cmp('foo_1.html', 'foo_2.html', -1)
428         self.assert_cmp('foo_1.1.html', 'foo_2.html', -1)
429         self.assert_cmp('foo_1.html', 'foo_10.html', -1)
430         self.assert_cmp('foo_2.html', 'foo_10.html', -1)
431         self.assert_cmp('foo_23.html', 'foo_10.html', 1)
432         self.assert_cmp('foo_23.html', 'foo_100.html', -1)
433
434
435 class KeyCompareTest(unittest.TestCase):
436     def setUp(self):
437         self._port = TestPort(MockSystemHost())
438
439     def assert_cmp(self, x, y, result):
440         self.assertEqual(cmp(self._port.test_key(x), self._port.test_key(y)), result)
441
442     def test_test_key(self):
443         self.assert_cmp('/a', '/a', 0)
444         self.assert_cmp('/a', '/b', -1)
445         self.assert_cmp('/a2', '/a10', -1)
446         self.assert_cmp('/a2/foo', '/a10/foo', -1)
447         self.assert_cmp('/a/foo11', '/a/foo2', 1)
448         self.assert_cmp('/ab', '/a/a/b', -1)
449         self.assert_cmp('/a/a/b', '/ab', 1)
450         self.assert_cmp('/foo-bar/baz', '/foo/baz', -1)
451
452
453 class VirtualTestSuiteTest(unittest.TestCase):
454     def test_basic(self):
455         suite = VirtualTestSuite('suite', 'base/foo', ['--args'])
456         self.assertEqual(suite.name, 'virtual/suite/base/foo')
457         self.assertEqual(suite.base, 'base/foo')
458         self.assertEqual(suite.args, ['--args'])
459
460     def test_no_slash(self):
461         suite = VirtualTestSuite('suite/bar', 'base/foo', ['--args'])
462         self.assertFalse(hasattr(suite, 'name'))
463         self.assertFalse(hasattr(suite, 'base'))
464         self.assertFalse(hasattr(suite, 'args'))
465
466     def test_legacy(self):
467         suite = VirtualTestSuite('suite/bar', 'base/foo', ['--args'], use_legacy_naming=True)
468         self.assertEqual(suite.name, 'virtual/suite/bar')
469         self.assertEqual(suite.base, 'base/foo')
470         self.assertEqual(suite.args, ['--args'])