普通文本  |  209行  |  7.14 KB

# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Touch firmware test report in html format."""

import os
import urllib

import common_util
import firmware_log
import test_conf as conf

from firmware_utils import get_fw_and_date
from string import Template
from validators import get_base_name_and_segment


class TemplateHtml:
    """An html Template."""

    def __init__(self, image_width, image_height, score_colors):
        self.score_colors = score_colors

        # Define the template of the doc
        self.doc = Template('$head $test_version $logs $tail')
        self.table = Template('<table border="3" width="100%"> $gestures '
                              '</table>')
        self.gestures = []

        # Define a template to show a gesture information including
        # the gesture name, variation, prompt, image, and test results.
        self.gesture_template = Template('''
            <tr>
                <td><table>
                    <tr>
                        <h3> $gesture_name.$variation </h3>
                        <h5> $prompt </h5>
                    </tr>
                    <tr>
                        <img src="data:image/png;base64,\n$image"
                            alt="$filename" width="%d" height="%d" />
                    </tr>
                </table></td>
                <td><table>
                    $vlogs
                </table></td>
            </tr>
        ''' % (image_width, image_height))

        self.criteria_string = '  criteria: %s'
        self.validator_template =  Template('''
            <tr>
<pre><span style="color:$color"><b>$name</b></span>
$details
$criteria
</pre>
            </tr>
        ''')

        self.detail_template =  Template('<tr><h5> $detail </h5></tr>')
        self._fill_doc()

    def _html_head(self):
        """Fill the head of an html document."""
        head = '\n'.join(['<!DOCTYPE html>', '<html>', '<body>'])
        return head

    def _html_tail(self):
        """Fill the tail of an html document."""
        tail = '\n'.join(['</body>', '</html>'])
        return tail

    def _fill_doc(self):
        """Fill in fields into the doc."""
        self.doc = Template(self.doc.safe_substitute(head=self._html_head(),
                                                     tail=self._html_tail()))

    def get_score_color(self, score):
        """Present the score in different colors."""
        for s, c in self.score_colors:
            if score >= s:
                return c

    def _insert_details(self, details):
        details_content = []
        for detail in details:
            details_content.append(' ' * 2 + detail.strip())
        return '<br>'.join(details_content)

    def _insert_vlog(self, vlog):
        """Insert a single vlog."""
        base_name, _ = get_base_name_and_segment(vlog.name)
        criteria_string = self.criteria_string % vlog.criteria
        vlog_content = self.validator_template.safe_substitute(
                name=vlog.name,
                details=self._insert_details(vlog.details),
                criteria=criteria_string,
                color='blue',
                score=vlog.score)
        return vlog_content

    def _insert_vlogs(self, vlogs):
        """Insert multiple vlogs."""
        vlogs_content = []
        for vlog in vlogs:
            vlogs_content.append(self._insert_vlog(vlog))
        return '<hr>'.join(vlogs_content)

    def insert_gesture(self, glog, image, image_filename):
        """Insert glog, image, and vlogs."""
        vlogs_content = self._insert_vlogs(glog.vlogs)
        gesture = self.gesture_template.safe_substitute(
                gesture_name=glog.name,
                variation=glog.variation,
                prompt=glog.prompt,
                image=image,
                filename=image_filename,
                vlogs=vlogs_content)
        self.gestures.append(gesture)

    def get_doc(self, test_version):
        gestures = ''.join(self.gestures)
        new_table = self.table.safe_substitute(gestures=gestures)
        new_doc = self.doc.safe_substitute(test_version=test_version,
                                           logs=new_table)
        return new_doc


class ReportHtml:
    """Firmware Report in html format."""

    def __init__(self, filename, screen_size, touch_device_window_size,
                 score_colors, test_version):
        self.html_filename = filename
        self.screen_size = screen_size
        self.image_width = self.screen_size[0] * 0.5
        touch_width, touch_height = touch_device_window_size
        self.image_height = self.image_width / touch_width * touch_height
        self.doc = TemplateHtml(self.image_width, self.image_height,
                                score_colors)
        self._reset_content()
        self.test_version = test_version
        fw_and_date = get_fw_and_date(filename)
        self.rlog = firmware_log.RoundLog(test_version, *fw_and_date)

    def __del__(self):
        self.stop()

    def stop(self):
        """Close the file."""
        with open(self.html_filename, 'w') as report_file:
            report_file.write(self.doc.get_doc(self.test_version))
        # Make a copy to /tmp so that it could be viewed in Chrome.
        tmp_copy = os.path.join(conf.docroot,
                                os.path.basename(self.html_filename))
        copy_cmd = 'cp %s %s' % (self.html_filename, tmp_copy)
        common_util.simple_system(copy_cmd)

        # Dump the logs to a byte stream file
        log_file_root = os.path.splitext(self.html_filename)[0]
        log_filename = os.extsep.join([log_file_root, 'log'])
        self.rlog.dump(log_filename)

    def _reset_content(self):
        self.glog = firmware_log.GestureLog()
        self.encoded_image=''
        self.image_filename=''

    def _get_content(self):
        return [self.glog, self.encoded_image, self.image_filename]

    def _encode_base64(self, filename):
        """Encode a file in base 64 format."""
        if (filename is None) or (not os.path.isfile(filename)):
            return None
        encoded = urllib.quote(open(filename, "rb").read().encode("base64"))
        return encoded

    def flush(self):
        """Flush the current gesture including gesture log, image and
        validator logs.
        """
        content = self._get_content()
        # It is ok to flush the gesture log even when there are no mtplot images
        if self.glog:
            # Write the content to the html file.
            self.doc.insert_gesture(*content)
            # Write the logs to the round log.
            self.rlog.insert_glog(self.glog)
            self._reset_content()

    def insert_image(self, filename):
        """Insert an image into the document."""
        self.encoded_image = self._encode_base64(filename)
        self.image_filename = filename

    def insert_result(self, text):
        """Insert the text into the document."""
        self.result += text

    def insert_gesture_log(self, glog):
        """Update the gesture log."""
        self.glog = glog

    def insert_validator_logs(self, vlogs):
        """Update the validator logs."""
        self.glog.vlogs = vlogs