2 new revisions:

Revision: 114fe8150b53
Author:   Mikko Korpela <[email protected]>
Date:     Fri Nov  4 06:55:32 2011
Log: WIP: JSON Serializer for the new result model -- based on reporting js...
http://code.google.com/p/robotframework/source/detail?r=114fe8150b53

Revision: 296b06c59e76
Author:   Mikko Korpela <[email protected]>
Date:     Fri Nov  4 06:55:37 2011
Log:      Automated merge with https://robotframework.googlecode.com/hg/
http://code.google.com/p/robotframework/source/detail?r=296b06c59e76

==============================================================================
Revision: 114fe8150b53
Author:   Mikko Korpela <[email protected]>
Date:     Fri Nov  4 06:55:32 2011
Log: WIP: JSON Serializer for the new result model -- based on reporting json model
http://code.google.com/p/robotframework/source/detail?r=114fe8150b53

Added:
 /src/robot/result/datamodel.py
 /src/robot/result/jsondatamodelhandlers.py
Modified:
 /utest/result/test_resultserializer.py

=======================================
--- /dev/null
+++ /src/robot/result/datamodel.py      Fri Nov  4 06:55:32 2011
@@ -0,0 +1,85 @@
+#  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.reporting.parsingcontext import Context
+from robot.result.jsondatamodelhandlers import ExecutionResultHandler, SuiteHandler, KeywordHandler
+
+from robot.result.visitor import Visitor
+
+class ResultVisitor(Visitor):
+
+    def start_statistics(self, statistics):
+        pass
+
+    def start_total_stats(self, total_stats):
+        pass
+
+    def total_stat(self, total_stat):
+        pass
+
+    def end_total_stats(self, total_stats):
+        pass
+
+    def start_tag_stats(self, tag_stats):
+        pass
+
+    def tag_stat(self, tag_stat):
+        pass
+
+    def end_tag_stats(self, tag_stats):
+        pass
+
+    def start_suite_stats(self, suite_stats):
+        pass
+
+    def suite_stat(self, suite_stat):
+        pass
+
+    def end_suite_stats(self, suite_stats):
+        pass
+
+    def end_statistics(self, statistics):
+        pass
+
+    def start_errors(self):
+        pass
+
+    def end_errors(self):
+        pass
+
+
+class DatamodelVisitor(ResultVisitor):
+
+    def __init__(self, result):
+        self._elements = []
+        self._context = Context()
+ self._elements.append(ExecutionResultHandler(self._context, result))
+        result.visit(self)
+
+    def _start(self, item):
+        next = self._elements[-1].start_child_element(item)
+        self._elements.append(next)
+
+    start_suite = start_keyword = start_test = _start
+
+    def _end(self, item):
+        item_datamodel = self._elements.pop().end_element(item)
+        self._elements[-1].add_child_data(item_datamodel)
+    end_suite = end_keyword = end_test = _end
+
+    def visit_message(self, msg):
+        self._elements[-1].message(msg)
+
+    @property
+    def datamodel(self):
+        return self._elements[-1].end_element('')
=======================================
--- /dev/null
+++ /src/robot/result/jsondatamodelhandlers.py  Fri Nov  4 06:55:32 2011
@@ -0,0 +1,226 @@
+#  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
+from robot.output import LEVELS
+from robot.result.model import TestSuite, Keyword, TestCase
+
+
+class _Handler(object):
+
+    def __init__(self, context, attrs=None):
+        self._context = context
+        self._current_children = None
+        self._suites = []
+        self._keywords = []
+        self._tests = []
+        self._data_from_children = []
+
+    def add_child_data(self, data):
+        self._data_from_children.append(data)
+
+    def start_child_element(self, child):
+        if isinstance(child, TestSuite):
+            self._current_children = self._suites
+            return SuiteHandler(self._context, child)
+        if isinstance(child, Keyword):
+            self._current_children = self._keywords
+            return KeywordHandler(self._context, child)
+        if isinstance(child, TestCase):
+            self._current_children = self._tests
+            return TestHandler(self._context, child)
+        raise AssertionError('unknown child type %r' % type(child))
+
+    def message(self, message):
+ self._data_from_children.append(_MsgHandler(self._context, message).end_element(message.message))
+
+    def end_element(self, text):
+        return self._data_from_children
+
+    def _get_id(self, item):
+        return self._context.get_id(item)
+
+    def _get_ids(self, *items):
+        return [self._get_id(i) for i in items]
+
+    def _last_child_passed(self):
+        return self._last_child_status() == 1
+
+    def _last_child_status(self):
+        return self._data_from_children[-1][0]
+
+
+class ExecutionResultHandler(_Handler):
+
+    def __init__(self, context, execution_result):
+        _Handler.__init__(self, context)
+        self._generator = execution_result.generator
+
+    def end_element(self, text):
+        return {'generator': self._generator,
+                'suite': self._data_from_children[0],
+#                'stats': self._data_from_children[1],
+#                'errors': self._data_from_children[2],
+                'baseMillis': self._context.basemillis,
+                'strings': self._context.dump_texts()}
+
+
+class SuiteHandler(_Handler):
+
+    def __init__(self, context, suite):
+        _Handler.__init__(self, context)
+        self._source = suite.source
+        self._name = suite.name
+        self._suites = []
+        self._tests = []
+        self._keywords = []
+        self._current_children = None
+        self._teardown_failed = False
+        self._context.start_suite()
+        self._doc = self._get_id(suite.doc)
+        self._data_from_children.append(self._doc)
+        self._metadata = []
+ for i in [self._get_ids(key, value) for key, value in suite.metadata.items()]:
+            self._metadata.extend(i)
+        self._data_from_children.append(self._metadata)
+
+    def _get_name_and_sources(self):
+        return self._get_ids(self._name, self._source,
+                             self._context.get_rel_log_path(self._source))
+
+    def _set_teardown_failed(self):
+        self._teardown_failed = True
+
+    def add_child_data(self, data):
+        self._current_children.append(data)
+
+    def end_element(self, suite):
+        stats = self._context.end_suite()
+ self._data_from_children.append(_StatusHandler(self._context, suite).end_element(''))
+        return self._get_name_and_sources() + self._data_from_children + \
+                 [self._suites, self._tests, self._keywords,
+                  int(self._teardown_failed), stats]
+
+
+class TestHandler(_Handler):
+
+    def __init__(self, context, test):
+        _Handler.__init__(self, context)
+        self._name = test.name
+        self._timeout = test.timeout
+        self._keywords = []
+        self._current_children = None
+        self._context.start_test()
+        self._critical = int(test.critical == 'yes')
+        self._doc = self._get_id(test.doc)
+        self._data_from_children.append(self._doc)
+        self._status = _StatusHandler(self._context, test).end_element('')
+
+    def add_child_data(self, data):
+        self._current_children.append(data)
+
+    def end_element(self, test):
+ self._data_from_children.append([self._get_id(tag) for tag in test.tags])
+        self._data_from_children.append(self._status)
+        self._context.add_test(self._critical, self._last_child_passed())
+        kws = self._context.end_test(self._keywords)
+        return self._get_ids(self._name, self._timeout, self._critical) + \
+                self._data_from_children + [kws]
+
+
+class KeywordHandler(_Handler):
+    _types = {'kw': 0, 'setup': 1, 'teardown': 2, 'for': 3, 'foritem': 4}
+
+    def __init__(self, context, keyword):
+        _Handler.__init__(self, context)
+        self._type = self._types[keyword.type]
+        self._name = keyword.name
+        self._timeout = keyword.timeout
+        self._keywords = []
+        self._messages = []
+        self._current_children = None
+        self._start()
+
+        self._doc = self._get_id(keyword.doc)
+        self._data_from_children.append(self._doc)
+
+        self._args = self._get_id(', '.join(keyword.args))
+        self._data_from_children.append(self._args)
+
+ self._status = _StatusHandler(self._context, keyword).end_element('')
+
+    def _start(self):
+        self._context.start_keyword()
+
+    def add_child_data(self, data):
+        self._current_children.append(data)
+
+    def message(self, message):
+ self._messages.append(_MsgHandler(self._context, message).end_element(message.message))
+
+    def end_element(self, keyword):
+        self._data_from_children.append(self._status)
+        return self._get_ids(self._type, self._name, self._timeout) + \
+ self._data_from_children + [self._get_keywords(), self._messages]
+
+    def _get_keywords(self):
+        self._context.end_keyword()
+        return self._keywords
+
+
+class _StatusHandler(_Handler):
+
+    _statuses = {'FAIL': 0, 'PASS': 1, 'NOT_RUN': 2}
+
+    def __init__(self, context, item):
+        self._context = context
+        self._status = self._statuses[item.status]
+        self._starttime = self._context.timestamp(item.starttime)
+        self._elapsed = self._calculate_elapsed(item)
+
+    def _calculate_elapsed(self, item):
+        endtime = self._context.timestamp(item.endtime)
+        # Must compare against None because either start and end may be 0.
+        if self._starttime is not None or endtime is not None:
+            return endtime - self._starttime
+        # Only RF 2.6+ outputs have elapsedtime when start or end is N/A.
+        return int(item.elapsed)
+
+    def end_element(self, text):
+        result = [self._status, self._starttime, self._elapsed]
+        if text:
+            result.append(text)
+        return self._get_ids(*result)
+
+
+class _MsgHandler(_Handler):
+
+    def __init__(self, context, message):
+        _Handler.__init__(self, context)
+        self._msg = [self._context.timestamp(message.timestamp),
+                     LEVELS[message.level]]
+        self._is_html = message.html
+        self._is_linkable_in_error_table = message.linkable
+        self._is_warning = message.level == 'WARN'
+
+    def end_element(self, text):
+ self._msg.append(text if self._is_html else utils.html_escape(text))
+        self._handle_warning_linking()
+        return self._get_ids(*self._msg)
+
+    def _handle_warning_linking(self):
+        if self._is_linkable_in_error_table:
+            self._msg.append(self._context.link_to(self._msg))
+        elif self._is_warning:
+            self._context.create_link_to_current_location(self._msg)
=======================================
--- /utest/result/test_resultserializer.py      Fri Nov  4 02:20:11 2011
+++ /utest/result/test_resultserializer.py      Fri Nov  4 06:55:32 2011
@@ -3,8 +3,10 @@
 from StringIO import StringIO
 from xml.etree.ElementTree import XML
 from xml.etree.ElementTree import tostring
+from robot.reporting.outputparser import OutputParser

 from robot.result.builders import ResultFromXML
+from robot.result.datamodel import DatamodelVisitor
 from robot.result.serializer import ResultSerializer
 from robot.utils.asserts import assert_equals

@@ -34,5 +36,31 @@
         self._assert_xml_content(self._xml_lines(output.getvalue()),
                                  self._xml_lines(GOLDEN_XML_TWICE))

+class TestResultJSONSerializer(unittest.TestCase):
+
+    def setUp(self):
+        output_parser = OutputParser()
+        output_parser._parse_fileobj(StringIO(GOLDEN_XML))
+        self._expected = output_parser._get_data_model()._robot_data
+        visitor = DatamodelVisitor(ResultFromXML(StringIO(GOLDEN_XML)))
+        self._datamodel = visitor.datamodel
+
+    def test_datamodel_suite(self):
+        self._equals('suite')
+
+    def test_datamodel_basemillis(self):
+        self._equals('baseMillis')
+
+    def test_datamodel_strings(self):
+        self._equals('strings')
+
+    def _equals(self, key):
+        if isinstance(self._expected[key], list):
+            for exp, act in zip(self._expected[key], self._datamodel[key]):
+                assert_equals(exp, act)
+        else:
+            assert_equals(self._expected[key], self._datamodel[key])
+
+
 if __name__ == '__main__':
     unittest.main()

==============================================================================
Revision: 296b06c59e76
Author:   Mikko Korpela <[email protected]>
Date:     Fri Nov  4 06:55:37 2011
Log:      Automated merge with https://robotframework.googlecode.com/hg/
http://code.google.com/p/robotframework/source/detail?r=296b06c59e76


Reply via email to