Revision: d2930be57486
Author:   Janne Härkönen <[email protected]>
Date:     Fri May  6 04:52:43 2011
Log:      Implemented keyword teardown functionality

Update issue 711
Owner: janne.t.harkonen
Cc: pekka.klarck
Still need to add tests for dry run and update user guide.
http://code.google.com/p/robotframework/source/detail?r=d2930be57486

Modified:
 /src/robot/parsing/model.py
 /src/robot/running/context.py
 /src/robot/running/fixture.py
 /src/robot/running/runerrors.py
 /src/robot/running/userkeyword.py
 /utest/parsing/test_model.py

=======================================
--- /src/robot/parsing/model.py Fri Apr 15 14:27:57 2011
+++ /src/robot/parsing/model.py Fri May  6 04:52:43 2011
@@ -464,7 +464,7 @@
         self.parent.report_invalid_syntax(message, level)

     def __iter__(self):
-        for element in [self.doc, self.tags, self.setup,
+        for element in [self.doc, self.tags, self.setup,
                         self.template, self.timeout] \
                         + self.steps + [self.teardown]:
             yield element
@@ -479,17 +479,19 @@
         self.args = Arguments('[Arguments]', self)
         self.return_ = Return('[Return]', self)
         self.timeout = Timeout('[Timeout]', self)
+        self.teardown = Fixture('[Teardown]', self)
         self.steps = []

     _setters = {'documentation': lambda s: s.doc.populate,
                 'document': lambda s: s.doc.populate,
                 'arguments': lambda s: s.args.populate,
                 'return': lambda s: s.return_.populate,
-                'timeout': lambda s: s.timeout.populate}
+                'timeout': lambda s: s.timeout.populate,
+                'teardown': lambda s: s.teardown.populate}

     def __iter__(self):
         for element in [self.args, self.doc, self.timeout] \
-                        + self.steps + [self.return_]:
+                        + self.steps + [self.teardown, self.return_]:
             yield element


=======================================
--- /src/robot/running/context.py       Sun Feb  6 01:24:10 2011
+++ /src/robot/running/context.py       Fri May  6 04:52:43 2011
@@ -21,12 +21,22 @@
         self.namespace = namespace
         self.output = output
         self.dry_run = dry_run
+        self._in_teardown = False

     @property
     def teardown(self):
+        if self._in_teardown:
+            return True
+        # TODO: tests and suites should also call start/end_teardown()
         test_or_suite = self.namespace.test or self.namespace.suite
         return test_or_suite.status != 'RUNNING'

+    def start_teardown(self):
+        self._in_teardown = True
+
+    def end_teardown(self):
+        self._in_teardown = False
+
     def get_current_vars(self):
         return self.namespace.variables

=======================================
--- /src/robot/running/fixture.py       Sun Feb  6 01:24:10 2011
+++ /src/robot/running/fixture.py       Fri May  6 04:52:43 2011
@@ -83,4 +83,11 @@

 class TestTeardownListener(_TestListener):
     def _notify_run_errors(self, error):
-        self._test.run_errors.teardown_err(unicode(error))
+        self._test.run_errors.teardown_err(error)
+
+
+class KeywordTeardownListener(object):
+    def __init__(self, run_errors):
+        self._run_errors = run_errors
+    def notify(self, error):
+        self._run_errors.teardown_err(error)
=======================================
--- /src/robot/running/runerrors.py     Sun Feb  6 01:24:10 2011
+++ /src/robot/running/runerrors.py     Fri May  6 04:52:43 2011
@@ -156,9 +156,31 @@
         return self._kw_err

     def get_teardown_message(self, message):
+        # TODO: This API is really in need of cleanup
         if message == '':
             return 'Teardown failed:\n%s' % self._teardown_err
return '%s\n\nAlso teardown failed:\n%s' % (message, self._teardown_err)

     def parent_or_init_error(self):
         return self._parent_err or self._init_err
+
+
+class KeywordRunErrors(object):
+
+    def __init__(self):
+        self._kw_err = ''
+        self._teardown_err = ''
+
+    def get_message(self):
+        if not self._teardown_err:
+            return self._kw_err
+        if not self._kw_err:
+            return 'Keyword teardown failed:\n%s' % self._teardown_err
+        return '%s\n\nAlso keyword teardown failed:\n%s' % (self._kw_err,
+ self._teardown_err)
+
+    def kw_err(self, error):
+        self._kw_err = unicode(error)
+
+    def teardown_err(self, err):
+        self._teardown_err = unicode(err)
=======================================
--- /src/robot/running/userkeyword.py   Sun Feb  6 01:24:10 2011
+++ /src/robot/running/userkeyword.py   Fri May  6 04:52:43 2011
@@ -16,13 +16,15 @@
 import re

 from robot.common import BaseLibrary, UserErrorHandler
-from robot.errors import DataError
+from robot.errors import DataError, ExecutionFailed
 from robot.variables import is_list_var, VariableSplitter
 from robot import utils

 from keywords import Keywords
+from fixture import Teardown, KeywordTeardownListener
 from timeouts import KeywordTimeout
 from arguments import UserKeywordArguments
+from runerrors import  KeywordRunErrors


 class UserLibrary(BaseLibrary):
@@ -98,6 +100,7 @@
         self.name = keyword.name
         self.keywords = Keywords(keyword.steps)
         self.return_value = keyword.return_.value
+        self.teardown = keyword.teardown
         self._libname = libname
         self.doc = self._doc = keyword.doc.value
         self._timeout = keyword.timeout
@@ -146,7 +149,22 @@
args_spec.set_variables(resolved_arguments, variables, context.output)
         self._verify_keyword_is_valid()
         self.timeout.start()
-        self.keywords.run(context)
+        run_errors = KeywordRunErrors()
+        try:
+            self.keywords.run(context)
+        except ExecutionFailed, err:
+            run_errors.kw_err(err)
+        self._run_teardown(context, run_errors)
+        msg = run_errors.get_message()
+        if msg:
+            raise ExecutionFailed(msg)
+
+    def _run_teardown(self, context, run_errors):
+        teardown = Teardown(self.teardown.name, self.teardown.args)
+        teardown.replace_variables(context.get_current_vars(), [])
+        context.start_teardown()
+        teardown.run(context, KeywordTeardownListener(run_errors))
+        context.end_teardown()

     def _verify_keyword_is_valid(self):
         if self._errors:
=======================================
--- /utest/parsing/test_model.py        Thu Jan 27 07:26:13 2011
+++ /utest/parsing/test_model.py        Fri May  6 04:52:43 2011
@@ -109,7 +109,7 @@
self._verify_import(self.table.add_variables('./v2.py', ['a1', 'a2']),
                             './v2.py', ['a1', 'a2'])
self._verify_import(self.table.add_library('N2', ['1', '2', '3', '4']),
-                            'N2', ['1', '2', '3', '4'])
+                            'N2', ['1', '2', '3', '4'])
         assert_equal(len(self.table.imports), 5)
assert_true(all(isinstance(im, _Import) for im in self.table.imports))

@@ -160,7 +160,7 @@
         self.table.add('not var', 'the value')
         assert_equal(self.table.variables[0].name, 'not var')
         assert_equal(self.table.variables[0].value, ['the value'])
-
+

 class TestTestCaseTable(unittest.TestCase):

@@ -221,6 +221,7 @@
         assert_true(isinstance(self.kw.args, Arguments))
         assert_true(isinstance(self.kw.return_, Return))
         assert_true(isinstance(self.kw.timeout, Timeout))
+        assert_true(isinstance(self.kw.teardown, Fixture))

     def test_set_settings(self):
         self.kw.doc.populate('My coooool doc')
@@ -307,7 +308,7 @@

     def test_in_range(self):
self._test(['${i}', 'IN RANGE', '100'], ['${i}'], ['100'], range=True)
-        self._test(['what', 'ever', 'in range', 'IN', 'whatever'],
+        self._test(['what', 'ever', 'in range', 'IN', 'whatever'],
                    ['what', 'ever'], ['IN', 'whatever'], range=True)

     def test_representation(self):

Reply via email to