blob: 7e181ed2d1393e79a33133d7a3d9f1209f8efb40 [file] [log] [blame]
#!/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 = filename.split(os.path.sep)
if 'platform' in path:
return path[path.index('platform') + 1]
return None
def _extract_test_name(self, filename):
path = filename.split(os.path.sep)
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()