Index: relatorio/tests/test_odt.py
===================================================================
--- relatorio/tests/test_odt.py (revision 99:1efd21aa821f)
+++ relatorio/tests/test_odt.py (revision 126:386be867715c)
@@ -32,5 +32,8 @@
 from genshi.template.eval import UndefinedError
 
-from templates.opendocument import Template, GENSHI_EXPR
+from templates.opendocument import Template, GENSHI_EXPR, GENSHI_URI, \
+                                   RELATORIO_URI
+
+OO_TABLE_NS = "urn:oasis:names:tc:opendocument:xmlns:table:1.0"
 
 def pseudo_gettext(string):
@@ -76,13 +79,152 @@
     def test_directives(self):
         "Testing the directives interpolation"
-        xml = '''<b:a xmlns:b="urn:b" xmlns:text="%s" xmlns:draw="urn:draw"
-        xmlns:table="urn:table" xmlns:office="urn:office"
-        xmlns:xlink="urn:xlink">
-        <text:a xlink:href="relatorio://foo">foo</text:a>
-        </b:a>''' % 'urn:text'
+        xml = '''<xml xmlns:text="urn:text" xmlns:xlink="urn:xlink">
+                    <text:a xlink:href="relatorio://foo">foo</text:a>
+                 </xml>'''
         interpolated = self.oot.insert_directives(xml)
         root_interpolated = lxml.etree.parse(interpolated).getroot()
-        root_attrs = root_interpolated[0].attrib
-        eq_(root_attrs['{http://genshi.edgewall.org/}replace'], 'foo')
+        child = root_interpolated[0]
+        eq_(child.get('{http://genshi.edgewall.org/}replace'), 'foo')
+
+    def test_column_looping(self):
+        xml = '''
+<table:table
+    xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+    xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
+    xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+    xmlns:xlink="http://www.w3.org/1999/xlink"
+    table:name="Tableau1"
+    table:style-name="Tableau1">
+    <table:table-column table:style-name="Tableau1.A"
+                        table:number-columns-repeated="2"/>
+    <table:table-column table:style-name="Tableau1.C"/>
+    <table:table-column table:style-name="Tableau1.A"/>
+    <table:table-column table:style-name="Tableau1.E"/>
+    <table:table-header-rows>
+        <table:table-row table:style-name="Tableau1.1">
+            <table:table-cell table:style-name="Tableau1.A1"
+                              office:value-type="string">
+                <text:p text:style-name="Table_20_Heading">Brol</text:p>
+            </table:table-cell>
+            <table:table-cell table:style-name="Tableau1.A1"
+                              office:value-type="string">
+                <text:p text:style-name="Table_20_Heading">
+                    <text:a xlink:type="simple"
+                            xlink:href="relatorio://for each=&quot;title in titles&quot;">for each=&quot;title in titles&quot;</text:a>
+                </text:p>
+            </table:table-cell>
+            <table:table-cell table:style-name="Tableau1.A1"
+                              office:value-type="string">
+                <text:p text:style-name="Table_20_Heading">${title}</text:p>
+                <text:p text:style-name="Table_20_Heading"/>
+            </table:table-cell>
+            <table:table-cell table:style-name="Tableau1.A1"
+                              office:value-type="string">
+                <text:p text:style-name="Table_20_Heading">
+                    <text:a xlink:type="simple"
+                            xlink:href="relatorio:///for">/for</text:a>
+                </text:p>
+            </table:table-cell>
+            <table:table-cell table:style-name="Tableau1.E1"
+                              office:value-type="string">
+                <text:p text:style-name="Table_20_Heading">Truc</text:p>
+            </table:table-cell>
+        </table:table-row>
+    </table:table-header-rows>
+    <table:table-row>
+        <table:table-cell table:style-name="Tableau1.A2"
+                          table:number-columns-spanned="5"
+                          office:value-type="string">
+            <text:p text:style-name="Table_20_Contents">
+                <text:a xlink:type="simple"
+                        xlink:href="relatorio://for%20each=%22items%20in%20lst%22">for each=&quot;items in lst&quot;</text:a>
+            </text:p>
+        </table:table-cell>
+        <table:covered-table-cell/>
+        <table:covered-table-cell/>
+        <table:covered-table-cell/>
+        <table:covered-table-cell/>
+    </table:table-row>
+    <table:table-row>
+        <table:table-cell table:style-name="Tableau1.A3"
+                          office:value-type="string">
+            <text:p text:style-name="Table_20_Contents">Brol</text:p>
+        </table:table-cell>
+        <table:table-cell table:style-name="Tableau1.A3"
+                          office:value-type="string">
+            <text:p text:style-name="Table_20_Contents">
+                <text:a xlink:type="simple"
+                        xlink:href="relatorio://for%20each=%22item%20in%20items%22">for each=&quot;item in items&quot;</text:a>
+            </text:p>
+        </table:table-cell>
+        <table:table-cell table:style-name="Tableau1.A3"
+                          office:value-type="string">
+            <text:p text:style-name="Table_20_Contents">${item}</text:p>
+            <text:p text:style-name="Table_20_Contents"/>
+        </table:table-cell>
+        <table:table-cell table:style-name="Tableau1.A3"
+                          office:value-type="string">
+            <text:p text:style-name="Table_20_Contents">
+                <text:a xlink:type="simple"
+                        xlink:href="relatorio:///for">/for</text:a>
+            </text:p>
+        </table:table-cell>
+        <table:table-cell table:style-name="Tableau1.A2"
+                          office:value-type="string">
+            <text:p text:style-name="Table_20_Contents">Truc</text:p>
+        </table:table-cell>
+    </table:table-row>
+    <table:table-row>
+        <table:table-cell table:style-name="Tableau1.A2"
+                          table:number-columns-spanned="5"
+                          office:value-type="string">
+            <text:p text:style-name="Table_20_Contents">
+                <text:a xlink:type="simple"
+                        xlink:href="relatorio:///for">/for</text:a>
+            </text:p>
+        </table:table-cell>
+        <table:covered-table-cell/>
+        <table:covered-table-cell/>
+        <table:covered-table-cell/>
+        <table:covered-table-cell/>
+    </table:table-row>
+</table:table>'''
+        interpolated = self.oot.insert_directives(xml)
+        root = lxml.etree.parse(interpolated).getroot()
+        child2 = root[1]
+        eq_(child2.tag, "{%s}repeat" % RELATORIO_URI)
+        eq_(child2.get("closing"), "3")
+        eq_(child2.get("opening"), "1")
+        eq_(len(child2), 1)
+        child4 = root[3]
+        eq_(child4.tag, "{%s}table-header-rows" % OO_TABLE_NS)
+        row1 = child4[0]
+        ok_(row1.get("{%s}attrs" % GENSHI_URI)
+                .startswith('__relatorio_reset_col_count'))
+        eq_(len(row1), 4)
+        loop = row1[1]
+        eq_(loop.tag, "{%s}for" % GENSHI_URI)
+        cell = loop[0]
+        ok_(cell.get("{%s}attrs" % GENSHI_URI)
+                .startswith('__relatorio_inc_col_count'))
+        last_row_node = row1[3]
+        eq_(last_row_node.tag, "{%s}replace" % GENSHI_URI)
+        ok_(last_row_node.get("value")
+                         .startswith('__relatorio_store_col_count'))
+
+    def test_text_outside_p(self):
+        "Testing that the tail text of a directive node is handled properly"
+        xml = '''<xml xmlns:text="urn:text" xmlns:xlink="urn:xlink">
+                    <text:a xlink:href="relatorio://if%20test=%22True%22">if test=&quot;True&quot;</text:a>
+                    xxx
+                    <text:p text:style-name="other">yyy</text:p>
+                    zzz
+                    <text:a xlink:href="relatorio:///if">/if</text:a>
+                 </xml>'''
+        interpolated = self.oot.insert_directives(xml)
+        root_interpolated = lxml.etree.parse(interpolated).getroot()
+        child = root_interpolated[0]
+        eq_(child.tag, '{http://genshi.edgewall.org/}if')
+        eq_(child.text.strip(), 'xxx')
 
     def test_styles(self):
@@ -128,15 +270,15 @@
         images = root.xpath('//draw:frame', namespaces=self.oot.namespaces)
         eq_(len(images), 3)
-        eq_(images[0].attrib['{%s}name' % self.oot.namespaces['draw']],
+        eq_(images[0].get('{%s}name' % self.oot.namespaces['draw']),
             "image: (oeuf, 'image/png')")
-        eq_(images[1].attrib['{%s}name' % self.oot.namespaces['draw']],
+        eq_(images[1].get('{%s}name' % self.oot.namespaces['draw']),
             'image: img')
-        eq_(images[1].attrib['{%s}width' % self.oot.namespaces['svg']],
+        eq_(images[1].get('{%s}width' % self.oot.namespaces['svg']),
             '1.732cm')
-        eq_(images[1].attrib['{%s}height' % self.oot.namespaces['svg']],
+        eq_(images[1].get('{%s}height' % self.oot.namespaces['svg']),
             '1.513cm')
-        eq_(images[2].attrib['{%s}width' % self.oot.namespaces['svg']],
+        eq_(images[2].get('{%s}width' % self.oot.namespaces['svg']),
             '1.732cm')
-        eq_(images[2].attrib['{%s}height' % self.oot.namespaces['svg']],
+        eq_(images[2].get('{%s}height' % self.oot.namespaces['svg']),
             '1.513cm')
 
