[SCM] WebKit Debian packaging branch, webkit-1.1, updated. upstream/1.1.19-706-ge5415e9

dpranke at chromium.org dpranke at chromium.org
Thu Feb 4 21:33:03 UTC 2010


The following commit has been merged in the webkit-1.1 branch:
commit 3aea660682fc35a504472c86206ecccad2310904
Author: dpranke at chromium.org <dpranke at chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Sat Jan 30 01:17:08 2010 +0000

    2010-01-29  Dirk Pranke  <dpranke at chromium.org>
    
            Reviewed by Eric Siedel.
    
            Add in the second block of python code for the Chromium port
            of run-webkit-tests. These files execute different diffs to classify
            the various types of failures from a test.
    
            * Scripts/webkitpy/layout_tests/test_types: Added.
            * Scripts/webkitpy/layout_tests/test_types/__init__.py: Added.
            * Scripts/webkitpy/layout_tests/test_types/fuzzy_image_diff.py: Added.
            * Scripts/webkitpy/layout_tests/test_types/image_diff.py: Added.
            * Scripts/webkitpy/layout_tests/test_types/test_type_base.py: Added.
            * Scripts/webkitpy/layout_tests/test_types/text_diff.py: Added.
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@54093 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebKitTools/ChangeLog b/WebKitTools/ChangeLog
index 57360d9..fbcd93f 100644
--- a/WebKitTools/ChangeLog
+++ b/WebKitTools/ChangeLog
@@ -2,6 +2,21 @@
 
         Reviewed by Eric Siedel.
 
+        Add in the second block of python code for the Chromium port
+        of run-webkit-tests. These files execute different diffs to classify
+        the various types of failures from a test.
+
+        * Scripts/webkitpy/layout_tests/test_types: Added.
+        * Scripts/webkitpy/layout_tests/test_types/__init__.py: Added.
+        * Scripts/webkitpy/layout_tests/test_types/fuzzy_image_diff.py: Added.
+        * Scripts/webkitpy/layout_tests/test_types/image_diff.py: Added.
+        * Scripts/webkitpy/layout_tests/test_types/test_type_base.py: Added.
+        * Scripts/webkitpy/layout_tests/test_types/text_diff.py: Added.
+
+2010-01-29  Dirk Pranke  <dpranke at chromium.org>
+
+        Reviewed by Eric Siedel.
+
         Check in the first part of the Chromium Python port of the 
         run-webkit-tests test driver. The files under 
         layout_tests/layout_layout constitute most of the implementation;
diff --git a/BugsSite/data/mail b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/__init__.py
similarity index 100%
copy from BugsSite/data/mail
copy to WebKitTools/Scripts/webkitpy/layout_tests/test_types/__init__.py
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/test_types/fuzzy_image_diff.py b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/fuzzy_image_diff.py
new file mode 100644
index 0000000..134b507
--- /dev/null
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/fuzzy_image_diff.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 The Chromium Authors. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the Chromium name nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Compares the image output of a test to the expected image output using
+fuzzy matching.
+"""
+
+import errno
+import logging
+import os
+import shutil
+import subprocess
+
+from layout_package import path_utils
+from layout_package import test_failures
+from test_types import test_type_base
+
+
+class FuzzyImageDiff(test_type_base.TestTypeBase):
+
+    def compare_output(self, filename, proc, output, test_args, target):
+        """Implementation of CompareOutput that checks the output image and
+        checksum against the expected files from the LayoutTest directory.
+        """
+        failures = []
+
+        # If we didn't produce a hash file, this test must be text-only.
+        if test_args.hash is None:
+            return failures
+
+        expected_png_file = path_utils.expected_filename(filename, '.png')
+
+        if test_args.show_sources:
+            logging.debug('Using %s' % expected_png_file)
+
+        # Also report a missing expected PNG file.
+        if not os.path.isfile(expected_png_file):
+            failures.append(test_failures.FailureMissingImage(self))
+
+        # Run the fuzzymatcher
+        r = subprocess.call([path_utils.fuzzy_match_path(),
+                            test_args.png_path, expected_png_file])
+        if r != 0:
+            failures.append(test_failures.FailureFuzzyFailure(self))
+
+        return failures
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/test_types/image_diff.py b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/image_diff.py
new file mode 100644
index 0000000..b0bf189
--- /dev/null
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/image_diff.py
@@ -0,0 +1,224 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 The Chromium Authors. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the Chromium name nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Compares the image output of a test to the expected image output.
+
+Compares hashes for the generated and expected images. If the output doesn't
+match, returns FailureImageHashMismatch and outputs both hashes into the layout
+test results directory.
+"""
+
+import errno
+import logging
+import os
+import shutil
+import subprocess
+
+from layout_package import path_utils
+from layout_package import test_failures
+from test_types import test_type_base
+
+# Cache whether we have the image_diff executable available.
+_compare_available = True
+_compare_msg_printed = False
+
+
+class ImageDiff(test_type_base.TestTypeBase):
+
+    def _copy_output_png(self, test_filename, source_image, extension):
+        """Copies result files into the output directory with appropriate
+        names.
+
+        Args:
+          test_filename: the test filename
+          source_file: path to the image file (either actual or expected)
+          extension: extension to indicate -actual.png or -expected.png
+        """
+        self._make_output_directory(test_filename)
+        dest_image = self.output_filename(test_filename, extension)
+
+        try:
+            shutil.copyfile(source_image, dest_image)
+        except IOError, e:
+            # A missing expected PNG has already been recorded as an error.
+            if errno.ENOENT != e.errno:
+                raise
+
+    def _save_baseline_files(self, filename, png_path, checksum):
+        """Saves new baselines for the PNG and checksum.
+
+        Args:
+          filename: test filename
+          png_path: path to the actual PNG result file
+          checksum: value of the actual checksum result
+        """
+        png_file = open(png_path, "rb")
+        png_data = png_file.read()
+        png_file.close()
+        self._save_baseline_data(filename, png_data, ".png")
+        self._save_baseline_data(filename, checksum, ".checksum")
+
+    def _create_image_diff(self, filename, target):
+        """Creates the visual diff of the expected/actual PNGs.
+
+        Args:
+          filename: the name of the test
+          target: Debug or Release
+        """
+        diff_filename = self.output_filename(filename,
+          self.FILENAME_SUFFIX_COMPARE)
+        actual_filename = self.output_filename(filename,
+          self.FILENAME_SUFFIX_ACTUAL + '.png')
+        expected_filename = self.output_filename(filename,
+          self.FILENAME_SUFFIX_EXPECTED + '.png')
+
+        global _compare_available
+        cmd = ''
+
+        try:
+            executable = path_utils.image_diff_path(target)
+            cmd = [executable, '--diff', actual_filename, expected_filename,
+                   diff_filename]
+        except Exception, e:
+            _compare_available = False
+
+        result = 1
+        if _compare_available:
+            try:
+                result = subprocess.call(cmd)
+            except OSError, e:
+                if e.errno == errno.ENOENT or e.errno == errno.EACCES:
+                    _compare_available = False
+                else:
+                    raise e
+            except ValueError:
+                # work around a race condition in Python 2.4's implementation
+                # of subprocess.Popen
+                pass
+
+        global _compare_msg_printed
+
+        if not _compare_available and not _compare_msg_printed:
+            _compare_msg_printed = True
+            print('image_diff not found. Make sure you have a ' + target +
+                  ' build of the image_diff executable.')
+
+        return result
+
+    def compare_output(self, filename, proc, output, test_args, target):
+        """Implementation of CompareOutput that checks the output image and
+        checksum against the expected files from the LayoutTest directory.
+        """
+        failures = []
+
+        # If we didn't produce a hash file, this test must be text-only.
+        if test_args.hash is None:
+            return failures
+
+        # If we're generating a new baseline, we pass.
+        if test_args.new_baseline:
+            self._save_baseline_files(filename, test_args.png_path,
+                                    test_args.hash)
+            return failures
+
+        # Compare hashes.
+        expected_hash_file = path_utils.expected_filename(filename,
+                                                          '.checksum')
+        expected_png_file = path_utils.expected_filename(filename, '.png')
+
+        if test_args.show_sources:
+            logging.debug('Using %s' % expected_hash_file)
+            logging.debug('Using %s' % expected_png_file)
+
+        try:
+            expected_hash = open(expected_hash_file, "r").read()
+        except IOError, e:
+            if errno.ENOENT != e.errno:
+                raise
+            expected_hash = ''
+
+
+        if not os.path.isfile(expected_png_file):
+            # Report a missing expected PNG file.
+            self.write_output_files(filename, '', '.checksum', test_args.hash,
+                                    expected_hash, diff=False, wdiff=False)
+            self._copy_output_png(filename, test_args.png_path, '-actual.png')
+            failures.append(test_failures.FailureMissingImage(self))
+            return failures
+        elif test_args.hash == expected_hash:
+            # Hash matched (no diff needed, okay to return).
+            return failures
+
+
+        self.write_output_files(filename, '', '.checksum', test_args.hash,
+                                expected_hash, diff=False, wdiff=False)
+        self._copy_output_png(filename, test_args.png_path, '-actual.png')
+        self._copy_output_png(filename, expected_png_file, '-expected.png')
+
+        # Even though we only use result in one codepath below but we
+        # still need to call CreateImageDiff for other codepaths.
+        result = self._create_image_diff(filename, target)
+        if expected_hash == '':
+            failures.append(test_failures.FailureMissingImageHash(self))
+        elif test_args.hash != expected_hash:
+            # Hashes don't match, so see if the images match. If they do, then
+            # the hash is wrong.
+            if result == 0:
+                failures.append(test_failures.FailureImageHashIncorrect(self))
+            else:
+                failures.append(test_failures.FailureImageHashMismatch(self))
+
+        return failures
+
+    def diff_files(self, file1, file2):
+        """Diff two image files.
+
+        Args:
+          file1, file2: full paths of the files to compare.
+
+        Returns:
+          True if two files are different.
+          False otherwise.
+        """
+
+        try:
+            executable = path_utils.image_diff_path('Debug')
+        except Exception, e:
+            logging.warn('Failed to find image diff executable.')
+            return True
+
+        cmd = [executable, file1, file2]
+        result = 1
+        try:
+            result = subprocess.call(cmd)
+        except OSError, e:
+            logging.warn('Failed to compare image diff: %s', e)
+            return True
+
+        return result == 1
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py
new file mode 100644
index 0000000..334ae70
--- /dev/null
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py
@@ -0,0 +1,266 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 The Chromium Authors. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the Chromium name nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Defines the interface TestTypeBase which other test types inherit from.
+
+Also defines the TestArguments "struct" to pass them additional arguments.
+"""
+
+import cgi
+import difflib
+import errno
+import logging
+import os.path
+import subprocess
+
+from layout_package import path_utils
+
+
+class TestArguments(object):
+    """Struct-like wrapper for additional arguments needed by
+    specific tests."""
+    # Whether to save new baseline results.
+    new_baseline = False
+
+    # Path to the actual PNG file generated by pixel tests
+    png_path = None
+
+    # Value of checksum generated by pixel tests.
+    hash = None
+
+    # Whether to use wdiff to generate by-word diffs.
+    wdiff = False
+
+    # Whether to report the locations of the expected result files used.
+    show_sources = False
+
+# Python bug workaround.  See the wdiff code in WriteOutputFiles for an
+# explanation.
+_wdiff_available = True
+
+
+class TestTypeBase(object):
+
+    # Filename pieces when writing failures to the test results directory.
+    FILENAME_SUFFIX_ACTUAL = "-actual"
+    FILENAME_SUFFIX_EXPECTED = "-expected"
+    FILENAME_SUFFIX_DIFF = "-diff"
+    FILENAME_SUFFIX_WDIFF = "-wdiff.html"
+    FILENAME_SUFFIX_COMPARE = "-diff.png"
+
+    def __init__(self, platform, root_output_dir):
+        """Initialize a TestTypeBase object.
+
+        Args:
+          platform: the platform (e.g., 'chromium-mac-leopard')
+            identifying the platform-specific results to be used.
+          root_output_dir: The unix style path to the output dir.
+        """
+        self._root_output_dir = root_output_dir
+        self._platform = platform
+
+    def _make_output_directory(self, filename):
+        """Creates the output directory (if needed) for a given test
+        filename."""
+        output_filename = os.path.join(self._root_output_dir,
+            path_utils.relative_test_filename(filename))
+        path_utils.maybe_make_directory(os.path.split(output_filename)[0])
+
+    def _save_baseline_data(self, filename, data, modifier):
+        """Saves a new baseline file into the platform directory.
+
+        The file will be named simply "<test>-expected<modifier>", suitable for
+        use as the expected results in a later run.
+
+        Args:
+          filename: path to the test file
+          data: result to be saved as the new baseline
+          modifier: type of the result file, e.g. ".txt" or ".png"
+        """
+        relative_dir = os.path.dirname(
+            path_utils.relative_test_filename(filename))
+        output_dir = os.path.join(
+            path_utils.chromium_baseline_path(self._platform), relative_dir)
+        output_file = os.path.basename(os.path.splitext(filename)[0] +
+            self.FILENAME_SUFFIX_EXPECTED + modifier)
+
+        path_utils.maybe_make_directory(output_dir)
+        output_path = os.path.join(output_dir, output_file)
+        logging.debug('writing new baseline to "%s"' % (output_path))
+        open(output_path, "wb").write(data)
+
+    def output_filename(self, filename, modifier):
+        """Returns a filename inside the output dir that contains modifier.
+
+        For example, if filename is c:/.../fast/dom/foo.html and modifier is
+        "-expected.txt", the return value is
+        c:/cygwin/tmp/layout-test-results/fast/dom/foo-expected.txt
+
+        Args:
+          filename: absolute filename to test file
+          modifier: a string to replace the extension of filename with
+
+        Return:
+          The absolute windows path to the output filename
+        """
+        output_filename = os.path.join(self._root_output_dir,
+            path_utils.relative_test_filename(filename))
+        return os.path.splitext(output_filename)[0] + modifier
+
+    def compare_output(self, filename, proc, output, test_args, target):
+        """Method that compares the output from the test with the
+        expected value.
+
+        This is an abstract method to be implemented by all sub classes.
+
+        Args:
+          filename: absolute filename to test file
+          proc: a reference to the test_shell process
+          output: a string containing the output of the test
+          test_args: a TestArguments object holding optional additional
+              arguments
+          target: Debug or Release
+
+        Return:
+          a list of TestFailure objects, empty if the test passes
+        """
+        raise NotImplemented
+
+    def write_output_files(self, filename, test_type, file_type, output,
+                           expected, diff=True, wdiff=False):
+        """Writes the test output, the expected output and optionally the diff
+        between the two to files in the results directory.
+
+        The full output filename of the actual, for example, will be
+          <filename><test_type>-actual<file_type>
+        For instance,
+          my_test-simp-actual.txt
+
+        Args:
+          filename: The test filename
+          test_type: A string describing the test type, e.g. "simp"
+          file_type: A string describing the test output file type, e.g. ".txt"
+          output: A string containing the test output
+          expected: A string containing the expected test output
+          diff: if True, write a file containing the diffs too. This should be
+              False for results that are not text
+          wdiff: if True, write an HTML file containing word-by-word diffs
+        """
+        self._make_output_directory(filename)
+        actual_filename = self.output_filename(filename,
+            test_type + self.FILENAME_SUFFIX_ACTUAL + file_type)
+        expected_filename = self.output_filename(filename,
+            test_type + self.FILENAME_SUFFIX_EXPECTED + file_type)
+        if output:
+            open(actual_filename, "wb").write(output)
+        if expected:
+            open(expected_filename, "wb").write(expected)
+
+        if not output or not expected:
+            return
+
+        if diff:
+            diff = difflib.unified_diff(expected.splitlines(True),
+                                        output.splitlines(True),
+                                        expected_filename,
+                                        actual_filename)
+
+            diff_filename = self.output_filename(filename,
+                test_type + self.FILENAME_SUFFIX_DIFF + file_type)
+            open(diff_filename, "wb").write(''.join(diff))
+
+        if wdiff:
+            # Shell out to wdiff to get colored inline diffs.
+            executable = path_utils.wdiff_path()
+            cmd = [executable,
+                   '--start-delete=##WDIFF_DEL##',
+                   '--end-delete=##WDIFF_END##',
+                   '--start-insert=##WDIFF_ADD##',
+                   '--end-insert=##WDIFF_END##',
+                   expected_filename,
+                   actual_filename]
+            filename = self.output_filename(filename,
+                            test_type + self.FILENAME_SUFFIX_WDIFF)
+
+            global _wdiff_available
+
+            try:
+                # Python's Popen has a bug that causes any pipes opened to a
+                # process that can't be executed to be leaked.  Since this
+                # code is specifically designed to tolerate exec failures
+                # to gracefully handle cases where wdiff is not installed,
+                # the bug results in a massive file descriptor leak. As a
+                # workaround, if an exec failure is ever experienced for
+                # wdiff, assume it's not available.  This will leak one
+                # file descriptor but that's better than leaking each time
+                # wdiff would be run.
+                #
+                # http://mail.python.org/pipermail/python-list/
+                #    2008-August/505753.html
+                # http://bugs.python.org/issue3210
+                #
+                # It also has a threading bug, so we don't output wdiff if
+                # the Popen raises a ValueError.
+                # http://bugs.python.org/issue1236
+                if _wdiff_available:
+                    wdiff = subprocess.Popen(
+                        cmd, stdout=subprocess.PIPE).communicate()[0]
+                    wdiff_failed = False
+
+            except OSError, e:
+                if (e.errno == errno.ENOENT or e.errno == errno.EACCES or
+                    e.errno == errno.ECHILD):
+                    _wdiff_available = False
+                else:
+                    raise e
+            except ValueError, e:
+                wdiff_failed = True
+
+            out = open(filename, 'wb')
+
+            if not _wdiff_available:
+                out.write(
+                    "wdiff not installed.<br/> "
+                    "If you're running OS X, you can install via macports."
+                    "<br/>"
+                    "If running Ubuntu linux, you can run "
+                    "'sudo apt-get install wdiff'.")
+            elif wdiff_failed:
+                out.write('wdiff failed due to running with multiple '
+                          'test_shells in parallel.')
+            else:
+                wdiff = cgi.escape(wdiff)
+                wdiff = wdiff.replace('##WDIFF_DEL##', '<span class=del>')
+                wdiff = wdiff.replace('##WDIFF_ADD##', '<span class=add>')
+                wdiff = wdiff.replace('##WDIFF_END##', '</span>')
+                out.write('<head><style>.del { background: #faa; } ')
+                out.write('.add { background: #afa; }</style></head>')
+                out.write('<pre>' + wdiff + '</pre>')
+
+            out.close()
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/test_types/text_diff.py b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/text_diff.py
new file mode 100644
index 0000000..8cff9e6
--- /dev/null
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/text_diff.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 The Chromium Authors. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the Chromium name nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Compares the text output of a test to the expected text output.
+
+If the output doesn't match, returns FailureTextMismatch and outputs the diff
+files into the layout test results directory.
+"""
+
+import errno
+import logging
+import os.path
+
+from layout_package import path_utils
+from layout_package import test_failures
+from test_types import test_type_base
+
+
+def is_render_tree_dump(data):
+    """Returns true if data appears to be a render tree dump as opposed to a
+    plain text dump."""
+    return data.find("RenderView at (0,0)") != -1
+
+
+class TestTextDiff(test_type_base.TestTypeBase):
+
+    def get_normalized_output_text(self, output):
+        # Some tests produce "\r\n" explicitly.  Our system (Python/Cygwin)
+        # helpfully changes the "\n" to "\r\n", resulting in "\r\r\n".
+        norm = output.replace("\r\r\n", "\r\n").strip("\r\n").replace(
+             "\r\n", "\n")
+        return norm + "\n"
+
+    def get_normalized_expected_text(self, filename, show_sources):
+        """Given the filename of the test, read the expected output from a file
+        and normalize the text.  Returns a string with the expected text, or ''
+        if the expected output file was not found."""
+        # Read the platform-specific expected text.
+        expected_filename = path_utils.expected_filename(filename, '.txt')
+        if show_sources:
+            logging.debug('Using %s' % expected_filename)
+
+        return self.get_normalized_text(expected_filename)
+
+    def get_normalized_text(self, filename):
+        try:
+            text = open(filename).read()
+        except IOError, e:
+            if errno.ENOENT != e.errno:
+                raise
+            return ''
+
+        # Normalize line endings
+        return text.strip("\r\n").replace("\r\n", "\n") + "\n"
+
+    def compare_output(self, filename, proc, output, test_args, target):
+        """Implementation of CompareOutput that checks the output text against
+        the expected text from the LayoutTest directory."""
+        failures = []
+
+        # If we're generating a new baseline, we pass.
+        if test_args.new_baseline:
+            self._save_baseline_data(filename, output, ".txt")
+            return failures
+
+        # Normalize text to diff
+        output = self.get_normalized_output_text(output)
+        expected = self.get_normalized_expected_text(filename,
+                                                     test_args.show_sources)
+
+        # Write output files for new tests, too.
+        if output != expected:
+            # Text doesn't match, write output files.
+            self.write_output_files(filename, "", ".txt", output, expected,
+                                    diff=True, wdiff=True)
+
+            if expected == '':
+                failures.append(test_failures.FailureMissingResult(self))
+            else:
+                failures.append(test_failures.FailureTextMismatch(self, True))
+
+        return failures
+
+    def diff_files(self, file1, file2):
+        """Diff two text files.
+
+        Args:
+          file1, file2: full paths of the files to compare.
+
+        Returns:
+          True if two files are different.
+          False otherwise.
+        """
+
+        return (self.get_normalized_text(file1) !=
+                self.get_normalized_text(file2))

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list