Mercurial > p > roundup > code
comparison test/test_templating.py @ 7866:9bbc1d951677
issue2551331 - Fix repeat first/last methods.
The first() and last() methods for a variable defined by tal:repeat
now work as documented.
There is an undocumented same_part() method for repeat. It is called
by first/last and can cause them to return true when not at an end of
the Iterator sequence. I wrote a treatise on that function and what it
does. I have no idea why it does what it does.
Added tests for roundup/cgi/ZTUtils/Iterator.py
Also fixes issue with roman() found while writing tests. lower wasn't
being called and it was printing the lower() method signature.
Doc updates in references.txt to come in a future checkin. Clarifying
the repeat methods led to finding/fixing this.
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Sun, 07 Apr 2024 20:52:17 -0400 |
| parents | b080cdb8b199 |
| children | 29a666d8a70d |
comparison
equal
deleted
inserted
replaced
| 7865:ee586ff074ed | 7866:9bbc1d951677 |
|---|---|
| 2 import unittest | 2 import unittest |
| 3 import time | 3 import time |
| 4 | 4 |
| 5 from roundup.anypy.cgi_ import FieldStorage, MiniFieldStorage | 5 from roundup.anypy.cgi_ import FieldStorage, MiniFieldStorage |
| 6 from roundup.cgi.templating import * | 6 from roundup.cgi.templating import * |
| 7 from roundup.cgi.ZTUtils.Iterator import Iterator | |
| 7 from .test_actions import MockNull, true | 8 from .test_actions import MockNull, true |
| 8 from .html_norm import NormalizingHtmlParser | 9 from .html_norm import NormalizingHtmlParser |
| 9 | 10 |
| 10 | 11 |
| 11 import pytest | 12 import pytest |
| 1117 def test_string_stext(self): | 1118 def test_string_stext(self): |
| 1118 p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'A string with cmeerw@example.com *embedded* \u00df')) | 1119 p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'A string with cmeerw@example.com *embedded* \u00df')) |
| 1119 self.assertEqual(p.stext(), u2s(u'A string with <a href="mailto:cmeerw@example.com">cmeerw@example.com</a> *embedded* \u00df')) | 1120 self.assertEqual(p.stext(), u2s(u'A string with <a href="mailto:cmeerw@example.com">cmeerw@example.com</a> *embedded* \u00df')) |
| 1120 | 1121 |
| 1121 | 1122 |
| 1123 class ZUtilsTestcase(TemplatingTestCase): | |
| 1124 | |
| 1125 def test_Iterator(self): | |
| 1126 """Test all the iterator functions and properties. | |
| 1127 """ | |
| 1128 sequence = ['one', 'two', '3', 4] | |
| 1129 i = Iterator(sequence) | |
| 1130 for j in [ # element, item, 1st, last, even, odd, number, | |
| 1131 # letter, Letter, roman, Roman | |
| 1132 (1, "one", 1, 0, True, 0, 1, 'a', 'A', 'i', 'I'), | |
| 1133 (1, "two", 0, 0, False, 1, 2, 'b', 'B', 'ii', 'II'), | |
| 1134 (1, "3", 0, 0, True, 0, 3, 'c', 'C', 'iii', 'III'), | |
| 1135 (1, 4, 0, 1, False, 1, 4, 'd', 'D', 'iv', 'IV'), | |
| 1136 # next() fails with 0 when past end of sequence | |
| 1137 # everything else is left at end of sequence | |
| 1138 (0, 4, 0, 1, False, 1, 4, 'd', 'D', 'iv', 'IV'), | |
| 1139 | |
| 1140 | |
| 1141 ]: | |
| 1142 element = i.next() # returns 1 if next item else 0 | |
| 1143 print(i.item) | |
| 1144 self.assertEqual(element, j[0]) | |
| 1145 self.assertEqual(i.item, j[1]) | |
| 1146 self.assertEqual(i.first(), j[2]) | |
| 1147 self.assertEqual(i.start, j[2]) | |
| 1148 self.assertEqual(i.last(), j[3]) | |
| 1149 self.assertEqual(i.end, j[3]) | |
| 1150 self.assertIs(i.even(), j[4]) | |
| 1151 self.assertEqual(i.odd(), j[5]) | |
| 1152 self.assertEqual(i.number(), j[6]) | |
| 1153 self.assertEqual(i.index, j[6] - 1) | |
| 1154 self.assertEqual(i.nextIndex, j[6]) | |
| 1155 self.assertEqual(i.letter(), j[7]) | |
| 1156 self.assertEqual(i.Letter(), j[8]) | |
| 1157 self.assertEqual(i.roman(), j[9]) | |
| 1158 self.assertEqual(i.Roman(), j[10]) | |
| 1159 | |
| 1160 class I: | |
| 1161 def __init__(self, name, data): | |
| 1162 self.name = name | |
| 1163 self.data = data | |
| 1164 | |
| 1165 sequence = [I('Al', 'd'), | |
| 1166 I('Bob', 'e'), | |
| 1167 I('Bob', 'd'), | |
| 1168 I('Chip', 'd') | |
| 1169 ] | |
| 1170 | |
| 1171 iterator = iter(sequence) | |
| 1172 | |
| 1173 # Iterator is supposed take both sequence and Python iterator. | |
| 1174 for source in [sequence, iterator]: | |
| 1175 i = Iterator(source) | |
| 1176 | |
| 1177 element = i.next() # returns 1 if next item else 0 | |
| 1178 item1 = i.item | |
| 1179 | |
| 1180 # note these can trigger calls by first/last to same_part(). | |
| 1181 # It can return true for first/last even when there are more | |
| 1182 # items in the sequence. I am just testing the current | |
| 1183 # implementation. Woe to the person who tries to change | |
| 1184 # Iterator.py. | |
| 1185 | |
| 1186 self.assertEqual(element, 1) | |
| 1187 # i.start == 1, so it bypasses name check | |
| 1188 self.assertEqual(i.first(name='namea'), 1) | |
| 1189 self.assertEqual(i.first(name='name'), 1) | |
| 1190 # i.end == 0 so it uses name check in object | |
| 1191 self.assertEqual(i.last(name='namea'), 0) | |
| 1192 self.assertEqual(i.last(name='name'), 0) | |
| 1193 | |
| 1194 element = i.next() # returns 1 if next item else 0 | |
| 1195 item2 = i.item | |
| 1196 self.assertEqual(element, 1) | |
| 1197 # i.start == 0 so it uses name check | |
| 1198 # between item1 and item2 | |
| 1199 self.assertEqual(i.first(name='namea'), 0) | |
| 1200 self.assertEqual(i.first(name='name'), 0) | |
| 1201 # i.end == 0 so it uses name check in object | |
| 1202 # between item2 and the next item item3 | |
| 1203 self.assertEqual(i.last(name='namea'), 0) | |
| 1204 self.assertEqual(i.last(name='name'), True) | |
| 1205 | |
| 1206 element = i.next() # returns 1 if next item else 0 | |
| 1207 item3 = i.item | |
| 1208 self.assertEqual(element, 1) | |
| 1209 # i.start == 0 so it uses name check | |
| 1210 self.assertEqual(i.first(name='namea'), 0) | |
| 1211 self.assertEqual(i.first(name='name'), 1) | |
| 1212 # i.end == 0 so it uses name check in object | |
| 1213 # between item3 and the next item item4 | |
| 1214 self.assertEqual(i.last(name='namea'), 0) | |
| 1215 self.assertEqual(i.last(name='name'), 0) | |
| 1216 | |
| 1217 element = i.next() # returns 1 if next item else 0 | |
| 1218 item4 = i.item | |
| 1219 self.assertEqual(element, 1) | |
| 1220 # i.start == 0 so it uses name check | |
| 1221 self.assertEqual(i.first(name='namea'), 0) | |
| 1222 self.assertEqual(i.first(name='name'), 0) | |
| 1223 # i.end == 0 so it uses name check in object | |
| 1224 # last two object have same name (1) | |
| 1225 self.assertEqual(i.last(name='namea'), 1) | |
| 1226 self.assertEqual(i.last(name='name'), 1) | |
| 1227 | |
| 1228 element = i.next() # returns 1 if next item else 0 | |
| 1229 self.assertEqual(element, 0) | |
| 1230 | |
| 1231 # this is the underlying call for first/last | |
| 1232 # when i.start/i.end are 0 | |
| 1233 # use non-existing attribute name, same item | |
| 1234 self.assertIs(i.same_part('namea', item2, item2), False) | |
| 1235 # use correct attribute name | |
| 1236 self.assertIs(i.same_part('name', item2, item2), True) | |
| 1237 # use no attribute name | |
| 1238 self.assertIs(i.same_part(None, item2, item2), True) | |
| 1239 | |
| 1240 # use non-existing attribute name, different item | |
| 1241 # non-matching names | |
| 1242 self.assertIs(i.same_part('namea', item1, item2), False) | |
| 1243 # use correct attribute name | |
| 1244 self.assertIs(i.same_part('name', item1, item2), False) | |
| 1245 # use no attribute name | |
| 1246 self.assertIs(i.same_part(None, item1, item2), False) | |
| 1247 | |
| 1248 # use non-existing attribute name, different item | |
| 1249 # matching names | |
| 1250 self.assertIs(i.same_part('namea', item2, item3), False) | |
| 1251 # use correct attribute name | |
| 1252 self.assertIs(i.same_part('name', item2, item3), True) | |
| 1253 # use no attribute name | |
| 1254 self.assertIs(i.same_part(None, item2, item3), False) | |
| 1255 | |
| 1122 r''' | 1256 r''' |
| 1123 class HTMLPermissions: | 1257 class HTMLPermissions: |
| 1124 def is_edit_ok(self): | 1258 def is_edit_ok(self): |
| 1125 def is_view_ok(self): | 1259 def is_view_ok(self): |
| 1126 def is_only_view_ok(self): | 1260 def is_only_view_ok(self): |
