2 new revisions:
Revision: 39a8a60bac73
Author: Mikko Korpela <[email protected]>
Date: Thu Dec 1 04:32:24 2011
Log: Remove JsDataModelWriter
http://code.google.com/p/robotframework/source/detail?r=39a8a60bac73
Revision: 20e5edef7799
Author: Mikko Korpela <[email protected]>
Date: Thu Dec 1 04:32:37 2011
Log: Automated merge with https://code.google.com/p/robotframework/
http://code.google.com/p/robotframework/source/detail?r=20e5edef7799
==============================================================================
Revision: 39a8a60bac73
Author: Mikko Korpela <[email protected]>
Date: Thu Dec 1 04:32:24 2011
Log: Remove JsDataModelWriter
http://code.google.com/p/robotframework/source/detail?r=39a8a60bac73
Modified:
/src/robot/conf/settings.py
/src/robot/reporting/builders.py
/src/robot/reporting/jsondatamodel.py
/src/robot/reporting/resultwriter.py
/src/robot/result/datamodel.py
/src/robot/result/jsondatamodelhandlers.py
/utest/reporting/test_jsondatamodel.py
/utest/reporting/test_reporting.py
/utest/result/test_jsoning.py
=======================================
--- /src/robot/conf/settings.py Wed Nov 30 05:53:07 2011
+++ /src/robot/conf/settings.py Thu Dec 1 04:32:24 2011
@@ -335,3 +335,25 @@
self['TagStatExclude'], self['TagStatCombine'],
self['TagDoc'], self['TagStatLink'])
+ def log_configuration(self):
+ return {
+ 'title': self['LogTitle'],
+ 'reportURL': self._url_from_path(self.log, self.report),
+ 'splitLogBase': os.path.basename(os.path.splitext(self.log)[0])
+ }
+
+ def report_configuration(self):
+ return {
+ 'title': self['ReportTitle'],
+ 'logURL': self._url_from_path(self.report, self.log),
+ 'background' : self._resolve_background_colors(),
+ }
+
+ def _url_from_path(self, source, destination):
+ if not destination:
+ return None
+ return utils.get_link_path(destination, os.path.dirname(source))
+
+ def _resolve_background_colors(self):
+ colors = self['ReportBackground']
+ return {'pass': colors[0], 'nonCriticalFail': colors[1], 'fail':
colors[2]}
=======================================
--- /src/robot/reporting/builders.py Thu Dec 1 01:36:44 2011
+++ /src/robot/reporting/builders.py Thu Dec 1 04:32:24 2011
@@ -20,6 +20,7 @@
from robot.errors import DataError
from robot.output import LOGGER
+from robot.reporting.jsondatamodel import ScriptBlockWriter
from robot.result.serializer import RebotXMLWriter
from robot.version import get_full_version
from robot import utils
@@ -70,18 +71,18 @@
class _HTMLFileBuilder(_Builder):
- def _write_file(self, path, template):
+ def _write_file(self, path, config, template):
with codecs.open(path, 'w', encoding='UTF-8') as outfile:
- writer = HTMLFileWriter(outfile, self._model)
+ writer = HTMLFileWriter(outfile, self._model, config)
for line in _WebContentFile(template):
writer.line(line)
class LogBuilder(_HTMLFileBuilder):
- def build(self, path):
+ def build(self, path, config):
try:
- self._write_file(path, 'log.html')
+ self._write_file(path, config, 'log.html')
self._write_split_logs_if_needed(path)
except EnvironmentError, err:
LOGGER.error("Writing log file '%s' failed: %s" %
(err.filename, err.strerror))
@@ -90,7 +91,7 @@
def _write_split_logs_if_needed(self, path):
base = os.path.splitext(path)[0]
- for index, (keywords, strings) in
enumerate(self._model._split_results):
+ for index, (keywords, strings) in
enumerate(self._model.split_results):
index += 1 # enumerate accepts start index only in Py 2.6+
self._write_split_log(index, keywords, strings, '%s-%d.js' %
(base, index))
@@ -104,9 +105,9 @@
class ReportBuilder(_HTMLFileBuilder):
- def build(self, path):
+ def build(self, path, config):
try:
- self._write_file(path, 'report.html')
+ self._write_file(path, config, 'report.html')
except EnvironmentError, err:
LOGGER.error("Writing report file '%s' failed: %s" % (path,
err.strerror))
else:
@@ -119,9 +120,10 @@
_css_media_matcher = re.compile('media=\"([^\"]+)\"')
#TODO: output js_model_writer
- def __init__(self, outfile, output):
+ def __init__(self, outfile, model, config):
self._outfile = outfile
- self._output = output
+ self._model = model
+ self._config = config
def line(self, line):
if self._is_output_js(line):
@@ -155,7 +157,7 @@
def _write_output_js(self):
separator = '</script>\n<script type="text/javascript">\n'
self._write_tag('script', 'type="text/javascript"',
- lambda: self._output.write_to(self._outfile,
separator))
+ lambda:
ScriptBlockWriter(separator).write_to(self._outfile, self._model,
self._config))
def _inline_js_file(self, line):
self._write_tag('script', 'type="text/javascript"',
=======================================
--- /src/robot/reporting/jsondatamodel.py Thu Dec 1 01:36:44 2011
+++ /src/robot/reporting/jsondatamodel.py Thu Dec 1 04:32:24 2011
@@ -12,91 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import time
-
-from robot import utils
from robot.reporting.jsondump import JsonDumper
-from robot.reporting.parsingcontext import TextIndex
-
-
-# TODO: This class (and module) has too much responsibilities
-
-class DataModelWriter(object):
- _SUITE_KEY = 'suite'
- _STRINGS_KEY = 'strings'
-
- def __init__(self, robot_data, split_results=None):
- self._robot_data = robot_data
- self._split_results = split_results
- self._settings = None
- self._set_generated(time.localtime())
-
- def _set_generated(self, timetuple):
- genMillis = long(time.mktime(timetuple) * 1000) -\
- self._robot_data['baseMillis']
- self._set_attr('generatedMillis', genMillis)
- self._set_attr('generatedTimestamp',
- utils.format_time(timetuple, gmtsep=' '))
-
- def _set_attr(self, name, value):
- self._robot_data[name] = value
-
- def set_settings(self, settings):
- self._settings = settings
-
- def write_to(self, output, separator='', split_threshold=9500):
- ScriptBlockWriter(separator, split_threshold).write_to(output,
self)
-
- def remove_keywords(self):
- self._remove_keywords_from_suite(self._robot_data[self._SUITE_KEY])
- self._prune_unused_indices()
-
- # TODO: this and remove_keywords should be removed
- # instead there should be a reportify or write_for_report_to method
- def remove_errors(self):
- self._robot_data.pop('errors')
-
- def _remove_keywords_from_suite(self, suite):
- suite[8] = []
- for subsuite in suite[6]:
- self._remove_keywords_from_suite(subsuite)
- for test in suite[7]:
- test[-1] = []
-
- def _prune_unused_indices(self):
- used =
self._collect_used_indices(self._robot_data[self._SUITE_KEY], set())
- remap = {}
- self._robot_data[self._STRINGS_KEY] = \
- list(self._prune(self._robot_data[self._STRINGS_KEY], used,
remap))
- self._remap_indices(self._robot_data[self._SUITE_KEY], remap)
-
- def _prune(self, data, used, index_remap, map_index=None,
offset_increment=1):
- offset = 0
- for index, text in enumerate(data):
- index = map_index(index) if map_index else index
- if index in used:
- index_remap[index] = index - offset
- yield text
- else:
- offset += offset_increment
-
- def _remap_indices(self, data, remap):
- for i, item in enumerate(data):
- if isinstance(item, TextIndex):
- data[i] = remap[item]
- elif isinstance(item, list):
- self._remap_indices(item, remap)
-
- def _collect_used_indices(self, data, result):
- for item in data:
- if isinstance(item, TextIndex):
- result.add(item)
- elif isinstance(item, list):
- self._collect_used_indices(item, result)
- elif isinstance(item, dict):
- self._collect_used_indices(item.values(), result)
- self._collect_used_indices(item.keys(), result)
- return result
class ScriptBlockWriter(object):
@@ -105,44 +21,41 @@
_SUITE_KEY = 'suite'
_STRINGS_KEY = 'strings'
- def __init__(self, separator, split_threshold):
+ def __init__(self, separator, split_threshold=9500):
self._separator = separator
self._split_threshold = split_threshold
- def write_to(self, output, model):
+ def write_to(self, output, model, config):
writer = SeparatingWriter(output, self._separator)
writer.write(self._OUTPUT+' = {};\n')
writer.separator()
- for key, value in model._robot_data.items():
- self._write_output_element(model, key, value, writer)
+ self._write_suite(writer, model.suite)
+ writer.separator()
+ self._write_strings(model.strings, writer)
+ writer.separator()
+ for key, value in model.data.items():
+ writer.dump_json(self._output_var(key)+' = ', value)
writer.separator()
- writer.dump_json(self._SETTINGS+' = ', model._settings)
-
- def _write_output_element(self, model ,key, value, writer):
- if key == self._SUITE_KEY:
- splitWriter = SplittingSuiteWriter(writer,
self._split_threshold)
- data, mapping =
splitWriter.write(model._robot_data[self._SUITE_KEY])
- writer.dump_json(self._str_out(self._SUITE_KEY)+' = ', data,
mapping=mapping)
- elif key == self._STRINGS_KEY:
- self._dump_and_split_strings(model, writer)
- else:
- writer.dump_json(self._str_out(key)+' = ', value)
-
- def _str_out(self, key):
+ writer.dump_json(self._SETTINGS+' = ', config)
+
+ def _write_suite(self, writer, suite):
+ splitWriter = SplittingSuiteWriter(writer, self._split_threshold)
+ data, mapping = splitWriter.write(suite)
+ writer.dump_json(self._output_var(self._SUITE_KEY)+' = ', data,
mapping=mapping)
+
+ def _output_var(self, key):
return self._OUTPUT+'["%s"]' % key
- def _dump_and_split_strings(self, model, writer):
- strings = model._robot_data[self._STRINGS_KEY]
- writer.write(self._OUTPUT+'["'+self._STRINGS_KEY+'"] = [];\n')
+ def _write_strings(self, strings, writer):
+ writer.write(self._output_var(self._STRINGS_KEY)+' = [];\n')
while strings:
writer.separator()
- writer.dump_json(self._str_out(self._STRINGS_KEY)
- +' = '+self._str_out(self._STRINGS_KEY)
+ writer.dump_json(self._output_var(self._STRINGS_KEY)
+ +' = '+self._output_var(self._STRINGS_KEY)
+'.concat(',
strings[:self._split_threshold], ');\n')
strings = strings[self._split_threshold:]
-
class SeparatingWriter(object):
def __init__(self, output, separator=''):
=======================================
--- /src/robot/reporting/resultwriter.py Wed Nov 30 06:12:07 2011
+++ /src/robot/reporting/resultwriter.py Thu Dec 1 04:32:24 2011
@@ -12,16 +12,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import os
from robot.errors import DATA_ERROR
from robot.result.builders import ResultFromXML
from robot.result.combiningvisitor import CombiningVisitor,
KeywordRemovingVisitor
from robot.result.datamodel import JSModelCreator
-from robot import utils
from .builders import LogBuilder, ReportBuilder, XUnitBuilder,
OutputBuilder
-from .jsondatamodel import DataModelWriter
class ResultWriter(object):
@@ -37,9 +34,11 @@
if settings.xunit:
XUnitBuilder(result.model).build(settings.xunit)
if settings.log:
- LogBuilder(result.log_model).build(settings.log)
+ LogBuilder(result.js_model).build(settings.log,
+ settings.log_configuration())
if settings.report:
- ReportBuilder(result.report_model).build(settings.report)
+ ReportBuilder(result.report_model).build(settings.report,
+
settings.report_configuration())
return result.return_code
@@ -71,34 +70,15 @@
creator = JSModelCreator(log_path=self._settings.log,
split_log=self._settings.split_log)
self.model.visit(CombiningVisitor(creator,
KeywordRemovingVisitor()))
- self._js_model = DataModelWriter(creator.datamodel,
creator.split_results)
+ self._js_model = creator.datamodel
return self._js_model
@property
def log_model(self):
- self.js_model.set_settings({
- 'title': self._settings['LogTitle'],
- 'reportURL': self._url_from_path(self._settings.log,
self._settings.report),
- 'splitLogBase':
os.path.basename(os.path.splitext(self._settings.log)[0])
- })
return self.js_model
@property
def report_model(self):
- self.js_model.set_settings({
- 'title': self._settings['ReportTitle'],
- 'logURL': self._url_from_path(self._settings.report,
self._settings.log),
- 'background' : self._resolve_background_colors(),
- })
self.js_model.remove_errors()
self.js_model.remove_keywords()
return self.js_model
-
- def _url_from_path(self, source, destination):
- if not destination:
- return None
- return utils.get_link_path(destination, os.path.dirname(source))
-
- def _resolve_background_colors(self):
- colors = self._settings['ReportBackground']
- return {'pass': colors[0], 'nonCriticalFail': colors[1], 'fail':
colors[2]}
=======================================
--- /src/robot/result/datamodel.py Wed Nov 30 04:48:02 2011
+++ /src/robot/result/datamodel.py Thu Dec 1 04:32:24 2011
@@ -30,10 +30,6 @@
self._datamodel = self._build()
return self._datamodel
- @property
- def split_results(self):
- return self._context.split_results
-
@property
def _top(self):
return self._handlers[-1]
=======================================
--- /src/robot/result/jsondatamodelhandlers.py Wed Nov 30 04:48:02 2011
+++ /src/robot/result/jsondatamodelhandlers.py Thu Dec 1 04:32:24 2011
@@ -11,9 +11,11 @@
# 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 time
from robot import utils
from robot.output import LEVELS
+from robot.reporting.parsingcontext import TextIndex
class _Handler(object):
@@ -89,11 +91,81 @@
class ExecutionResultHandler(_Handler):
def build(self, _):
- return {'suite': self._suites[0],
+ return JsExecutionResult(
+ suite=self._suites[0],
+ strings=self._context.dump_texts(),
+ data= {
'stats': self._statistics,
'errors': self._errors,
- 'baseMillis': self._context.basemillis,
- 'strings': self._context.dump_texts()}
+ 'baseMillis': self._context.basemillis
+ },
+ split_results= self._context.split_results
+ )
+
+
+class JsExecutionResult(object):
+
+ def __init__(self, suite, strings, data, split_results=None):
+ self.suite = suite
+ self.strings = strings
+ self.data = data
+ self._set_generated(time.localtime())
+ self.split_results = split_results or []
+
+ def _set_generated(self, timetuple):
+ genMillis = long(time.mktime(timetuple) * 1000) -
self.data['baseMillis']
+ self.data['generatedMillis'] = genMillis
+ self.data['generatedTimestamp'] = utils.format_time(timetuple,
gmtsep=' ')
+
+ def remove_keywords(self):
+ self._remove_keywords_from_suite(self.suite)
+ self._prune_unused_indices()
+
+ def remove_errors(self):
+ self.data.pop('errors')
+
+ def _remove_keywords_from_suite(self, suite):
+ suite[8] = []
+ for subsuite in suite[6]:
+ self._remove_keywords_from_suite(subsuite)
+ for test in suite[7]:
+ test[-1] = []
+
+ def _prune_unused_indices(self):
+ used = self._collect_used_indices(self.suite, set())
+ remap = {}
+ self.strings = \
+ list(self._prune(self.strings, used, remap))
+ self._remap_indices(self.suite, remap)
+
+ def _prune(self, data, used, index_remap, map_index=None,
offset_increment=1):
+ offset = 0
+ for index, text in enumerate(data):
+ index = map_index(index) if map_index else index
+ if index in used:
+ index_remap[index] = index - offset
+ yield text
+ else:
+ offset += offset_increment
+
+ def _remap_indices(self, data, remap):
+ for i, item in enumerate(data):
+ if isinstance(item, TextIndex):
+ data[i] = remap[item]
+ elif isinstance(item, list):
+ self._remap_indices(item, remap)
+
+ def _collect_used_indices(self, data, result):
+ for item in data:
+ if isinstance(item, TextIndex):
+ result.add(item)
+ elif isinstance(item, list):
+ self._collect_used_indices(item, result)
+ elif isinstance(item, dict):
+ self._collect_used_indices(item.values(), result)
+ self._collect_used_indices(item.keys(), result)
+ return result
+
class ErrorsHandler(_Handler):
=======================================
--- /utest/reporting/test_jsondatamodel.py Mon Oct 24 03:12:31 2011
+++ /utest/reporting/test_jsondatamodel.py Thu Dec 1 04:32:24 2011
@@ -1,7 +1,8 @@
from StringIO import StringIO
import unittest
+from robot.result.jsondatamodelhandlers import JsExecutionResult
from robot.utils.asserts import assert_equals, assert_true
-from robot.reporting.jsondatamodel import DataModelWriter
+from robot.reporting.jsondatamodel import ScriptBlockWriter
class TestDataModelWrite(unittest.TestCase):
@@ -11,9 +12,11 @@
assert_true(lines[1].startswith('window.output["'), lines[1])
assert_true(lines[-1].startswith('window.settings ='), lines[-1])
- def _get_lines(self, data=None, separator=None, split_threshold=None):
+ def _get_lines(self, suite=None, strings=None, data=None,
separator=None,
+ split_threshold=None):
output = StringIO()
- DataModelWriter(data or {'baseMillis':100}).write_to(output,
separator=separator, split_threshold=split_threshold)
+ data = JsExecutionResult(suite, strings, data or
{'baseMillis':100})
+ ScriptBlockWriter(separator=separator,
split_threshold=split_threshold).write_to(output, data, {})
return output.getvalue().splitlines()
def test_writing_datamodel_with_separator(self):
@@ -30,14 +33,16 @@
def test_writing_datamodel_with_split_threshold_in_suite(self):
suite = [1, [2, 3], [4, [5], [6, 7]], 8]
- lines = self._get_lines(data={'baseMillis':100, 'suite':suite},
+ lines = self._get_lines(suite=suite,
+ data={'baseMillis':100},
split_threshold=2, separator='foo\n')
parts = filter(lambda l: l.startswith('window.sPart'), lines)
assert_equals(parts, ['window.sPart0 = [2,3];', 'window.sPart1 =
[6,7];', 'window.sPart2 = [4,[5],window.sPart1];', 'window.sPart3 =
[1,window.sPart0,window.sPart2,8];'])
self._assert_separators_in(lines, 'foo')
def test_splitting_output_strings(self):
- lines = self._get_lines(data={'baseMillis':100, 'strings':['data'
for _ in range(100)]},
+ lines = self._get_lines(strings=['data' for _ in range(100)],
+ data={'baseMillis':100},
split_threshold=9, separator='?\n')
parts = [l for l in lines if
l.startswith('window.output["strings')]
assert_equals(len(parts), 13)
=======================================
--- /utest/reporting/test_reporting.py Wed Nov 30 07:38:25 2011
+++ /utest/reporting/test_reporting.py Thu Dec 1 04:32:24 2011
@@ -13,14 +13,14 @@
def set_write_log_mock():
results = {'log_path': None}
- def write_log(self, path, template):
+ def write_log(self, path, *args):
results['log_path'] = path
LogBuilder._write_file = write_log
return results
def set_write_report_mock():
results = {'report_path': None}
- def write_report(self, path, template):
+ def write_report(self, path, *args):
results['report_path'] = path
ReportBuilder._write_file = write_report
return results
=======================================
--- /utest/result/test_jsoning.py Wed Nov 30 15:22:40 2011
+++ /utest/result/test_jsoning.py Thu Dec 1 04:32:24 2011
@@ -262,13 +262,13 @@
self._visitor = JSModelCreator()
self._context = self._visitor._context
result.visit(self._visitor)
- self._verify_message(self.datamodel['errors'][0],
+ self._verify_message(self.datamodel.data['errors'][0],
result.errors.messages[0])
-
assert_equals(self._context.dump_texts()[self.datamodel['errors'][0][3]], '*s1-s1-t1-k1')
- self._verify_suite(self.datamodel['suite'], result.suite)
- assert_equals(self.datamodel['baseMillis'],
self._context.basemillis)
- assert_equals(len(self.datamodel['strings']), 10)
- assert_equals(self.datamodel['stats'],
+
assert_equals(self._context.dump_texts()[self.datamodel.data['errors'][0][3]], '*s1-s1-t1-k1')
+ self._verify_suite(self.datamodel.suite, result.suite)
+ assert_equals(self.datamodel.data['baseMillis'],
self._context.basemillis)
+ assert_equals(len(self.datamodel.strings), 10)
+ assert_equals(self.datamodel.data['stats'],
[[{'fail': 1, 'label': 'Critical Tests', 'pass': 0},
{'fail': 1, 'label': 'All Tests', 'pass': 0}],
[{'pass': 0, 'fail': 1, 'label': 'tagi'}],
==============================================================================
Revision: 20e5edef7799
Author: Mikko Korpela <[email protected]>
Date: Thu Dec 1 04:32:37 2011
Log: Automated merge with https://code.google.com/p/robotframework/
http://code.google.com/p/robotframework/source/detail?r=20e5edef7799
Modified:
/src/robot/result/jsondatamodelhandlers.py
=======================================
--- /src/robot/result/jsondatamodelhandlers.py Thu Dec 1 03:39:28 2011
+++ /src/robot/result/jsondatamodelhandlers.py Thu Dec 1 04:32:37 2011
@@ -11,9 +11,11 @@
# 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 time
from robot import utils
from robot.output import LEVELS
+from robot.reporting.parsingcontext import TextIndex
class _Handler(object):
@@ -89,11 +91,81 @@
class ExecutionResultHandler(_Handler):
def build(self, _):
- return {'suite': self._suites[0],
+ return JsExecutionResult(
+ suite=self._suites[0],
+ strings=self._context.dump_texts(),
+ data= {
'stats': self._statistics,
'errors': self._errors,
- 'baseMillis': self._context.basemillis,
- 'strings': self._context.dump_texts()}
+ 'baseMillis': self._context.basemillis
+ },
+ split_results= self._context.split_results
+ )
+
+
+class JsExecutionResult(object):
+
+ def __init__(self, suite, strings, data, split_results=None):
+ self.suite = suite
+ self.strings = strings
+ self.data = data
+ self._set_generated(time.localtime())
+ self.split_results = split_results or []
+
+ def _set_generated(self, timetuple):
+ genMillis = long(time.mktime(timetuple) * 1000) -
self.data['baseMillis']
+ self.data['generatedMillis'] = genMillis
+ self.data['generatedTimestamp'] = utils.format_time(timetuple,
gmtsep=' ')
+
+ def remove_keywords(self):
+ self._remove_keywords_from_suite(self.suite)
+ self._prune_unused_indices()
+
+ def remove_errors(self):
+ self.data.pop('errors')
+
+ def _remove_keywords_from_suite(self, suite):
+ suite[8] = []
+ for subsuite in suite[6]:
+ self._remove_keywords_from_suite(subsuite)
+ for test in suite[7]:
+ test[-1] = []
+
+ def _prune_unused_indices(self):
+ used = self._collect_used_indices(self.suite, set())
+ remap = {}
+ self.strings = \
+ list(self._prune(self.strings, used, remap))
+ self._remap_indices(self.suite, remap)
+
+ def _prune(self, data, used, index_remap, map_index=None,
offset_increment=1):
+ offset = 0
+ for index, text in enumerate(data):
+ index = map_index(index) if map_index else index
+ if index in used:
+ index_remap[index] = index - offset
+ yield text
+ else:
+ offset += offset_increment
+
+ def _remap_indices(self, data, remap):
+ for i, item in enumerate(data):
+ if isinstance(item, TextIndex):
+ data[i] = remap[item]
+ elif isinstance(item, list):
+ self._remap_indices(item, remap)
+
+ def _collect_used_indices(self, data, result):
+ for item in data:
+ if isinstance(item, TextIndex):
+ result.add(item)
+ elif isinstance(item, list):
+ self._collect_used_indices(item, result)
+ elif isinstance(item, dict):
+ self._collect_used_indices(item.values(), result)
+ self._collect_used_indices(item.keys(), result)
+ return result
+
class ErrorsHandler(_Handler):