Revision: 3301
Author: janne.t.harkonen
Date: Tue May 18 01:10:22 2010
Log: Support for FOR loops, cleanup
http://code.google.com/p/robotframework/source/detail?r=3301

Modified:
 /trunk/src/robot/parsing/populator.py
 /trunk/utest/parsing/test_populator.py

=======================================
--- /trunk/src/robot/parsing/populator.py       Mon May 17 23:24:38 2010
+++ /trunk/src/robot/parsing/populator.py       Tue May 18 01:10:22 2010
@@ -117,6 +117,40 @@
         return UserKeywordPopulator(self._table.add)


+class ForLoopPopulator(Populator):
+    row_continuation_marker = '...'
+
+    def __init__(self, for_loop_creator):
+        self._for_loop_creator = for_loop_creator
+        self._loop = None
+        self._populator = NullPopulator()
+        self._declaration = []
+
+    def add(self, row):
+        dedented_row = row.dedent()
+        if not self._loop:
+            declaration_ready = self._populate_declaration(row)
+            if not declaration_ready:
+                return
+            self._loop = self._for_loop_creator(self._declaration)
+        if not (self._continues(row) or self._continues(dedented_row)):
+            self._populator.populate()
+            self._populator = StepPopulator(self._loop.add_step)
+        self._populator.add(dedented_row)
+
+    def _populate_declaration(self, row):
+        if row.starts_for_loop() or self._continues(row):
+            self._declaration.extend(row.tail())
+            return False
+        return True
+
+    def populate(self):
+        self._populator.populate()
+
+    def _continues(self, row):
+        return row.startswith(self.row_continuation_marker)
+
+
 class _TestCaseUserKeywordPopulator(Populator):
     row_continuation_marker = '...'

@@ -129,23 +163,24 @@
         dedented_row = row.dedent()
         if not self._test_or_uk:
             self._test_or_uk = self._test_or_uk_creator(row.head())
-        if not dedented_row.startswith(self.row_continuation_marker):
+        if not self._continues(dedented_row):
             self._populator.populate()
             self._populator = self._get_populator(dedented_row)
         self._populator.add(dedented_row)

     def populate(self):
-        if self._populator:
-            self._populator.populate()
+        self._populator.populate()

     def _get_populator(self, row):
-        first_cell = row.head()
-        if self._is_setting(first_cell):
-            return SettingPopulator(self._setting_setter(first_cell))
+        if row.starts_test_or_user_keyword_setting():
+            return SettingPopulator(self._setting_setter(row.head()))
+        if row.starts_for_loop():
+            return ForLoopPopulator(self._test_or_uk.add_for_loop)
         return StepPopulator(self._test_or_uk.add_step)

-    def _is_setting(self, cell):
-        return cell and cell[0] == '[' and cell[-1] == ']'
+    def _continues(self, row):
+        return row.startswith(self.row_continuation_marker) or \
+ (isinstance(self._populator, ForLoopPopulator) and row.startswith(''))

     def _setting_setter(self, cell):
         attr_name = self.attrs_by_name[self._setting_name(cell)]
@@ -268,6 +303,9 @@
     def populate(self):
         self._current_populator.populate()

+    def eof(self):
+        self.populate()
+
     def add(self, row):
         data = DataRow(row)
         if data:
@@ -295,6 +333,15 @@
     def startswith(self, value):
         return self.head() == value

+    def starts_for_loop(self):
+        if not self.head().startswith(':'):
+            return False
+        return self.head().replace(':', '').upper().strip() == 'FOR'
+
+    def starts_test_or_user_keyword_setting(self):
+        head = self.head()
+        return head and head[0] == '[' and head[-1] == ']'
+
     def _data_cells(self, row):
         cells = [ self._collapse_whitespace(cell)
                   for cell in self._cells_without_comments(row) ]
=======================================
--- /trunk/utest/parsing/test_populator.py      Mon May 17 23:24:38 2010
+++ /trunk/utest/parsing/test_populator.py      Tue May 18 01:10:22 2010
@@ -87,6 +87,50 @@
         assert_equals(len(self._first_test().steps), 1)
         assert_equals(len(self._nth_test(2).steps), 2)

+    def test_for_loop(self):
+        self._create_table('Test cases', [['For loop test'],
+ ['', ':FOR', '${i}', 'IN', '@{list}'],
+                                          ['', '', 'Log', '${i}']])
+        assert_equals(len(self._first_test().steps), 1)
+        for_loop = self._first_test().steps[0]
+        assert_equals(len(for_loop.steps), 1)
+        assert_true(not for_loop.range)
+        assert_equals(for_loop.vars, ['${i}'])
+        assert_equals(for_loop.values, ['@{list}'])
+
+    def test_in_range_for_loop(self):
+        self._create_table('Test cases', [['For loop test'],
+                                          ['', 'Log', 'Before FOR'],
+ ['', ': for', '${i}', '${j}', 'IN RANGE', '10'],
+                                          ['', '', 'Log', '${i}'],
+                                          ['', '', 'Fail', '${j}'],
+                                          ['', 'Log', 'Outside FOR']])
+        assert_equals(len(self._first_test().steps), 3)
+        for_loop = self._first_test().steps[1]
+        assert_equals(len(for_loop.steps), 2)
+        assert_true(for_loop.range)
+        assert_equals(for_loop.vars, ['${i}', '${j}'])
+
+    def test_malicious_for_loop(self):
+        self._create_table('Test cases', [['Malicious for loop test'],
+                                          ['', 'Log', 'Before FOR'],
+                                          ['#', 'Log', 'Before FOR'],
+ ['', ':::: fOr', '${i}', 'IN', '10', '20'],
+                                          ['#', '...', 'No operation'],
+                                          ['', '...', '30', '40'],
+                                          ['', '...', '50', '60'],
+                                          ['', '', 'Log Many', '${i}'],
+                                          ['', '', '...', '${i}'],
+                                          ['', '...', '${i}'],
+                                          ['', 'Log', 'Outside FOR']])
+        assert_equals(len(self._first_test().steps), 3)
+        for_loop = self._first_test().steps[1]
+        assert_equals(len(for_loop.steps), 1)
+        assert_true(not for_loop.range)
+        assert_equals(for_loop.vars, ['${i}'])
+ assert_equals(for_loop.values, ['10', '20', '30', '40', '50', '60'])
+
+
     def test_test_settings(self):
         doc = 'This is domumentation for the test case'
         self._create_table('Test cases', [['My test name'],
@@ -167,7 +211,7 @@
         self._start_table(name)
         for r  in rows:
             self._populator.add(r)
-        self._populator.populate()
+        self._populator.eof()

     def _nth_test(self, index):
         return self._datafile.testcase_table.tests[index-1]

Reply via email to