2 new revisions:

Revision: 62d08391b1be
Author:   Pekka Klärck
Date:     Sun Dec 18 14:26:45 2011
Log: StringCache: No need to keep count on an index when it is the same as ...
http://code.google.com/p/robotframework/source/detail?r=62d08391b1be

Revision: 222743395354
Author:   Pekka Klärck
Date:     Sun Dec 18 16:32:16 2011
Log: Result writing: 1) Nuked builders and moved logging to resultwriter. 2...
http://code.google.com/p/robotframework/source/detail?r=222743395354

==============================================================================
Revision: 62d08391b1be
Author:   Pekka Klärck
Date:     Sun Dec 18 14:26:45 2011
Log: StringCache: No need to keep count on an index when it is the same as size of the cache. Verified using timeit that this doesn't accect performance at all.
http://code.google.com/p/robotframework/source/detail?r=62d08391b1be

Modified:
 /src/robot/reporting/stringcache.py

=======================================
--- /src/robot/reporting/stringcache.py Sun Dec 18 03:09:57 2011
+++ /src/robot/reporting/stringcache.py Sun Dec 18 14:26:45 2011
@@ -34,15 +34,13 @@

     def __init__(self):
         self._cache = {'*': self._zero_index}
-        self._index = 1

     def add(self, text):
         if not text:
             return self._zero_index
         text = self._encode(text)
         if text not in self._cache:
-            self._cache[text] = StringIndex(self._index)
-            self._index += 1
+            self._cache[text] = StringIndex(len(self._cache))
         return self._cache[text]

     def _encode(self, text):

==============================================================================
Revision: 222743395354
Author:   Pekka Klärck
Date:     Sun Dec 18 16:32:16 2011
Log: Result writing: 1) Nuked builders and moved logging to resultwriter. 2) General cleanup. 3) Use -1 as RC (not DATA_ERROR i.e. 252) when no outputs are created and raise exception if that happens with rebot (that results to 252 RC in the end).
http://code.google.com/p/robotframework/source/detail?r=222743395354

Deleted:
 /src/robot/reporting/builders.py
Modified:
 /atest/robot/cli/rebot/status_rc.txt
 /src/robot/__init__.py
 /src/robot/reporting/resultwriter.py
 /utest/reporting/test_reporting.py

=======================================
--- /src/robot/reporting/builders.py    Sun Dec 18 02:58:17 2011
+++ /dev/null
@@ -1,86 +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 __future__ import with_statement
-
-
-from robot.errors import DataError
-from robot.output import LOGGER
-from robot.result.outputwriter import OutputWriter
-
-from .xunitwriter import XUnitWriter
-from .logreportwriters import LogWriter, ReportWriter
-
-
-class OutputBuilder(object):
-
-    def __init__(self, model):
-        self._model = model
-
-    def build(self, path):
-        try:
-            writer = OutputWriter(path)
-        except DataError, err:
-            LOGGER.error(unicode(err))
-        else:
-            self._model.visit(writer)
-            LOGGER.output_file('Output', path)
-
-
-class XUnitBuilder(object):
-
-    def __init__(self, model):
-        self._model = model
-
-    def build(self, path):
-        try:
-            writer = XUnitWriter(path)
-        except EnvironmentError, err:
-            LOGGER.error("Opening XUnit result file '%s' failed: %s"
-                         % (path, err.strerror))
-        else:
-            self._model.visit(writer)
-            LOGGER.output_file('XUnit', path)
-
-
-
-class LogBuilder(object):
-
-    def __init__(self, js_model):
-        self._js_model = js_model
-
-    def build(self, path, config):
-        try:
-            LogWriter(self._js_model).write(path, config)
-        except EnvironmentError, err:
- # Cannot use err.filename due to http://bugs.jython.org/issue1825 - # and thus error has wrong file name if writing split log fails. - LOGGER.error("Writing log file '%s' failed: %s" % (path, err.strerror))
-        else:
-            LOGGER.output_file('Log', path)
-
-
-
-class ReportBuilder(object):
-
-    def __init__(self, js_model):
-        self._js_model = js_model
-
-    def build(self, path, config):
-        try:
-            ReportWriter(self._js_model).write(path, config)
-        except EnvironmentError, err:
- LOGGER.error("Writing report file '%s' failed: %s" % (path, err.strerror))
-        else:
-            LOGGER.output_file('Report', path)
=======================================
--- /atest/robot/cli/rebot/status_rc.txt        Wed Nov 30 06:12:07 2011
+++ /atest/robot/cli/rebot/status_rc.txt        Sun Dec 18 16:32:16 2011
@@ -12,6 +12,7 @@
 ${PASSING TESTS}   ${MISCDIR}/normal.html
 ${FAILING TESTS}   ${MISCDIR}/pass_and_fail.html
 ${REPORT}          ${TEMPDIR}${/}robot-testing-report.html
+${NO OUTPUTS} [ ERROR ] No outputs created.\n\nTry --help for usage information.

 *** Test Cases ***

@@ -30,9 +31,9 @@
 Zero RC when critical tests fail with --NoStatusRC
     --nostatusrc ${FAILING}       rc=0

-DATA_ERROR (252) when no output is created
-    ${PASSING}                    rc=252    report=NONE
-    --nostatusrc ${FAILING}       rc=252    report=NONE
+Error when no output is created
+ ${PASSING} rc=252 output=${NO OUTPUTS} report=NONE + --nostatusrc ${FAILING} rc=252 output=${NO OUTPUTS} report=NONE


 *** Keywords ***
@@ -47,7 +48,9 @@
     Remove Files  ${PASSING}  ${FAILING}

 Run Rebot and Verify RC
-    [Arguments]  ${options & source}  ${rc}=  ${report}=${REPORT}
- ${returned} ${output} = Run And Return RC And Output ${REBOT} --log NONE --report ${report} ${options & source}
-    Run Keyword If  ${rc} != ${returned}  Log  ${output}
-    Should Be Equal As Integers  ${returned}  ${rc}
+ [Arguments] ${options & source} ${rc}= ${output}= ${report}=${REPORT}
+    ${returned rc}  ${returned output} =  Run And Return RC And Output
+    ...  ${REBOT} --log NONE --report ${report} ${options & source}
+    Run Keyword If  ${rc} != ${returned rc}  Log  ${output}
+    Should Be Equal As Integers  ${returned rc}  ${rc}
+ Run Keyword If """${output}""" Should Be Equal ${returned output} ${output}
=======================================
--- /src/robot/__init__.py      Fri Dec  2 03:27:16 2011
+++ /src/robot/__init__.py      Sun Dec 18 16:32:16 2011
@@ -130,7 +130,7 @@
     output.close(suite)
     if settings.is_rebot_needed():
         output, settings = settings.get_rebot_datasource_and_settings()
-        ResultWriter(settings, output).write_results()
+        ResultWriter(output).write_results(settings)
     LOGGER.close()
     return suite.return_code

@@ -153,7 +153,9 @@
     settings = RebotSettings(options)
     LOGGER.register_console_logger(colors=settings['MonitorColors'])
     LOGGER.disable_message_cache()
-    rc = ResultWriter(settings, *datasources).write_results()
+    rc = ResultWriter(*datasources).write_results(settings)
+    if rc < 0:
+        raise DataError('No outputs created.')
     LOGGER.close()
     return rc

=======================================
--- /src/robot/reporting/resultwriter.py        Wed Dec 14 00:37:51 2011
+++ /src/robot/reporting/resultwriter.py        Sun Dec 18 16:32:16 2011
@@ -12,70 +12,97 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.

-from robot.errors import DATA_ERROR
-from robot.reporting.jsmodelbuilders import JsModelBuilder
+from robot.errors import DataError
+from robot.output import LOGGER
 from robot.result import ResultFromXml

-from .builders import LogBuilder, ReportBuilder, XUnitBuilder, OutputBuilder
+# TODO: OutputWriter belongs into robot.reporting
+from robot.result.outputwriter import OutputWriter
+
+from .jsmodelbuilders import JsModelBuilder
+from .logreportwriters import LogWriter, ReportWriter
+from .xunitwriter import XUnitWriter


 class ResultWriter(object):

-    def __init__(self, settings, *data_sources):
-        self._settings = settings
-        self._result = Result(settings, data_sources)
-
-    def write_results(self):
-        settings = self._settings
-        self._write_output(settings.output)
-        self._write_xunit(settings.xunit)
-        self._write_log(settings.log, settings.log_config)
-        self._write_report(settings.report, settings.report_config)
-        return self._result.return_code
-
-    def _write_output(self, output):
-        if output:
-            OutputBuilder(self._result.model).build(output)
-
-    def _write_xunit(self, xunit):
-        if xunit:
-            XUnitBuilder(self._result.model).build(xunit)
-
-    def _write_log(self, log, config):
-        if log:
-            LogBuilder(self._result.js_model).build(log, config)
-
-    def _write_report(self, report, config):
-        if report:
-            self._result.js_model.remove_data_not_needed_in_report()
-            ReportBuilder(self._result.js_model).build(report, config)
+    def __init__(self, *data_sources):
+        self._data_sources = data_sources
+
+    def write_results(self, settings, results=None):
+        results = results or Results(self._data_sources, settings)
+        if settings.output:
+            self._write_output(results.result, settings.output)
+        if settings.xunit:
+            self._write_xunit(results.result, settings.xunit)
+        if settings.log:
+ self._write_log(results.js_result, settings.log, settings.log_config)
+        if settings.report:
+            results.js_result.remove_data_not_needed_in_report()
+ self._write_report(results.js_result, settings.report, settings.report_config)
+        return results.return_code
+
+    def _write_output(self, result, path):
+        try:
+            result.visit(OutputWriter(path))
+        except DataError, err:
+            LOGGER.error(unicode(err))
+        else:
+            LOGGER.output_file('Output', path)
+
+    def _write_xunit(self, result, path):
+        try:
+            result.visit(XUnitWriter(path))
+        except EnvironmentError, err:
+            LOGGER.error("Opening XUnit result file '%s' failed: %s"
+                         % (path, err.strerror))
+        else:
+            LOGGER.output_file('XUnit', path)
+
+    def _write_log(self, js_result, path, config):
+        try:
+            LogWriter(js_result).write(path, config)
+        except EnvironmentError, err:
+ # Cannot use err.filename due to http://bugs.jython.org/issue1825 + # and thus error has wrong file name if writing split log fails. + LOGGER.error("Writing log file '%s' failed: %s" % (path, err.strerror))
+        else:
+            LOGGER.output_file('Log', path)
+
+    def _write_report(self, js_result, path, config):
+        try:
+            ReportWriter(js_result).write(path, config)
+        except EnvironmentError, err:
+ LOGGER.error("Writing report file '%s' failed: %s" % (path, err.strerror))
+        else:
+            LOGGER.output_file('Report', path)


-class Result(object):
-
-    def __init__(self, settings, data_sources):
-        self._settings = settings
+class Results(object):
+
+    def __init__(self, data_sources, settings):
         self._data_sources = data_sources
-        self._model = None
-        self._js_model = None
-        self.return_code = DATA_ERROR
+        self._settings = settings
+        self._result = None
+        self._js_result = None
+        self.return_code = -1

     @property
-    def model(self):
-        if self._model is None:
-            self._model = ResultFromXml(*self._data_sources)
-            self._model.configure(self._settings.status_rc,
-                                  self._settings.suite_config,
-                                  self._settings.statistics_config)
-            self.return_code = self._model.return_code
-        return self._model
+    def result(self):
+        if self._result is None:
+            self._result = ResultFromXml(*self._data_sources)
+            self._result.configure(self._settings.status_rc,
+                                   self._settings.suite_config,
+                                   self._settings.statistics_config)
+            self.return_code = self._result.return_code
+        return self._result

     @property
-    def js_model(self):
-        if self._js_model is None:
+    def js_result(self):
+        if self._js_result is None:
             builder = JsModelBuilder(log_path=self._settings.log,
                                      split_log=self._settings.split_log,
                                      prune_input_to_save_memory=True)
-            self._js_model = builder.build_from(self.model)
-            self._model = None
-        return self._js_model
+            self._js_result = builder.build_from(self.result)
+            self._result = None
+        return self._js_result
=======================================
--- /utest/reporting/test_reporting.py  Wed Dec  7 10:52:24 2011
+++ /utest/reporting/test_reporting.py  Sun Dec 18 16:32:16 2011
@@ -1,173 +1,179 @@
 from StringIO import StringIO
 import os
 import unittest
-from robot.reporting.resultwriter import ResultWriter, Result
+from robot.reporting.resultwriter import ResultWriter, Results
 from robot.output import LOGGER

 from robot.result.executionresult import ExecutionResult
+from robot.result.executionerrors import ExecutionErrors
 from robot.result.testsuite import TestSuite
 from robot.utils.asserts import assert_true, assert_equals


 LOGGER.disable_automatic_console_logger()

-class TestReporting(unittest.TestCase):
-
+
+class TestReporting(unittest.TestCase):
     EXPECTED_SUITE_NAME = 'My Suite Name'
     EXPECTED_TEST_NAME  = 'My Test Name'
     EXPECTED_KEYWORD_NAME = 'My Keyword Name'
     EXPECTED_FAILING_TEST = 'My Failing Test'
     EXPECTED_DEBUG_MESSAGE = '1111DEBUG777'
-
-    def setUp(self):
-        self._settings = lambda:0
-        self._settings.log = None
-        self._settings.log_config = None
-        self._settings.split_log = False
-        self._settings.report = None
-        self._settings.report_config = None
-        self._settings.output = None
-        self._settings.xunit = None
-        self._settings.status_rc = True
-        self._settings.suite_config = {}
-        self._settings.statistics_config = {}
-        self._create_suite_and_writer()
-
-    def _create_suite_and_writer(self):
-        self._root_suite = TestSuite(name=self.EXPECTED_SUITE_NAME)
-        self._root_suite.tests.create(name=self.EXPECTED_TEST_NAME).\
-                    keywords.create(name=self.EXPECTED_KEYWORD_NAME,
-                                    status='PASS')
-        self._root_suite.tests.create(name=self.EXPECTED_FAILING_TEST).\
-                    keywords.create(name=self.EXPECTED_KEYWORD_NAME).\
- messages.create(message=self.EXPECTED_DEBUG_MESSAGE,
-                                        level='DEBUG',
-                                        timestamp='20201212 12:12:12.000')
-        self._writer = ResultWriter(self._settings)
-        self._writer._result._model = ExecutionResult(self._root_suite)
-
-    def test_generate_report_and_log(self):
-        self._settings.log = ClosableOutput('log.html')
-        self._settings.report = ClosableOutput('report.html')
-        self._write_results()
-        self._verify_log()
-        self._verify_report()
-
-    def _write_results(self):
-        self._writer.write_results()
-
-    def _verify_log(self):
-        log = self._settings.log.getvalue()
-        assert_true(self.EXPECTED_KEYWORD_NAME in log)
-        assert_true(self.EXPECTED_SUITE_NAME in log)
-        assert_true(self.EXPECTED_TEST_NAME in log)
-        assert_true(self.EXPECTED_FAILING_TEST in log)
-
-    def _verify_report(self):
-        report = self._settings.report.getvalue()
-        assert_true(self.EXPECTED_KEYWORD_NAME not in report)
-        assert_true(self.EXPECTED_SUITE_NAME in report)
-        assert_true(self.EXPECTED_TEST_NAME in report)
-        assert_true(self.EXPECTED_FAILING_TEST in report)
-
-    def test_no_generation(self):
-        self._writer._result._model = None
-        self._write_results()
-        assert_equals(self._writer._result._model, None)
-
-    def test_only_log(self):
-        self._settings.log = ClosableOutput('log.html')
-        self._write_results()
-        self._verify_log()
-
-    def test_only_report(self):
-        self._settings.report = ClosableOutput('report.html')
-        self._write_results()
-        self._verify_report()
-
-    def test_only_xunit(self):
-        self._settings.xunit = ClosableOutput('xunit.xml')
-        self._write_results()
-        self._verify_xunit()
-
-    def test_only_output_generation(self):
-        self._settings.output = ClosableOutput('output.xml')
-        self._write_results()
-        self._verify_output()
-
-    def test_generate_all(self):
-        self._settings.log = ClosableOutput('l.html')
-        self._settings.report = ClosableOutput('r.html')
-        self._settings.xunit = ClosableOutput('x.xml')
-        self._settings.output = ClosableOutput('o.xml')
-        self._write_results()
-        self._verify_log()
-        self._verify_report()
-        self._verify_xunit()
-        self._verify_output()
-
-    def test_log_generation_removes_keywords_from_original_model(self):
-        self._settings.log = ClosableOutput('log.html')
-        self._write_results()
-        for test in self._root_suite.tests:
-            assert_equals(len(test.keywords), 0)
-
-    def _verify_xunit(self):
-        xunit = self._settings.xunit.getvalue()
-        assert_true(self.EXPECTED_DEBUG_MESSAGE in xunit)
-
-    def _verify_output(self):
-        assert_true(self._settings.output.getvalue())
-
-
-if os.name == 'java':
-    import java.io.OutputStream
-    import java.lang.String
-
-    class ClosableOutput(java.io.OutputStream):
-        def __init__(self, path):
-            self._output = StringIO()
-            self._path = path
-
-        __enter__ = lambda *args: 0
-        __exit__ = lambda self, *args: self.close()
-
-        def write(self, *args):
-            self._output.write(java.lang.String(args[0]))
-
-        def close(self):
-            self.value = self._output.getvalue()
-            self._output.close()
-
-        def getvalue(self):
-            return self.value
-
-        def __str__(self):
-            return self._path
-
-else:
-
-    class ClosableOutput(object):
-
-        def __init__(self, path):
-            self._output = StringIO()
-            self._path = path
-
-        __enter__= lambda *args: 0
-        __exit__ = lambda self, *args: self.close()
-
-        def write(self, data):
-            self._output.write(data)
-
-        def close(self):
-            self.value = self._output.getvalue()
-            self._output.close()
-
-        def getvalue(self):
-            return self.value
-
-        def __str__(self):
-            return self._path
+    EXPECTED_ERROR_MESSAGE = 'ERROR M355463'
+
+    def test_no_generation(self):
+        settings = StubSettings()
+        results = StubResults(None, settings)
+        rc = ResultWriter().write_results(settings, results)
+        assert_equals(rc, -1)
+
+    def test_only_output(self):
+        output = ClosableOutput('output.xml')
+        self._write_results(output=output)
+        self._verify_output(output.value)
+
+    def test_only_xunit(self):
+        xunit = ClosableOutput('xunit.xml')
+        self._write_results(xunit=xunit)
+        self._verify_xunit(xunit.value)
+
+    def test_only_log(self):
+        log = ClosableOutput('log.html')
+        self._write_results(log=log)
+        self._verify_log(log.value)
+
+    def test_only_report(self):
+        report = ClosableOutput('report.html')
+        self._write_results(report=report)
+        self._verify_report(report.value)
+
+    def test_log_and_report(self):
+        log = ClosableOutput('log.html')
+        report = ClosableOutput('report.html')
+        self._write_results(log=log, report=report)
+        self._verify_log(log.value)
+        self._verify_report(report.value)
+
+    def test_generate_all(self):
+        output = ClosableOutput('o.xml')
+        xunit = ClosableOutput('x.xml')
+        log = ClosableOutput('l.html')
+        report = ClosableOutput('r.html')
+ self._write_results(output=output, xunit=xunit, log=log, report=report)
+        self._verify_output(output.value)
+        self._verify_xunit(xunit.value)
+        self._verify_log(log.value)
+        self._verify_report(report.value)
+
+    def test_log_generation_removes_keywords_from_execution_result(self):
+        self._write_results(log=ClosableOutput('log.html'))
+        for test in self.execution_result.suite.tests:
+            assert_equals(len(test.keywords), 0)
+
+    def _write_results(self, **settings):
+        self.execution_result = self._get_execution_result()
+        settings = StubSettings(**settings)
+        results = StubResults(self.execution_result, settings)
+        rc = ResultWriter().write_results(settings, results)
+        assert_equals(rc, 1)
+
+    def _get_execution_result(self):
+        suite = TestSuite(name=self.EXPECTED_SUITE_NAME)
+ tc = suite.tests.create(name=self.EXPECTED_TEST_NAME, status='PASS')
+        tc.keywords.create(name=self.EXPECTED_KEYWORD_NAME, status='PASS')
+        tc = suite.tests.create(name=self.EXPECTED_FAILING_TEST)
+        kw = tc.keywords.create(name=self.EXPECTED_KEYWORD_NAME)
+        kw.messages.create(message=self.EXPECTED_DEBUG_MESSAGE,
+ level='DEBUG', timestamp='20201212 12:12:12.000')
+        errors = ExecutionErrors()
+        errors.messages.create(message=self.EXPECTED_ERROR_MESSAGE,
+ level='ERROR', timestamp='20201212 12:12:12.000')
+        return ExecutionResult(suite, errors)
+
+    def _verify_output(self, content):
+        assert_true(self.EXPECTED_SUITE_NAME in content)
+        assert_true(self.EXPECTED_TEST_NAME in content)
+        assert_true(self.EXPECTED_FAILING_TEST in content)
+        assert_true(self.EXPECTED_KEYWORD_NAME in content)
+        assert_true(self.EXPECTED_DEBUG_MESSAGE in content)
+        assert_true(self.EXPECTED_ERROR_MESSAGE in content)
+
+    def _verify_xunit(self, content):
+        assert_true(self.EXPECTED_SUITE_NAME in content)
+        assert_true(self.EXPECTED_TEST_NAME in content)
+        assert_true(self.EXPECTED_FAILING_TEST in content)
+        assert_true(self.EXPECTED_KEYWORD_NAME not in content)
+        assert_true(self.EXPECTED_DEBUG_MESSAGE in content)
+        assert_true(self.EXPECTED_ERROR_MESSAGE not in content)
+
+    def _verify_log(self, content):
+        self._verify_output(content)
+
+    def _verify_report(self, content):
+        assert_true(self.EXPECTED_SUITE_NAME in content)
+        assert_true(self.EXPECTED_TEST_NAME in content)
+        assert_true(self.EXPECTED_FAILING_TEST in content)
+        assert_true(self.EXPECTED_KEYWORD_NAME not in content)
+        assert_true(self.EXPECTED_DEBUG_MESSAGE not in content)
+        assert_true(self.EXPECTED_ERROR_MESSAGE not in content)
+
+
+class StubSettings(object):
+    log = None
+    log_config = None
+    split_log = False
+    report = None
+    report_config = None
+    output = None
+    xunit = None
+    status_rc = True
+    suite_config = {}
+    statistics_config = {}
+
+    def __init__(self, **settings):
+        self.__dict__.update(settings)
+
+
+class StubResults(Results):
+
+    def __init__(self, result, settings):
+        Results.__init__(self, None, settings)
+        self._result = result
+        if result:
+            self.return_code = result.return_code
+
+
+class ClosableOutput(object):
+
+    def __init__(self, path):
+        self._output = StringIO()
+        self._path = path
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, *args):
+        self.close()
+
+    def write(self, data):
+        self._output.write(data)
+
+    def close(self):
+        self.value = self._output.getvalue()
+        self._output.close()
+
+    def __str__(self):
+        return self._path
+
+
+if os.name == 'java':
+    from java.io import OutputStream
+    from java.lang import String
+
+    class ClosableOutput(ClosableOutput, OutputStream):
+
+        def write(self, *args):
+            self._output.write(String(args[0]))


 if __name__ == '__main__':

Reply via email to