# 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