12fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#!/usr/bin/env python
22fc2651226baac27029e38c9d6ef883fa32084dbSteve Block# Copyright (C) 2010 Google Inc. All rights reserved.
32fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#
42fc2651226baac27029e38c9d6ef883fa32084dbSteve Block# Redistribution and use in source and binary forms, with or without
52fc2651226baac27029e38c9d6ef883fa32084dbSteve Block# modification, are permitted provided that the following conditions
62fc2651226baac27029e38c9d6ef883fa32084dbSteve Block# are met:
72fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#
82fc2651226baac27029e38c9d6ef883fa32084dbSteve Block# 1.  Redistributions of source code must retain the above copyright
92fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#     notice, this list of conditions and the following disclaimer.
102fc2651226baac27029e38c9d6ef883fa32084dbSteve Block# 2.  Redistributions in binary form must reproduce the above copyright
112fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#     notice, this list of conditions and the following disclaimer in the
122fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#     documentation and/or other materials provided with the distribution.
132fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#
142fc2651226baac27029e38c9d6ef883fa32084dbSteve Block# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
152fc2651226baac27029e38c9d6ef883fa32084dbSteve Block# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
162fc2651226baac27029e38c9d6ef883fa32084dbSteve Block# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
172fc2651226baac27029e38c9d6ef883fa32084dbSteve Block# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
192fc2651226baac27029e38c9d6ef883fa32084dbSteve Block# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
202fc2651226baac27029e38c9d6ef883fa32084dbSteve Block# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
212fc2651226baac27029e38c9d6ef883fa32084dbSteve Block# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
222fc2651226baac27029e38c9d6ef883fa32084dbSteve Block# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
232fc2651226baac27029e38c9d6ef883fa32084dbSteve Block# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
242fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
252fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockfrom webkitpy.common.system.directoryfileset import DirectoryFileSet
262fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockfrom webkitpy.common.system.zipfileset import ZipFileSet
272fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockimport re
282fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockimport testoutput
292fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockimport urllib
302fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
312fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
322fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockclass TestOutputSet(object):
332fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def __init__(self, name, platform, zip_file, **kwargs):
342fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        self._name = name
352fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        self._platform = platform
362fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        self._zip_file = zip_file
372fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        self._include_expected = kwargs.get('include_expected', True)
382fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
392fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    @classmethod
402fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def from_zip_url(cls, platform, zip_path):
412fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return TestOutputSet('local zip %s builder' % platform, platform, ZipFileSet(zip_path))
422fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
432fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    @classmethod
442fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def from_zip(cls, platform, zip):
452fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return TestOutputSet('local zip %s builder' % platform, platform, zip)
462fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
472fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    @classmethod
482fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def from_zip_map(cls, zip_map):
492fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        output_sets = []
502fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        for k, v in zip_map.items():
512fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            output_sets.append(TestOutputSet.from_zip(k, v))
522fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return AggregateTestOutputSet(output_sets)
532fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
542fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    @classmethod
552fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def from_path(self, path, platform=None):
562fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return TestOutputSet('local %s builder' % platform, platform, DirectoryFileSet(path))
572fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
582fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def name(self):
592fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return self._name
602fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
612fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def set_platform(self, platform):
622fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        self._platform = platform
632fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
642fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def files(self):
652fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return [self._zip_file.open(filename) for filename in self._zip_file.namelist()]
662fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
672fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def _extract_output_files(self, name, exact_match):
682fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        name_matcher = re.compile(name)
692fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        actual_matcher = re.compile(r'-actual\.')
702fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        expected_matcher = re.compile(r'-expected\.')
712fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
722fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        checksum_files = []
732fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        text_files = []
742fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        image_files = []
752fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        for output_file in self.files():
762fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            name_match = name_matcher.search(output_file.name())
772fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            actual_match = actual_matcher.search(output_file.name())
782fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            expected_match = expected_matcher.search(output_file.name())
792fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            if not (name_match and (actual_match or (self._include_expected and expected_match))):
802fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                continue
812fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            if output_file.name().endswith('.checksum'):
822fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                checksum_files.append(output_file)
832fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            elif output_file.name().endswith('.txt'):
842fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                text_files.append(output_file)
852fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            elif output_file.name().endswith('.png'):
862fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                image_files.append(output_file)
872fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
882fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return (checksum_files, text_files, image_files)
892fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
902fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def _extract_file_with_name(self, name, files):
912fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        for file in files:
922fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            if file.name() == name:
932fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                return file
942fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return None
952fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
962fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def _make_output_from_image(self, image_file, checksum_files):
972fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        checksum_file_name = re.sub('\.png', '.checksum', image_file.name())
982fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        checksum_file = self._extract_file_with_name(checksum_file_name, checksum_files)
992fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return testoutput.ImageTestOutput(self._platform, image_file, checksum_file)
1002fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1012fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def outputs_for(self, name, **kwargs):
1022fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        target_type = kwargs.get('target_type', None)
1032fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        exact_match = kwargs.get('exact_match', False)
1042fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        if re.search(r'\.x?html', name):
1052fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            name = name[:name.rindex('.')]
1062fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1072fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        (checksum_files, text_files, image_files) = self._extract_output_files(name, exact_match)
1082fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1092fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        outputs = [self._make_output_from_image(image_file, checksum_files) for image_file in image_files]
1102fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1112fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        outputs += [testoutput.TextTestOutput(self._platform, text_file) for text_file in text_files]
1122fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1132fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        if exact_match:
1142fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            outputs = filter(lambda output: output.name() == name, outputs)
1152fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1162fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        outputs = filter(lambda r: target_type in [None, r.type()], outputs)
1172fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return outputs
1192fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1202fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1212fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockclass AggregateTestOutputSet(object):
1222fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    """Set of test outputs from a list of builders"""
1232fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def __init__(self, builders):
1242fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        self._builders = builders
1252fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1262fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def outputs_for(self, name, **kwargs):
1272fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return sum([builder.outputs_for(name, **kwargs) for builder in self._builders], [])
1282fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1292fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def builders(self):
1302fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return self._builders
131