2 new revisions:
Revision: db6202d22f3b
Author: Jussi Malinen <jussi.ao.mali...@gmail.com>
Date: Wed Jun 15 04:28:20 2011
Log: new settings api for javascript
http://code.google.com/p/robotframework/source/detail?r=db6202d22f3b
Revision: 80afd415b7f9
Author: Jussi Malinen <jussi.ao.mali...@gmail.com>
Date: Wed Jun 15 04:28:42 2011
Log: merge
http://code.google.com/p/robotframework/source/detail?r=80afd415b7f9
==============================================================================
Revision: db6202d22f3b
Author: Jussi Malinen <jussi.ao.mali...@gmail.com>
Date: Wed Jun 15 04:28:20 2011
Log: new settings api for javascript
http://code.google.com/p/robotframework/source/detail?r=db6202d22f3b
Modified:
/src/robot/webcontent/report.html
/src/robot/webcontent/testdata/data.js
=======================================
--- /src/robot/webcontent/report.html Wed Jun 15 01:42:45 2011
+++ /src/robot/webcontent/report.html Wed Jun 15 04:28:20 2011
@@ -261,12 +261,12 @@
}
function setBackground(topsuite) {
- var bodyclass = "critical_pass";
if (topsuite.criticalFailed)
- bodyclass = "critical_fail";
+ $("body").css("background-color",window.settings.background.fail);
else if (topsuite.totalFailed)
- bodyclass = "non_critical_fail";
- $("body").addClass(bodyclass);
+
$("body").css("background-color",window.settings.background.nonCriticalFail);
+ else
+ $("body").css("background-color",window.settings.background.pass);
}
function iterateDetails(){
@@ -274,7 +274,7 @@
return;
}
var elements = pop_upto(window.tasks, 50);
- $.tmpl(window.templates.testDetailsRow, elements, {logPath:
window.settings.logPath}).appendTo('#tests_detail_table');
+ $.tmpl(window.templates.testDetailsRow, elements, {logURL:
window.settings.logURL}).appendTo('#tests_detail_table');
if(window.tasks.length > 0)
setTimeout("iterateDetails()", 0);
}
@@ -532,8 +532,8 @@
<script type="text/html" id="report_test_details_row">
<tr class="test_row">
- {{if $item.logPath}}
- <td class="col_name"><a href="${$item.logPath}#test_${fullname}"
id="test_${fullname}" title="${fullname}"><span
class="parent_name">${parentName}</span>${name}</a></td>
+ {{if $item.logURL}}
+ <td class="col_name"><a href="${$item.logURL}#test_${fullname}"
id="test_${fullname}" title="${fullname}"><span
class="parent_name">${parentName}</span>${name}</a></td>
{{else}}
<td class="col_name"><span
class="parent_name">${parentName}</span>${name}</td>
{{/if}}
=======================================
--- /src/robot/webcontent/testdata/data.js Wed Jun 15 00:35:23 2011
+++ /src/robot/webcontent/testdata/data.js Wed Jun 15 04:28:20 2011
@@ -12,9 +12,8 @@
strings: window._strings
}
window.settings = {
- logPath: 'log.html',
- reportPath: 'report.html',
- passBackground: '#99FF66',
- nonCriticalFailBackground: '#99FF66',
- criticalFailBackground: '#FF3333'
-}
+ title: 'Title',
+ logURL: 'log.html',
+ reportURL: 'report.html',
+ background:
{pass: '#99FF66',nonCriticalFail: '#99FF66',fail: '#FF3333'}
+}
==============================================================================
Revision: 80afd415b7f9
Author: Jussi Malinen <jussi.ao.mali...@gmail.com>
Date: Wed Jun 15 04:28:42 2011
Log: merge
http://code.google.com/p/robotframework/source/detail?r=80afd415b7f9
Deleted:
/src/robot/serializing/logserializers.py
/src/robot/serializing/reportserializers.py
/src/robot/serializing/statserializers.py
/src/robot/serializing/templates.py
=======================================
--- /src/robot/serializing/logserializers.py Mon May 9 02:38:16 2011
+++ /dev/null
@@ -1,305 +0,0 @@
-# Copyright 2008-2011 Nokia Siemens Networks Oyj
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import os.path
-
-from robot import utils
-
-
-class LogSerializer:
-
- def __init__(self, output, split_level=-1):
- self._writer = utils.HtmlWriter(output)
- self._writer.element('h2', 'Test Execution Log')
- self._idgen = utils.IdGenerator()
- self._suite_level = 0
- self._split_level = split_level
-
- def start_suite(self, suite):
- suite.id = self._idgen.get_id('suite')
- self._writer.start('table', {'class': 'suite', 'id': suite.id})
- self._write_suite_or_test_name(suite, 'suite')
- self._writer.start_many(['tr', 'td'])
- self._writer.start('div', {'class': 'indent',
- 'style': self._get_display_style(suite),
- 'id': '%s_children' % suite.id})
- self._write_suite_metadata(suite)
- self._suite_level += 1
-
- def end_suite(self, suite):
- self._writer.end_many(['div','td','tr','table'])
- self._suite_level -= 1
-
- def start_test(self, test):
- test.id = self._idgen.get_id('test')
- self._writer.start('table', {'class': 'test', 'id': test.id})
- self._write_suite_or_test_name(test, 'test')
- self._writer.start_many(['tr', 'td'])
- self._writer.start('div', {'class': 'indent',
- 'style': self._get_display_style(test),
- 'id': '%s_children' % test.id})
- self._write_test_metadata(test)
-
- def end_test(self, test):
- self._writer.end_many(['div','td','tr','table'])
-
- def start_keyword(self, kw):
- kw.id = self._idgen.get_id('kw')
- self._writer.start('table', {'class': 'keyword', 'id': kw.id})
- self._write_keyword_name(kw)
- self._writer.start('tr')
- self._writer.start('td', newline=True)
- self._writer.start('div', {'class': 'indent',
- 'style': self._get_display_style(kw),
- 'id': '%s_children' % kw.id})
- self._write_keyword_info(kw)
-
- def end_keyword(self, kw):
- self._writer.end_many(['div','td','tr','table'])
-
- def message(self, msg):
- self._writer.start('table', {'class': 'messages'})
- self._writer.start('tr')
- attrs = {'class': 'time'}
- if msg.level in ['WARN', 'ERROR']:
- # Allow linking from Test Execution Errors table
- attrs['id'] = 'msg_%s' % msg.get_timestamp(sep='_')
- self._writer.element('td', msg.time, attrs)
- self._writer.element('td', msg.level,
- {'class': '%s level' % msg.level.lower()})
- self._writer.element('td', msg.message, {'class': 'msg'},
- escape=not msg.html)
- self._writer.end_many(['tr', 'table'])
-
- def _write_suite_or_test_name(self, item, type_):
- self._writer.start_many(['tr', 'td'])
- self._write_expand_all(item)
- self._write_folding_button(item)
- label = type_ == 'suite' and 'TEST SUITE: '
or 'TEST CASE: '
- self._writer.element('span', label, {'class': item.status.lower()},
- escape=False)
- name = item.get_long_name(self._split_level)
- self._writer.element('a', item.name, {'name': '%s_%s' % (type_,
name),
- 'class': 'name', 'title':
name})
- self._writer.end_many(['td', 'tr'])
-
- def _write_expand_all(self, item):
- # Overridden by testdoc.py tool.
- attrs = {'href': "javascript:expand_all_children('%s')" % item.id,
- 'class': 'expand'}
- self._writer.element('a', 'Expand All', attrs)
-
- def _write_keyword_name(self, kw):
- self._writer.start('tr')
- self._writer.start('td')
- self._write_folding_button(kw)
- status = {'class': kw.status.lower()}
- if kw.type == 'for':
- self._writer.element('span', 'FOR ', status)
- self._writer.element('span', kw.name, {'class': 'arg'})
- elif kw.type == 'foritem':
- self._writer.element('span', 'VAR: ', status)
- self._writer.element('span', kw.name, {'class': 'arg'})
- else:
- kw_type = kw.type in ['setup','teardown'] and kw.type
or 'keyword'
- self._writer.element('span', kw_type.upper()+': ', status)
- self._writer.element('span', kw.name+' ', {'class': 'name'})
- self._writer.element('span', ', '.join(kw.args),
{'class': 'arg'})
- self._writer.end_many(['td', 'tr'])
-
- def _write_keyword_info(self, kw):
- self._writer.start('table', {'class': 'metadata'})
- doc = utils.html_escape(kw.doc, formatting=True)
- self._write_metadata_row('Documentation', doc, escape=False)
- self._write_metadata_row('Timeout', kw.timeout)
- self._write_times(kw)
- self._writer.end('table')
-
- def _write_folding_button(self, item):
- fold, unfold = self._is_element_open(item) and ('-','+') or
('+','-')
- onclk = "toggle_child_visibility('%s');" % item.id
- self._write_button(unfold, 'none', item.id+'_unfoldlink', onclk)
- self._write_button(fold, 'block', item.id+'_foldlink', onclk)
-
- def _write_button(self, label, display, id_, onclick):
- attrs = {'style': 'display: %s;' %
display, 'class': 'foldingbutton',
- 'id': id_, 'onclick': onclick}
- self._writer.element('div', label, attrs)
-
- def _is_element_open(self, item):
- if item.status == 'FAIL':
- return True
- try:
- return item.all_stats.failed > 0 or self._suite_level == 0
- except AttributeError:
- return False
-
- def _get_display_style(self, item):
- style = self._is_element_open(item) and 'block' or 'none'
- return 'display: %s;' % style
-
- def _write_suite_metadata(self, suite):
- self._start_suite_or_test_metadata(suite)
- for name, value in suite.get_metadata(html=True):
- self._write_metadata_row(name, value, escape=False,
- escape_name=True, write_empty=True)
- self._write_source(suite.source)
- self._write_times(suite)
- self._write_metadata_row('Overall Status', suite.status,
- {'class': suite.status.lower()})
- self._write_metadata_row('Message',
suite.get_full_message(html=True),
- escape=False)
- self._write_split_suite_details_link()
- self._writer.end('table')
-
- def _write_source(self, source):
- if source:
- if os.path.exists(source):
- ref = utils.get_link_path(source, self._writer.output.name)
- source = '<a href="%s">%s</a>' % (ref, source)
- self._write_metadata_row('Source', source, escape=False)
-
- def _write_test_metadata(self, test):
- self._start_suite_or_test_metadata(test)
- self._write_metadata_row('Timeout', test.timeout)
- self._write_metadata_row('Tags', ', '.join(test.tags))
- self._write_times(test)
- crit = test.critical == 'yes' and 'critical' or 'non-critical'
- self._write_metadata_row('Status', '%s (%s)' % (test.status, crit),
- {'class': test.status.lower()})
- self._write_metadata_row('Message', test.message)
- self._writer.end('table')
-
- def _start_suite_or_test_metadata(self, item):
- self._writer.start('table', {'class': 'metadata'})
- self._write_metadata_row('Full Name', item.longname)
- self._write_metadata_row('Documentation', item.htmldoc,
escape=False)
-
- def _write_times(self, item):
- titles = ' / '.join(['Start','End','Elapsed'])
- times = ' / '.join([item.starttime, item.endtime,
-
utils.elapsed_time_to_string(item.elapsedtime)])
- self._write_metadata_row(titles, times)
-
- def _write_metadata_row(self, name, value, attrs={}, escape=True,
- escape_name=False, write_empty=False):
- if value or write_empty:
- self._writer.start('tr', newline=False)
- self._writer.element('th', name+':', escape=escape_name,
- newline=False)
- self._writer.element('td', value, attrs, escape=escape,
- newline=False)
- self._writer.end('tr')
-
- def _write_split_suite_details_link(self):
- pass
-
-
-class SplitLogSerializer(LogSerializer):
-
- def __init__(self, output, split_level):
- LogSerializer.__init__(self, output, split_level)
- self._namegen =
utils.FileNameGenerator(os.path.basename(output.name))
-
- def start_suite(self, suite):
- if self._suite_level <= self._split_level:
- LogSerializer.start_suite(self, suite)
- else:
- self._suite_level += 1
-
- def end_suite(self, suite):
- if self._suite_level <= self._split_level + 1:
- LogSerializer.end_suite(self, suite)
- else:
- self._suite_level -= 1
-
- def start_test(self, test):
- if self._suite_level <= self._split_level:
- LogSerializer.start_test(self, test)
-
- def end_test(self, test):
- if self._suite_level <= self._split_level:
- LogSerializer.end_test(self, test)
-
- def start_keyword(self, kw):
- if self._suite_level <= self._split_level:
- LogSerializer.start_keyword(self, kw)
-
- def end_keyword(self, kw):
- if self._suite_level <= self._split_level:
- LogSerializer.end_keyword(self, kw)
-
- def message(self, msg):
- if self._suite_level <= self._split_level:
- LogSerializer.message(self, msg)
-
- def _write_suite_or_test_name(self, item, type_):
- if type_ == 'test' or self._suite_level < self._split_level:
- LogSerializer._write_suite_or_test_name(self, item, type_)
- elif self._suite_level == self._split_level:
- self._write_split_suite_name(item)
-
- def _write_split_suite_name(self, suite):
- self._writer.start_many(['tr', 'td'])
- self._write_folding_button(suite)
- self._writer.element('span', 'TEST SUITE: ',
- {'class': suite.status.lower()}, escape=False)
- link = '%s#suite_%s' % (self._namegen.get_name(), suite.name)
- self._writer.element('a', suite.name,
- {'name': 'suite_%s' % suite.longname,
- 'href': link, 'class': 'splitname',
- 'title': suite.longname})
- self._writer.end_many(['td', 'tr'])
-
- def _write_split_suite_details_link(self):
- if self._suite_level == self._split_level:
- name = self._namegen.get_prev()
- link = '<a href="%s">%s</a>' % (name, name)
- self._write_metadata_row('Details', link, escape=False)
-
-
-class ErrorSerializer:
-
- def __init__(self, output):
- self._writer = utils.HtmlWriter(output)
-
- def start_errors(self, errors):
- if errors.messages:
- self._writer.element('h2', 'Test Execution Errors')
- self._writer.start('table', {'class': 'errors'})
-
- def message(self, msg):
- self._writer.start('tr')
- self._writer.start('td', {'class': 'time'}, newline=False)
- self._write_timestamp(msg)
- self._writer.end('td')
- self._writer.element('td', msg.level,
- {'class': '%s level' % msg.level.lower()})
- self._writer.element('td', msg.message, {'class': 'msg'},
- escape=not msg.html)
- self._writer.end('tr')
-
- def _write_timestamp(self, msg):
- if msg.linkable:
- attrs = {'href': "#msg_%s" % msg.get_timestamp(sep='_'),
- 'onclick': "set_element_visible('msg_%s')" %
msg.get_timestamp(sep='_'),
- 'title': 'Link to details.'}
- self._writer.start('a', attrs, newline=False)
- self._writer.content(msg.get_timestamp(sep=' '), escape=False)
- if msg.linkable:
- self._writer.end('a', newline=False)
-
- def end_errors(self, errors):
- if errors.messages:
- self._writer.end('table')
=======================================
--- /src/robot/serializing/reportserializers.py Sun Feb 6 01:24:10 2011
+++ /dev/null
@@ -1,236 +0,0 @@
-# Copyright 2008-2011 Nokia Siemens Networks Oyj
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-from robot import utils
-
-
-class _TableHelper:
-
- def _start_table(self, name, tag_column_name):
- self._writer.start('table', {'class': name})
- self._writer.start('tr')
- self._writer.element('th', 'Name', {'class': 'col_name'})
- self._writer.element('th', 'Documentation', {'class': 'col_doc'})
- self._writer.element('th', tag_column_name,
- {'class': 'col_tags'}, escape=False)
- self._writer.element('th', 'Crit.', {'class': 'col_crit'})
- self._writer.element('th', 'Status', {'class': 'col_status'})
- self._writer.element('th', 'Message', {'class': 'col_msg'})
- self._writer.element('th', 'Start / Elapsed',
- {'class': 'col_times'}, escape=False)
- self._writer.end('tr')
-
- def _test_row(self, test):
- self._start_suite_or_test_row(test, 'test')
- self._end_test_row(test)
-
- def _suite_row(self, suite):
- self._start_suite_or_test_row(suite, 'suite')
- self._end_suite_row(suite)
-
- def _start_suite_or_test_row(self, item, type_):
- self._writer.start('tr', {'class': '%s_row' % type_})
- self._writer.start('td', {'class': 'col_name'}, newline=False)
- self._write_name(item, type_)
- self._writer.end('td')
- self._writer.element('td', item.htmldoc, {'class': 'col_doc'},
- escape=False)
-
- def _write_name(self, item, type_):
- attrs = {'id': '%s_%s' % (type_,item.longname), 'title':
item.longname}
- if item.linkpath:
- elem = 'a'
- attrs['href'] = '%s#%s_%s' % (item.linkpath, type_,
item.linkname)
- else:
- elem = 'span'
- self._writer.start(elem, attrs, newline=False)
- self._write_item_name(item, type_)
- self._writer.end(elem, newline=False)
-
- def _write_item_name(self, item, type_):
- name = type_ == 'suite' and item.longname or item.name
- return self._writer.content(name)
-
- def _end_test_row(self, test):
- self._writer.element('td', ', '.join(test.tags),
{'class': 'col_tags'})
- self._writer.element('td', test.critical, {'class': 'col_crit'})
- self._writer.element('td', test.status,
- {'class': 'col_status %s' %
test.status.lower()})
- self._writer.element('td', test.message, {'class': 'col_msg'})
- self._writer.element('td', self._get_times(test),
- {'class': 'col_times'}, escape=False)
- self._writer.end('tr')
-
- def _get_times(self, item):
- """Return start and elapsed time in html format without millis.
-
- Millis are stripped from start time but elapsed is rounded to
closest
- second.
- """
- if item.starttime == 'N/A':
- start = 'N/A'
- else:
- start = item.starttime[:-4].replace(' ', ' ')
- if item.elapsedtime < 0: # --CombinedTime NONE
- elapsed = ' '
- else:
- rounded_millis = round(item.elapsedtime, -3)
- elapsed = utils.elapsed_time_to_string(rounded_millis)[:-4]
- return '%s<br />%s' % (start, elapsed)
-
-
-class ReportSerializer(_TableHelper):
- end_test = start_keyword = end_keyword = message = lambda self, arg:
None
-
- def __init__(self, output, logpath=None):
- self._writer = utils.HtmlWriter(output)
- self._loglink = logpath and \
- utils.get_link_path(logpath, output.name) or None
- self._suite_level = 0
-
- def start_suite(self, suite):
- self._suite_level += 1
- self._set_suite_link(suite)
- if self._suite_level == 1:
- self._writer.element('h2', 'Test Details by Suite')
-
self._start_table('tests_by_suite', 'Metadata / Tags')
- self._suite_row(suite)
-
- def end_suite(self, suite):
- self._suite_level -= 1
- if self._suite_level == 0:
- self._writer.end('table')
-
- def start_test(self, test):
- self._set_test_link(test)
- self._test_row(test)
-
- def _set_suite_link(self, suite):
- # linkpath and linkname are also used when TagStats are serialized.
- # This is rather ugly and should be refactored at some point.
- suite.linkpath = self._loglink
- suite.linkname = suite.longname
-
- def _set_test_link(self, test):
- # Separate _set_test/suite_link methods are needed to allow
overriding
- # them separately in SplitReportSerializer
- test.linkpath = self._loglink
- test.linkname = test.longname
-
- def _end_suite_row(self, suite):
- self._writer.start('td', {'class': 'col_tags'})
- for name, value in suite.get_metadata(html=True):
- self._writer.element('span', '%s: ' % name,
{'class': 'meta_name'})
- self._writer.content(value, escape=False)
- self._writer.start_and_end('br')
- self._writer.end('td')
- self._writer.element('td', 'N/A', {'class': 'col_crit
not_available'})
- self._writer.element('td', suite.status,
- {'class': 'col_status %s' %
suite.status.lower()})
- self._writer.element('td', suite.get_full_message(html=True),
- {'class': 'col_msg'}, escape=False)
- self._writer.element('td', self._get_times(suite),
- {'class': 'col_times'}, escape=False)
- self._writer.end('tr')
-
-
-class SplitReportSerializer(ReportSerializer):
-
- def __init__(self, output, logpath, split_level):
- ReportSerializer.__init__(self, output, logpath)
- self._split_level = split_level
- self._namegen = utils.FileNameGenerator(self._loglink)
-
- def _set_suite_link(self, suite):
- if self._suite_level <= self._split_level:
- ReportSerializer._set_suite_link(self, suite)
- else:
- if self._suite_level == self._split_level + 1:
- self._split_loglink = self._namegen.get_name()
- self._set_split_link(suite)
-
- def _set_test_link(self, test):
- if self._suite_level <= self._split_level:
- ReportSerializer._set_test_link(self, test)
- else:
- self._set_split_link(test)
-
- def _set_split_link(self, item):
- item.linkpath = self._split_loglink
- item.linkname = item.get_long_name(self._split_level)
-
-
-class TagDetailsSerializer(_TableHelper):
-
- def __init__(self, output):
- self._writer = utils.HtmlWriter(output)
-
- def start_tag_stats(self, stats):
- if stats.stats:
- self._writer.element('h2', 'Test Details by Tag')
- self._start_table('tests_by_tag', 'Tags')
-
- def end_tag_stats(self, stats):
- if stats.stats:
- self._writer.end('table')
-
- def tag_stat(self, stat):
- self._tag_row(stat)
- for test in stat.tests:
- self._test_row(test)
-
- def _write_item_name(self, stat, type_is_ignored):
- tokens = stat.get_long_name(separator=None)
- self._writer.element('span', ' . '.join(tokens[:-1]+['']),
- {'class': 'parent_name'}, newline=False)
- self._writer.content(tokens[-1])
-
- def _tag_row(self, stat):
- self._writer.start('tr', {'class': 'tag_row'})
- self._writer.start('td', {'class': 'col_name'}, newline=False)
- self._writer.element('a', None, {'name': 'tag_%s' % stat.name},
- newline=False)
- self._writer.content(stat.name)
- self._writer.end('td')
- doc = utils.html_escape(stat.get_doc() or '', formatting=True)
- self._writer.element('td', doc, {'class': 'col_doc'}, escape=False)
- self._writer.element('td', 'N/A', {'class': 'col_tags
not_available'})
- self._writer.element('td', self._get_crit(stat),
{'class': 'col_crit'})
- status = stat.failed == 0 and 'PASS' or 'FAIL'
- self._writer.element('td', status,
- {'class': 'col_status %s' % status.lower()})
- self._writer.element('td', self._get_msg(stat.passed, stat.failed),
- {'class': 'col_msg'}, escape=False)
- self._writer.element('td', self._get_elapsed(stat.tests),
- {'class': 'col_times'})
- self._writer.end('tr')
-
- def _get_msg(self, passed, failed):
- total = passed + failed
- class_ = failed > 0 and ' class="fail"' or ''
- return '%d test%s, %d passed, <span%s>%d failed</span>' \
- % (total, utils.plural_or_not(total), passed, class_,
failed)
-
- def _get_elapsed(self, tests):
- millis = sum([test.elapsedtime for test in tests])
- millis = round(millis, -3) # millis not shown in report
- return utils.elapsed_time_to_string(millis)[:-4]
-
- def _get_crit(self, stat):
- if stat.critical:
- return 'crit.'
- if stat.non_critical:
- return 'non-c.'
- return ''
=======================================
--- /src/robot/serializing/statserializers.py Sun Feb 6 01:24:10 2011
+++ /dev/null
@@ -1,250 +0,0 @@
-# Copyright 2008-2011 Nokia Siemens Networks Oyj
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-import os.path
-
-from robot import utils
-
-
-class _StatSerializer:
-
- def __init__(self, output, split_level=-1):
- self._writer = utils.HtmlWriter(output)
- self._split_level = split_level
-
- def start_statistics(self, statistics):
- self._writer.element('h2', 'Test Statistics')
-
- def end_statistics(self, statistics):
- pass
-
- def start_total_stats(self, total_stats):
- self._statistics_table(total_stats, 'Total Statistics')
-
- def start_tag_stats(self, tag_stats):
- self._statistics_table(tag_stats, 'Statistics by Tag')
-
- def start_suite_stats(self, suite_stats):
- self._statistics_table(suite_stats, 'Statistics by Suite')
-
- def end_total_stats(self, total_stats):
- self._writer.end('table')
-
- end_tag_stats = end_suite_stats = end_total_stats
-
- def total_stat(self, stat):
- elem = self._start_stat_name(stat)
- self._write_stat_name(stat)
- self._end_stat_name(elem)
- self._write_numbers_and_graph(stat)
-
- def suite_stat(self, stat):
- elem = self._start_stat_name(stat)
- self._write_suite_stat_name(stat)
- self._end_stat_name(elem)
- self._write_numbers_and_graph(stat)
-
- def tag_stat(self, stat):
- elem = self._start_stat_name(stat)
- self._write_stat_name(stat)
- self._end_tag_stat_name(elem, stat)
- self._write_numbers_and_graph(stat)
-
- def _start_stat_name(self, stat):
- self._writer.start('tr')
- self._writer.start('td', {'class': 'col_stat_name'})
- self._writer.start('div', {'class': 'stat_name'}, newline=False)
- elem, attrs = self._get_element_name_and_attrs(stat)
- doc = stat.get_doc(self._split_level)
- if doc:
- attrs['title'] = doc
- self._writer.start(elem, attrs, newline=False)
- return elem
-
- def _write_stat_name(self, stat):
- self._writer.content(stat.name)
-
- def _write_suite_stat_name(self, stat):
- tokens = stat.get_long_name(self._split_level, separator=None)
- if len(tokens) > 1:
- self._writer.element('span', ' . '.join(tokens[:-1]+['']),
- {'class': 'parent_name'}, newline=False)
- self._writer.content(tokens[-1])
-
- def _end_stat_name(self, elem):
- self._writer.end(elem, newline=False)
- self._writer.end('div')
- self._writer.end('td')
-
- def _end_tag_stat_name(self, elem, stat):
- self._writer.end(elem, newline=False)
- self._write_tag_criticality(stat)
- self._writer.end('div')
- self._write_tag_stat_link(stat)
- self._writer.end('td')
-
- def _write_numbers_and_graph(self, stat):
- self._writer.element('td', stat.passed + stat.failed,
- {'class': 'col_stat'})
- self._writer.element('td', stat.passed, {'class': 'col_stat'})
- self._writer.element('td', stat.failed, {'class': 'col_stat'})
- self._writer.start('td', {'class': 'col_graph'})
- self._writer.start('div', {'class': 'graph'})
- self._write_graph(stat)
- self._writer.end_many(['div', 'td', 'tr'])
-
- def _write_graph(self, stat):
- # See utils.percents_to_widths to understand why different percent
and
- # width values are needed
- percents = _Percents(stat.passed, stat.failed)
- pass_attrs = {'class': 'pass_bar',
- 'title': '%.1f%%' % percents.pass_percent,
- 'style': 'width: %.2f%%;' % percents.pass_width}
- fail_attrs = {'class': 'fail_bar',
- 'title': '%.1f%%' % percents.fail_percent,
- 'style': 'width: %.2f%%;' % percents.fail_width}
- self._writer.element('b', None, pass_attrs)
- self._writer.element('b', None, fail_attrs)
-
- def _statistics_table(self, statistics, title):
- self._writer.start('table', {'class': 'statistics'})
- self._writer.start('tr')
- self._writer.element('th', title, {'class': 'col_stat_name'})
- self._writer.element('th', 'Total', {'class': 'col_stat'})
- self._writer.element('th', 'Pass', {'class': 'col_stat'})
- self._writer.element('th', 'Fail', {'class': 'col_stat'})
- self._writer.element('th', 'Graph', {'class': 'col_graph'})
- self._writer.end('tr')
- # processing tag stats but no tags specified
- if hasattr(statistics, 'stats') and statistics.stats == {}:
- self._no_tag_statistics()
-
- def _no_tag_statistics(self):
- self._writer.start('tr')
- self._writer.element('td', 'No Tags', {'class': 'col_stat_name'})
- self._writer.element('td', None, {'class': 'col_stat'})
- self._writer.element('td', None, {'class': 'col_stat'})
- self._writer.element('td', None, {'class': 'col_stat'})
- self._writer.start('td', {'class': 'col_graph'})
- self._writer.start('div', {'class': 'graph'})
- self._writer.element('b', None, {'class': 'no_tags_bar',
- 'style': 'width: 100%;'})
- self._writer.end_many(['div', 'td', 'tr'])
-
- def _write_tag_criticality(self, stat):
- if stat.critical:
- self._writer.content(' (critical)')
- if stat.non_critical:
- self._writer.content(' (non-critical)')
-
- def _write_tag_stat_link(self, stat):
- self._writer.start('div', {'class': 'tag_links'})
- for link, title in stat.links:
- self._writer.start('span', newline=False)
- self._writer.content('[')
- self._writer.element('a', title, {'href': link}, newline=False)
- self._writer.content(']')
- self._writer.end('span')
- self._writer.end('div')
-
-
-class LogStatSerializer(_StatSerializer):
-
- def _get_element_name_and_attrs(self, stat):
- if stat.type == 'suite':
- return 'a', self._get_link_attributes(stat)
- return 'span', {}
-
- def _get_link_attributes(self, stat):
- target = 'suite_%s' % stat.get_link(self._split_level)
- return {'href': '#' + target,
- 'onclick': "set_element_visible('%s')" % target}
-
-
-class SplitLogStatSerializer(LogStatSerializer):
-
- def __init__(self, output, split_level):
- LogStatSerializer.__init__(self, output, split_level=-1)
- self._split_border = split_level
- self._link_target = None
- self._namegen =
utils.FileNameGenerator(os.path.basename(output.name))
-
- def _get_link_attributes(self, stat):
- border = self._before_after_or_on_split_border(stat)
- if border < 0:
- return LogStatSerializer._get_link_attributes(self, stat)
- if border == 0:
- self._link_target = self._namegen.get_name()
- return {'href': '%s#suite_%s' % (self._link_target,
-
stat.get_link(self._split_border))}
-
- def _before_after_or_on_split_border(self, stat):
- tokens = stat.get_long_name(separator=None)
- return cmp(len(tokens), self._split_border+1)
-
-
-class ReportStatSerializer(_StatSerializer):
-
- def _get_element_name_and_attrs(self, stat):
- if stat.type in ['suite', 'tag']:
- return 'a', {'href': '#%s_%s' % (stat.type, stat.get_link())}
- return 'span', {}
-
-
-class SummaryStatSerializer(_StatSerializer):
-
- def _get_element_name_and_attrs(self, stat):
- return 'span', {}
-
-
-class _Percents(object):
-
- def __init__(self, passed, failed):
- self.pass_percent, self.fail_percent \
- = self._calculate_percents(passed, failed)
- self.pass_width, self.fail_width \
- = self._calculate_widths(self.pass_percent, self.fail_percent)
-
- def _calculate_percents(self, passed, failed):
- total = passed + failed
- if total == 0:
- return 0.0, 0.0
- pass_percent = 100.0 * passed / total
- fail_percent = 100.0 * failed / total
- if 0 < pass_percent < 0.1:
- return 0.1, 99.9
- if 0 < fail_percent < 0.1:
- return 99.9, 0.1
- return round(pass_percent, 1), round(fail_percent, 1)
-
- def _calculate_widths(self, num1, num2):
- if num1 + num2 == 0:
- return 0.0, 0.0
- # Make small percentages better visible
- if 0 < num1 < 1:
- num1, num2 = 1.0, 99.0
- if 0 < num2 < 1:
- num1, num2 = 99.0, 1.0
- # Handle situation where both are rounded up
- while num1 + num2 > 100:
- num1, num2 = self._subtract_from_larger(num1, num2, 0.1)
- # Make sure both pass and fail bar fit into 100% also in IE
- num1, num2 = self._subtract_from_larger(num1, num2, 0.01)
- return num1, num2
-
- def _subtract_from_larger(self, num1, num2, subtr):
- if num1 > num2:
- return num1-subtr, num2
- return num1, num2-subtr
=======================================
--- /src/robot/serializing/templates.py Sun Feb 6 01:24:10 2011
+++ /dev/null
@@ -1,572 +0,0 @@
-# Copyright 2008-2011 Nokia Siemens Networks Oyj
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-_STYLE = '''
-<style media="all" type="text/css">
- /* Generic styles */
- body {
- font-family: sans-serif;
- font-size: 0.8em;
- color: black;
- padding: 6px;
- }
- h2 {
- margin-top: 1.2em;
- }
- br {
- mso-data-placement: same-cell; /* maintain line breaks in Excel */
- }
- /* Statistics Table */
- table.statistics {
- width: 58em;
- border: 1px solid black;
- border-collapse: collapse;
- empty-cells: show;
- margin-bottom: 1em;
- }
- table.statistics td, table.statistics th {
- border: 1px solid black;
- padding: 1px 4px;
- margin: 0px;
- }
- table.statistics th {
- background: #C6C6C6;
- }
- .col_stat_name {
- width: 40em;
- }
- .col_stat {
- width: 3em;
- text-align: center;
- }
- .stat_name {
- float: left;
- }
- .stat_name a, .stat_name span {
- font-weight: bold;
- }
- .tag_links {
- font-size: 0.9em;
- float: right;
- margin-top: 0.05em;
- }
- .tag_links span {
- margin-left: 0.2em;
- }
- /* Statistics Table Graph */
- .pass_bar {
- background: #00f000;
- }
- .fail_bar {
- background: red;
- }
- .no_tags_bar {
- background: #E9E9E9;
- }
- .graph {
- position: relative;
- border: 1px solid black;
- width: 11em;
- height: 0.75em;
- padding: 0px;
- background: #E9E9E9;
- }
- .graph b {
- display: block;
- position: relative;
- height: 100%;
- float: left;
- font-size: 4px; /* to make graphs thin also in IE */
- }
- /* Tables in documentation */
- table.doc {
- border: 1px solid gray;
- background: transparent;
- border-collapse: collapse;
- empty-cells: show;
- font-size: 0.9em;
- }
- table.doc td {
- border: 1px solid gray;
- padding: 0.1em 0.3em;
- height: 1.2em;
- }
- /* Misc Styles */
- .not_available {
- color: gray; /* no grey in IE */
- font-weight: normal;
- }
- .parent_name {
- font-size: 0.7em;
- letter-spacing: -0.07em;
- }
- a:link, a:visited {
- text-decoration: none;
- color: blue;
- }
- a:hover, a:active {
- text-decoration: underline;
- color: purple;
- }
- /* Headers */
- .header {
- width: 58em;
- margin: 6px 0px;
- }
- h1 {
- margin: 0px;
- width: 70%;
- float: left;
- }
- .times {
- width: 29%;
- float: right;
- text-align: right;
- }
- .generated_time, .generated_ago {
- font-size: 0.9em;
- }
- .spacer {
- font-size: 0.8em;
- clear: both;
- }
- /* Status text colors */
- .error, .fail {
- color: red;
- }
- .pass {
- color: #009900;
- }
- .warn {
- color: #FFCC00;
- }
- .not_run {
- color: #663300;
- }
-</style>
-<style media="print" type="text/css">
- body {
- background: white;
- padding: 0px;
- font-size: 8pt;
- }
- a:link, a:visited {
- color: black;
- }
- .header, table.details, table.statistics {
- width: 100%;
- }
- .generated_ago, .expand {
- display: none;
- }
-</style>
-'''[1:-1]
-
-
-_FUNCTIONS = '''
-<!-- FUNCTION meta ${version} -->
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta http-equiv="Expires" content="Mon, 20 Jan 2001 20:01:21 GMT" />
-<meta name="generator" content="${version}" />
-<!-- END FUNCTION -->
-<!-- FUNCTION generate_header ${title} -->
-<div class="header">
- <h1>${title}</h1>
- <div class="times">
- <span class="generated_time">Generated<br />${GENTIME_STR}</span><br />
- <span class="generated_ago">
-<script type="text/javascript">
- function get_end(number) {
- if (number == 1) { return ' ' }
- return 's '
- }
- function get_sec_str(secs) {
- return secs + ' second' + get_end(secs)
- }
- function get_min_str(mins) {
- return mins + ' minute' + get_end(mins)
- }
- function get_hour_str(hours) {
- return hours + ' hour' + get_end(hours)
- }
- function get_day_str(days) {
- return days + ' day' + get_end(days)
- }
- function get_year_str(years) {
- return years + ' year' + get_end(years)
- }
- generated = ${GENTIME_INT}
- current = Math.round(new Date().getTime() / 1000) // getTime returns
millis
- elapsed = current - generated
- // elapsed should only be negative if clocks are not in sync
- if (elapsed < 0) {
- elapsed = Math.abs(elapsed)
- prefix = '- '
- }
- else {
- prefix = ''
- }
- secs = elapsed % 60
- mins = Math.floor(elapsed / 60) % 60
- hours = Math.floor(elapsed / (60*60)) % 24
- days = Math.floor(elapsed / (60*60*24)) % 365
- years = Math.floor(elapsed / (60*60*24*365))
- if (years > 0) {
- // compencate the effect of leap years (not perfect but should be
enough)
- days = days - Math.floor(years / 4)
- if (days < 0) { days = 0 }
- output = get_year_str(years) + get_day_str(days)
- }
- else if (days > 0) {
- output = get_day_str(days) + get_hour_str(hours)
- }
- else if (hours > 0) {
- output = get_hour_str(hours) + get_min_str(mins)
- }
- else if (mins > 0) {
- output = get_min_str(mins) + get_sec_str(secs)
- }
- else {
- output = get_sec_str(secs)
- }
- document.write(prefix + output + 'ago')
-</script>
- </span>
- </div>
-</div>
-<div class="spacer"> </div>
-<!-- END FUNCTION -->
-'''
-
-
-LOG = '''%(FUNCTIONS)s
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01
Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
-<!-- CALL meta ${version} -->
-%(STYLE)s
-<style media="all" type="text/css">
- /* Tables */
- body {
- background: white;
- }
- table.suite, table.errors {
- width: 100%%;
- border: 1px solid gray; /* no grey in IE */
- margin: 0.2em 0em;
- padding: 0.2em;
- }
- table.errors td.level {
- font-weight: bold;
- width: 4em;
- text-align: center;
- vertical-align: top;
- }
- table.errors td.time {
- width: 10em;
- vertical-align: top;
- }
- table.test {
- width: 100%%;
- border: 1px dashed gray;
- margin: 0.2em 0em;
- padding: 0.2em;
- }
- table.metadata, table.keyword, table.messages {
- margin-left: 1.1em;
- width: 100%%;
- }
- table.metadata, table.messages {
- margin-right: 2em;
- }
- table.keyword table.metadata {
- font-size: 0.9em;
- margin-left: 1.4em;
- }
- table.messages {
- font-family: monospace;
- font-size: 1.2em;
- }
- table.metadata th {
- width: 12em;
- text-align: left;
- vertical-align: top;
- }
- table.metadata td {
- padding-left: 0.5em;
- vertical-align: top;
- }
- table.messages td {
- vertical-align: top;
- }
- table.messages td.time {
- width: 6em;
- letter-spacing: -0.05em;
- }
- table.messages td.level {
- width: 4em;
- text-align: center;
- }
- /* Folding buttons */
- div.foldingbutton {
- text-align: center;
- line-height: 0.8em;
- font-size: 0.8em;
- margin: 0.2em 0.4em 0em 0.1em;
- height: 0.9em;
- width: 0.9em;
- float: left;
- text-decoration: none;
- font-weight: bold;
- border: 1px solid black;
- border: 1px solid black;
- }
- div.foldingbutton:hover {
- background: yellow;
- }
- .expand {
- float: right;
- margin-right: 0.5em;
- font-size: 0.8em;
- }
- /* Test, suite and kw names */
- .name, .splitname {
- font-weight: bold;
- text-decoration: none;
- }
- a.name:hover {
- text-decoration: none;
- color: black;
- }
-</style>
-<script type="text/javascript">
- function toggle_child_visibility(element_id) {
- if (document.getElementById(element_id + '_children') != null) {
- toggle_visibility(element_id + '_children')
- }
- else {
- toggle_visibility(element_id)
- }
- if (document.getElementById(element_id + '_foldlink') != null) {
- toggle_visibility(element_id + '_foldlink')
- }
- if (document.getElementById(element_id + '_unfoldlink') != null) {
- toggle_visibility(element_id + '_unfoldlink')
- }
- }
- function toggle_visibility(element_id) {
- var element = document.getElementById(element_id)
- if (element == null) {
- return
- }
- if (element.style.display == 'none') {
- element.style.display = 'block'
- }
- else {
- element.style.display = 'none'
- }
- }
- function expand_all_children(element_id) {
- var elements =
document.getElementById(element_id).getElementsByTagName('div')
- for (var i=0; i<elements.length; i++) {
- var element = elements[i]
- if (element.className == 'indent' && element.style.display
== 'none') {
-
toggle_child_visibility(element.getAttribute('id').replace(/_children/, ''))
- }
- }
- }
- function open_element_by_url() {
- var name = get_element_name_from_url()
- if (name != null) {
- set_element_visible(name)
- window.location.hash = name // does not seem to work with
Opera
- }
- }
- function get_element_name_from_url() {
- var hash = window.location.hash
- if (hash == '' || hash == '#' || hash == null) {
- return null
- }
- return hash.slice(1).replace(/%%20/g, ' ')
- }
- function set_element_visible(id_or_name) {
- var element = document.getElementById(id_or_name)
- if (element) {
- open_parents(element)
- return
- }
- var elements = document.getElementsByName(id_or_name)
- for (var i=0; i<elements.length; i++) {
- open_parents(elements[i])
- }
- }
- // Find right type of parent element, open it and its parents
- function open_parents(element) {
- var parent = element.parentNode
- if (!parent) {
- return
- }
- // Find a parent table with id
- while (parent.nodeName != 'TABLE' || parent.getAttribute('id') ==
null) {
- parent = parent.parentNode
- if (!parent) {
- return
- }
- }
- var element_id = parent.getAttribute('id')
- if (document.getElementById(element_id+'_children').style.display
== 'none') {
- toggle_child_visibility(element_id)
- }
- open_parents(parent)
- }
-</script>
-
-<title>${title}</title>
-</head>
-<body onload="open_element_by_url()">
-<!-- CALL generate_header ${title} -->
-''' % {'STYLE': _STYLE, 'FUNCTIONS': _FUNCTIONS}
-
-
-REPORT = '''%(FUNCTIONS)s
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01
Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
-<!-- CALL meta ${version} -->
-<style media="all" type="text/css">
- body {
- background: ${BACKGROUND};
- }
- /* Generic Table Styles */
- table {
- background: white;
- border: 1px solid black;
- border-collapse: collapse;
- empty-cells: show;
- margin: 0px 1px;
- }
- th, td {
- border: 1px solid black;
- padding: 1px 5px;
- }
- th {
- background: #C6C6C6;
- color: black;
- }
- /* Test by Suite/Tag Tables */
- table.tests_by_suite, table.tests_by_tag {
- width: 100%%;
- }
- .col_name {
- width: 13em;
- font-weight: bold;
- }
- .col_doc {
- min-width: 13em;
- }
- .col_tags {
- width: 10em;
- }
- .col_crit {
- width: 2em;
- text-align: center;
- }
- .col_status {
- width: 3.5em;
- text-align: center;
- }
- .col_msg {
- min-width: 13em;
- }
- .col_times {
- width: 9em;
- }
- td.col_times{
- text-align: right;
- }
- .suite_row, .tag_row{
- background: #E9E9E9;
- }
- .meta_name {
- font-weight: bold;
- }
- /* Details Table */
- table.details {
- width: 58em;
- }
- table.details th {
- background: white;
- width: 9em;
- text-align: left;
- vertical-align: top;
- padding-right: 1em;
- border: none;
- padding: 2px 4px;
- }
- table.details td {
- vertical-align: top;
- border: none;
- padding: 2px 4px;
- }
- .status_fail {
- color: red;
- font-weight: bold;
- }
- .status_pass {
- color: #009900;
- }
-</style>
-%(STYLE)s
-<title>${title}</title>
-</head>
-<body>
-<!-- CALL generate_header ${title} -->
-<h2>Summary Information</h2>
-
-<table class="details">
-<tr>
- <th>Status:</th>
-<!-- IF ${SUITE.all_stats.failed} == 0 -->
- <td class="status_pass">All tests passed</td>
-<!-- END IF -->
-<!-- IF ${SUITE.all_stats.failed} != 0 and ${SUITE.critical_stats.failed}
== 0 -->
- <td class="status_pass">All critical tests passed</td>
-<!-- END IF -->
-<!-- IF ${SUITE.critical_stats.failed} == 1 -->
- <td class="status_fail">1 critical test failed</td>
-<!-- END IF -->
-<!-- IF ${SUITE.critical_stats.failed} > 1 -->
- <td class="status_fail">${SUITE.critical_stats.failed} critical tests
failed</td>
-<!-- END IF -->
-</tr>
-<!-- IF ${SUITE.htmldoc.__len__()} > 0 -->
- <tr><th>Documentation:</th><td>${SUITE.htmldoc}</td></tr>
-<!-- END IF -->
-<!-- FOR ${meta} IN ${SUITE.get_metadata(html=True)} -->
- <tr><th>${meta[0]}:</th><td>${meta[1]}</td></tr>
-<!-- END FOR -->
-<!-- IF '${SUITE.starttime}' != 'N/A' -->
- <tr><th>Start Time:</th><td>${SUITE.starttime}</td></tr>
-<!-- END IF -->
-<!-- IF '${SUITE.endtime}' != 'N/A' -->
- <tr><th>End Time:</th><td>${SUITE.endtime}</td></tr>
-<!-- END IF -->
-<tr><th>Elapsed Time:</th><td>${ELAPSEDTIME}</td></tr>
-</table>
-''' % {'STYLE': _STYLE, 'FUNCTIONS': _FUNCTIONS}
-
-
-del _STYLE
-del _FUNCTIONS