diff options
Diffstat (limited to 'Tools/Scripts/webkitpy/common/net/testoutput.py')
-rw-r--r-- | Tools/Scripts/webkitpy/common/net/testoutput.py | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/Tools/Scripts/webkitpy/common/net/testoutput.py b/Tools/Scripts/webkitpy/common/net/testoutput.py new file mode 100644 index 0000000..37c1445 --- /dev/null +++ b/Tools/Scripts/webkitpy/common/net/testoutput.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python +# Copyright (C) 2010 Google Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. 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. +# +# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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. + +import os +import re + + +class NaiveImageDiffer(object): + def same_image(self, img1, img2): + return img1 == img2 + + +class TestOutput(object): + """Represents the output that a single layout test generates when it is run + on a particular platform. + Note that this is the raw output that is produced when the layout test is + run, not the results of the subsequent comparison between that output and + the expected output.""" + def __init__(self, platform, output_type, files): + self._output_type = output_type + self._files = files + file = files[0] # Pick some file to do test name calculation. + self._name = self._extract_test_name(file.name()) + self._is_actual = '-actual.' in file.name() + + self._platform = platform or self._extract_platform(file.name()) + + def _extract_platform(self, filename): + """Calculates the platform from the name of the file if it isn't known already""" + path = re.split(os.path.sep, filename) + if 'platform' in path: + return path[path.index('platform') + 1] + return None + + def _extract_test_name(self, filename): + path = re.split(os.path.sep, filename) + if 'LayoutTests' in path: + path = path[1 + path.index('LayoutTests'):] + if 'layout-test-results' in path: + path = path[1 + path.index('layout-test-results'):] + if 'platform' in path: + path = path[2 + path.index('platform'):] + + filename = path[-1] + filename = re.sub('-expected\..*$', '', filename) + filename = re.sub('-actual\..*$', '', filename) + path[-1] = filename + return os.path.sep.join(path) + + def save_to(self, path): + """Have the files in this TestOutput write themselves to the disk at the specified location.""" + for file in self._files: + file.save_to(path) + + def is_actual(self): + """Is this output the actual output of a test? (As opposed to expected output.)""" + return self._is_actual + + def name(self): + """The name of this test (doesn't include extension)""" + return self._name + + def __eq__(self, other): + return (other != None and + self.name() == other.name() and + self.type() == other.type() and + self.platform() == other.platform() and + self.is_actual() == other.is_actual() and + self.same_content(other)) + + def __hash__(self): + return hash(str(self.name()) + str(self.type()) + str(self.platform())) + + def is_new_baseline_for(self, other): + return (self.name() == other.name() and + self.type() == other.type() and + self.platform() == other.platform() and + self.is_actual() and + (not other.is_actual())) + + def __str__(self): + actual_str = '[A] ' if self.is_actual() else '' + return "TestOutput[%s/%s] %s%s" % (self._platform, self._output_type, actual_str, self.name()) + + def type(self): + return self._output_type + + def platform(self): + return self._platform + + def _path_to_platform(self): + """Returns the path that tests for this platform are stored in.""" + if self._platform is None: + return "" + else: + return os.path.join("self._platform", self._platform) + + def _save_expected_result(self, file, path): + path = os.path.join(path, self._path_to_platform()) + extension = os.path.splitext(file.name())[1] + filename = self.name() + '-expected' + extension + file.save_to(path, filename) + + def save_expected_results(self, path_to_layout_tests): + """Save the files of this TestOutput to the appropriate directory + inside the LayoutTests directory. Typically this means that these files + will be saved in "LayoutTests/platform/<platform>/, or simply + LayoutTests if the platform is None.""" + for file in self._files: + self._save_expected_result(file, path_to_layout_tests) + + def delete(self): + """Deletes the files that comprise this TestOutput from disk. This + fails if the files are virtual files (eg: the files may reside inside a + remote zip file).""" + for file in self._files: + file.delete() + + +class TextTestOutput(TestOutput): + """Represents a text output of a single test on a single platform""" + def __init__(self, platform, text_file): + self._text_file = text_file + TestOutput.__init__(self, platform, 'text', [text_file]) + + def same_content(self, other): + return self._text_file.contents() == other._text_file.contents() + + def retarget(self, platform): + return TextTestOutput(platform, self._text_file) + + +class ImageTestOutput(TestOutput): + image_differ = NaiveImageDiffer() + """Represents an image output of a single test on a single platform""" + def __init__(self, platform, image_file, checksum_file): + self._checksum_file = checksum_file + self._image_file = image_file + files = filter(bool, [self._checksum_file, self._image_file]) + TestOutput.__init__(self, platform, 'image', files) + + def has_checksum(self): + return self._checksum_file is not None + + def same_content(self, other): + # FIXME This should not assume that checksums are up to date. + if self.has_checksum() and other.has_checksum(): + return self._checksum_file.contents() == other._checksum_file.contents() + else: + self_contents = self._image_file.contents() + other_contents = other._image_file.contents() + return ImageTestOutput.image_differ.same_image(self_contents, other_contents) + + def retarget(self, platform): + return ImageTestOutput(platform, self._image_file, self._checksum_file) + + def checksum(self): + return self._checksum_file.contents() |