Merge lp:~justas.sadzevicius/schooltool/schooltool.pdf_testing into lp:~schooltool-owners/schooltool/schooltool
- schooltool.pdf_testing
- Merge into schooltool
Proposed by
Justas Sadzevičius
Status: | Merged |
---|---|
Merge reported by: | Ignas Mikalajūnas |
Merged at revision: | not available |
Proposed branch: | lp:~justas.sadzevicius/schooltool/schooltool.pdf_testing |
Merge into: | lp:~schooltool-owners/schooltool/schooltool |
Diff against target: | None lines |
To merge this branch: | bzr merge lp:~justas.sadzevicius/schooltool/schooltool.pdf_testing |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ignas Mikalajūnas (community) | Approve | ||
Review via email: mp+5026@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Justas Sadzevičius (justas.sadzevicius) wrote : | # |
- 2467. By Justas Sadzevičius
-
Refactored helpers to a single StoryXML class.
- 2468. By Justas Sadzevičius
-
Whitespace
- 2469. By Justas Sadzevičius
-
Improved readability of README.txt and test_pdf a bit.
Revision history for this message
Ignas Mikalajūnas (ignas) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/schooltool/testing/README.txt' | |||
2 | --- src/schooltool/testing/README.txt 2008-01-15 18:46:51 +0000 | |||
3 | +++ src/schooltool/testing/README.txt 2009-03-30 12:24:08 +0000 | |||
4 | @@ -161,3 +161,60 @@ | |||
5 | 161 | >>> print analyze.queryHTML('/html/body/h1', html)[0] | 161 | >>> print analyze.queryHTML('/html/body/h1', html)[0] |
6 | 162 | <h1>This is my page!</h1> | 162 | <h1>This is my page!</h1> |
7 | 163 | 163 | ||
8 | 164 | |||
9 | 165 | Reportlab PDF story testing | ||
10 | 166 | --------------------------- | ||
11 | 167 | |||
12 | 168 | Schooltool PDF reports utilize Reportlab platypus module. A report is | ||
13 | 169 | built from a list of platypus flowables known as as 'story'. | ||
14 | 170 | |||
15 | 171 | Let's build a short pdf story. | ||
16 | 172 | |||
17 | 173 | >>> from reportlab.lib.styles import ParagraphStyle | ||
18 | 174 | >>> from reportlab.platypus.paragraph import Paragraph | ||
19 | 175 | >>> from reportlab.platypus.flowables import PageBreak | ||
20 | 176 | |||
21 | 177 | >>> style = ParagraphStyle(name='Test', fontName='Times-Roman') | ||
22 | 178 | |||
23 | 179 | >>> story = [ | ||
24 | 180 | ... Paragraph('Hello world', style), | ||
25 | 181 | ... PageBreak(), | ||
26 | 182 | ... Paragraph('A new page', style)] | ||
27 | 183 | |||
28 | 184 | There are several helpers for testing the stories. | ||
29 | 185 | |||
30 | 186 | >>> from schooltool.testing import pdf | ||
31 | 187 | |||
32 | 188 | The tools aim to build a human readable XML representation of the | ||
33 | 189 | story. There is a helper which prints the formatted XML: | ||
34 | 190 | |||
35 | 191 | >>> pdf.printStoryXML(story) | ||
36 | 192 | <story> | ||
37 | 193 | <Paragraph>Hello world</Paragraph> | ||
38 | 194 | <PageBreak/> | ||
39 | 195 | <Paragraph>A new page</Paragraph> | ||
40 | 196 | </story> | ||
41 | 197 | |||
42 | 198 | As with HTML analyzation tools, there are helpers for XPath queries: | ||
43 | 199 | |||
44 | 200 | >>> pdf.queryStory('//Paragraph', story) | ||
45 | 201 | ['<Paragraph>Hello world</Paragraph>', | ||
46 | 202 | '<Paragraph>A new page</Paragraph>'] | ||
47 | 203 | |||
48 | 204 | >>> pdf.printQuery('//Paragraph', story) | ||
49 | 205 | <Paragraph>Hello world</Paragraph> | ||
50 | 206 | <Paragraph>A new page</Paragraph> | ||
51 | 207 | |||
52 | 208 | These helpers also work on single platypus flowables: | ||
53 | 209 | |||
54 | 210 | >>> pdf.printStoryXML(Paragraph('Some text', style)) | ||
55 | 211 | <story> | ||
56 | 212 | <Paragraph>Some text</Paragraph> | ||
57 | 213 | </story> | ||
58 | 214 | |||
59 | 215 | If these helpers are not sufficient, we can build the raw XML document. | ||
60 | 216 | |||
61 | 217 | >>> document = pdf.getStoryXML(story) | ||
62 | 218 | >>> document | ||
63 | 219 | <...ElementTree object ...> | ||
64 | 220 | |||
65 | 164 | 221 | ||
66 | === added file 'src/schooltool/testing/pdf.py' | |||
67 | --- src/schooltool/testing/pdf.py 1970-01-01 00:00:00 +0000 | |||
68 | +++ src/schooltool/testing/pdf.py 2009-03-30 11:49:24 +0000 | |||
69 | @@ -0,0 +1,240 @@ | |||
70 | 1 | # | ||
71 | 2 | # SchoolTool - common information systems platform for school administration | ||
72 | 3 | # Copyright (c) 2005 Shuttleworth Foundation | ||
73 | 4 | # | ||
74 | 5 | # This program is free software; you can redistribute it and/or modify | ||
75 | 6 | # it under the terms of the GNU General Public License as published by | ||
76 | 7 | # the Free Software Foundation; either version 2 of the License, or | ||
77 | 8 | # (at your option) any later version. | ||
78 | 9 | # | ||
79 | 10 | # This program is distributed in the hope that it will be useful, | ||
80 | 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
81 | 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
82 | 13 | # GNU General Public License for more details. | ||
83 | 14 | # | ||
84 | 15 | # You should have received a copy of the GNU General Public License | ||
85 | 16 | # along with this program; if not, write to the Free Software | ||
86 | 17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
87 | 18 | # | ||
88 | 19 | """ | ||
89 | 20 | SchoolTool Reporlab PDF testing helpers. | ||
90 | 21 | |||
91 | 22 | $Id$ | ||
92 | 23 | |||
93 | 24 | """ | ||
94 | 25 | |||
95 | 26 | import cgi | ||
96 | 27 | from cStringIO import StringIO | ||
97 | 28 | from lxml import etree | ||
98 | 29 | |||
99 | 30 | from reportlab import platypus | ||
100 | 31 | |||
101 | 32 | |||
102 | 33 | def getStoryXML(story): | ||
103 | 34 | """Build human readable XML from a story of Reportlab flowables""" | ||
104 | 35 | parser = Parser(formatters=_xml_formatters, | ||
105 | 36 | default=format_classname_xml) | ||
106 | 37 | text = u'<story>\n%s\n</story>' % parser(story) | ||
107 | 38 | return etree.parse(StringIO(text.encode('UTF-8'))) | ||
108 | 39 | |||
109 | 40 | |||
110 | 41 | def printStoryXML(story): | ||
111 | 42 | print etree.tostring(getStoryXML(story), | ||
112 | 43 | pretty_print=True) | ||
113 | 44 | |||
114 | 45 | def queryStory(xpath, story): | ||
115 | 46 | """Perform an XPath query on XML built from the story of | ||
116 | 47 | Reportlab flowables""" | ||
117 | 48 | doc = getStoryXML(story) | ||
118 | 49 | result = [] | ||
119 | 50 | for node in doc.xpath(xpath): | ||
120 | 51 | if isinstance(node, basestring): | ||
121 | 52 | result.append(node) | ||
122 | 53 | else: | ||
123 | 54 | result.append(etree.tostring(node, pretty_print=True)) | ||
124 | 55 | return [s.strip() for s in result] | ||
125 | 56 | |||
126 | 57 | |||
127 | 58 | def printQuery(xpath, story): | ||
128 | 59 | """Print results of XPath query on XML built from the story of | ||
129 | 60 | Reportlab flowables""" | ||
130 | 61 | for entry in queryStory(xpath, story): | ||
131 | 62 | print entry | ||
132 | 63 | |||
133 | 64 | |||
134 | 65 | null_formatter = lambda parser, flowable: u'' | ||
135 | 66 | |||
136 | 67 | |||
137 | 68 | class Parser(object): | ||
138 | 69 | def __init__(self, formatters={}, default=null_formatter): | ||
139 | 70 | self.formatters = formatters.copy() | ||
140 | 71 | self.default = default | ||
141 | 72 | |||
142 | 73 | def __call__(self, flowable): | ||
143 | 74 | formatter = self.formatters.get(flowable.__class__, self.default) | ||
144 | 75 | return formatter(self, flowable) | ||
145 | 76 | |||
146 | 77 | |||
147 | 78 | def format_flowable_list(parser, flowables): | ||
148 | 79 | parsed = [parser(flowable) | ||
149 | 80 | for flowable in flowables] | ||
150 | 81 | return '\n'.join([text for text in parsed if text]) | ||
151 | 82 | |||
152 | 83 | |||
153 | 84 | def format_str_text(parser, flowable): | ||
154 | 85 | return unicode(flowable) | ||
155 | 86 | |||
156 | 87 | |||
157 | 88 | def format_classname_text(parser, flowable): | ||
158 | 89 | return unicode(flowable.__class__.__name__) | ||
159 | 90 | |||
160 | 91 | |||
161 | 92 | def format_str_xml(parser, flowable): | ||
162 | 93 | return cgi.escape(unicode(flowable)) | ||
163 | 94 | |||
164 | 95 | |||
165 | 96 | def format_classname_xml(parser, flowable): | ||
166 | 97 | return u'<%s />' % format_classname_text(parser, flowable) | ||
167 | 98 | |||
168 | 99 | |||
169 | 100 | def format_container_xml(parser, flowable): | ||
170 | 101 | tag_name = format_classname_text(parser, flowable) | ||
171 | 102 | content = parser(flowable._content) | ||
172 | 103 | return u'<%s>\n%s\n</%s>' % (tag_name, content, tag_name) | ||
173 | 104 | |||
174 | 105 | |||
175 | 106 | def format_preformatted_xml(parser, flowable): | ||
176 | 107 | tag_name = format_classname_text(parser, flowable) | ||
177 | 108 | return u'<%s bulletText="%s">%s</%s>' % ( | ||
178 | 109 | tag_name, | ||
179 | 110 | cgi.escape(flowable.bulletText), | ||
180 | 111 | cgi.escape(u'\n'.join(flowable.lines)), | ||
181 | 112 | tag_name) | ||
182 | 113 | |||
183 | 114 | |||
184 | 115 | def format_table_xml(parser, flowable): | ||
185 | 116 | tag_name = format_classname_text(parser, flowable) | ||
186 | 117 | text = u'<%s>\n' % tag_name | ||
187 | 118 | for row in flowable._cellvalues: | ||
188 | 119 | text += '<tr>\n' | ||
189 | 120 | for cell in row: | ||
190 | 121 | text += '<td>%s</td>\n' % parser(cell) | ||
191 | 122 | text += '</tr>\n' | ||
192 | 123 | text += u'</%s>' % tag_name | ||
193 | 124 | return text | ||
194 | 125 | |||
195 | 126 | |||
196 | 127 | class Format_Attributes_XML(object): | ||
197 | 128 | def __init__(self, attributes=[], content=''): | ||
198 | 129 | self.attribute_names = attributes | ||
199 | 130 | self.content_attribute = content | ||
200 | 131 | |||
201 | 132 | def formatAttr(self, parser, flowable, attr_name): | ||
202 | 133 | words = [word for word in attr_name.split('_') if word] | ||
203 | 134 | if words: | ||
204 | 135 | # first word starts with lower case | ||
205 | 136 | words[0] = words[0][:1].lower() + words[0][1:] | ||
206 | 137 | # other words start with upper case | ||
207 | 138 | words[1:] = [word[:1].upper() + word[1:] for word in words[1:]] | ||
208 | 139 | pretty_name = ''.join(words) | ||
209 | 140 | |||
210 | 141 | return u'%s="%s"' % ( | ||
211 | 142 | pretty_name, | ||
212 | 143 | cgi.escape(str(getattr(flowable, attr_name, None)))) | ||
213 | 144 | |||
214 | 145 | def formatContents(self, parser, flowable): | ||
215 | 146 | contents = u'' | ||
216 | 147 | if self.content_attribute: | ||
217 | 148 | contents = getattr( | ||
218 | 149 | flowable, self.content_attribute, '') | ||
219 | 150 | return unicode(cgi.escape(contents)) | ||
220 | 151 | |||
221 | 152 | def __call__(self, parser, flowable): | ||
222 | 153 | tag_name = format_classname_text(parser, flowable) | ||
223 | 154 | text = u'<%s' % tag_name | ||
224 | 155 | for attr_name in self.attribute_names: | ||
225 | 156 | text += u' %s' % self.formatAttr(parser, flowable, attr_name) | ||
226 | 157 | |||
227 | 158 | contents = self.formatContents(parser, flowable) | ||
228 | 159 | if contents: | ||
229 | 160 | text += u'>%s</%s>' % (contents, tag_name) | ||
230 | 161 | else: | ||
231 | 162 | text += u' />' | ||
232 | 163 | |||
233 | 164 | return text | ||
234 | 165 | |||
235 | 166 | |||
236 | 167 | class Format_Paragraph_XML(Format_Attributes_XML): | ||
237 | 168 | def __init__(self, attributes=[]): | ||
238 | 169 | Format_Attributes_XML.__init__(self, attributes=attributes) | ||
239 | 170 | |||
240 | 171 | def formatContents(self, parser, flowable): | ||
241 | 172 | return unicode(cgi.escape(flowable.getPlainText())) | ||
242 | 173 | |||
243 | 174 | |||
244 | 175 | class Format_ParaAndImage_XML(Format_Attributes_XML): | ||
245 | 176 | |||
246 | 177 | def __init__(self): | ||
247 | 178 | Format_Attributes_XML.__init__(self, ['xpad', 'ypad']) | ||
248 | 179 | |||
249 | 180 | def formatContents(self, parser, flowable): | ||
250 | 181 | text = parser([flowable.I, flowable.P]) | ||
251 | 182 | return text and '\n%s\n' % text or '' | ||
252 | 183 | |||
253 | 184 | |||
254 | 185 | _xml_formatters = { | ||
255 | 186 | # system | ||
256 | 187 | type(None): null_formatter, | ||
257 | 188 | list: format_flowable_list, | ||
258 | 189 | |||
259 | 190 | # plain text | ||
260 | 191 | str: format_str_xml, | ||
261 | 192 | unicode: format_str_xml, | ||
262 | 193 | |||
263 | 194 | # paragraph text | ||
264 | 195 | platypus.paragraph.Paragraph: Format_Paragraph_XML(), | ||
265 | 196 | platypus.xpreformatted.XPreformatted: Format_Paragraph_XML( | ||
266 | 197 | attributes=['bulletText']), | ||
267 | 198 | platypus.xpreformatted.PythonPreformatted: Format_Paragraph_XML( | ||
268 | 199 | attributes=['bulletText']), | ||
269 | 200 | platypus.flowables.Preformatted: format_preformatted_xml, | ||
270 | 201 | |||
271 | 202 | # graphics | ||
272 | 203 | platypus.flowables.Image: | ||
273 | 204 | Format_Attributes_XML(['filename', '_width', '_height']), | ||
274 | 205 | platypus.flowables.HRFlowable: | ||
275 | 206 | Format_Attributes_XML( | ||
276 | 207 | ['width', 'lineWidth', 'spaceBefore', 'spaceAfter', | ||
277 | 208 | 'hAlign', 'vAlign']), | ||
278 | 209 | |||
279 | 210 | # containers | ||
280 | 211 | platypus.tables.Table: format_table_xml, | ||
281 | 212 | platypus.tables.LongTable: format_table_xml, | ||
282 | 213 | platypus.flowables.ParagraphAndImage: Format_ParaAndImage_XML(), | ||
283 | 214 | #platypus.flowables.ImageAndFlowables | ||
284 | 215 | #platypus.flowables.PTOContainer, # (Please Turn Over The Page behaviour) | ||
285 | 216 | |||
286 | 217 | # spacing | ||
287 | 218 | platypus.flowables.KeepInFrame: format_container_xml, | ||
288 | 219 | platypus.flowables.KeepTogether: format_container_xml, | ||
289 | 220 | platypus.flowables.PageBreak: format_classname_xml, | ||
290 | 221 | platypus.flowables.SlowPageBreak: format_classname_xml, | ||
291 | 222 | platypus.flowables.CondPageBreak: Format_Attributes_XML(['height']), | ||
292 | 223 | platypus.flowables.Spacer: Format_Attributes_XML( | ||
293 | 224 | ['width', 'height']), | ||
294 | 225 | |||
295 | 226 | # other | ||
296 | 227 | platypus.flowables.AnchorFlowable: Format_Attributes_XML(['_name']), | ||
297 | 228 | #platypus.tableofcontents.TableOfContents, | ||
298 | 229 | #platypus.tableofcontents.SimpleIndex, | ||
299 | 230 | |||
300 | 231 | # omit from output | ||
301 | 232 | platypus.flowables.UseUpSpace: null_formatter, | ||
302 | 233 | platypus.flowables.Flowable: null_formatter, | ||
303 | 234 | platypus.flowables.TraceInfo: null_formatter, | ||
304 | 235 | platypus.flowables.Macro: null_formatter, | ||
305 | 236 | platypus.flowables.CallerMacro: null_formatter, | ||
306 | 237 | platypus.flowables.FailOnWrap: null_formatter, | ||
307 | 238 | platypus.flowables.FailOnDraw: null_formatter, | ||
308 | 239 | } | ||
309 | 240 | |||
310 | 0 | 241 | ||
311 | === added directory 'src/schooltool/testing/tests' | |||
312 | === removed file 'src/schooltool/testing/tests.py' | |||
313 | --- src/schooltool/testing/tests.py 2005-10-01 10:25:55 +0000 | |||
314 | +++ src/schooltool/testing/tests.py 1970-01-01 00:00:00 +0000 | |||
315 | @@ -1,36 +0,0 @@ | |||
316 | 1 | # | ||
317 | 2 | # SchoolTool - common information systems platform for school administration | ||
318 | 3 | # Copyright (c) 2005 Shuttleworth Foundation | ||
319 | 4 | # | ||
320 | 5 | # This program is free software; you can redistribute it and/or modify | ||
321 | 6 | # it under the terms of the GNU General Public License as published by | ||
322 | 7 | # the Free Software Foundation; either version 2 of the License, or | ||
323 | 8 | # (at your option) any later version. | ||
324 | 9 | # | ||
325 | 10 | # This program is distributed in the hope that it will be useful, | ||
326 | 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
327 | 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
328 | 13 | # GNU General Public License for more details. | ||
329 | 14 | # | ||
330 | 15 | # You should have received a copy of the GNU General Public License | ||
331 | 16 | # along with this program; if not, write to the Free Software | ||
332 | 17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
333 | 18 | # | ||
334 | 19 | """ | ||
335 | 20 | Testing the package. | ||
336 | 21 | |||
337 | 22 | $Id$ | ||
338 | 23 | """ | ||
339 | 24 | |||
340 | 25 | import unittest | ||
341 | 26 | from zope.testing import doctest | ||
342 | 27 | |||
343 | 28 | |||
344 | 29 | def test_suite(): | ||
345 | 30 | return unittest.TestSuite(( | ||
346 | 31 | doctest.DocFileSuite('README.txt', | ||
347 | 32 | optionflags=doctest.NORMALIZE_WHITESPACE), | ||
348 | 33 | )) | ||
349 | 34 | |||
350 | 35 | if __name__ == '__main__': | ||
351 | 36 | unittest.main(default='test_suite') | ||
352 | 37 | 0 | ||
353 | === added file 'src/schooltool/testing/tests/__init__.py' | |||
354 | --- src/schooltool/testing/tests/__init__.py 1970-01-01 00:00:00 +0000 | |||
355 | +++ src/schooltool/testing/tests/__init__.py 2009-03-30 11:49:24 +0000 | |||
356 | @@ -0,0 +1,36 @@ | |||
357 | 1 | # | ||
358 | 2 | # SchoolTool - common information systems platform for school administration | ||
359 | 3 | # Copyright (c) 2005 Shuttleworth Foundation | ||
360 | 4 | # | ||
361 | 5 | # This program is free software; you can redistribute it and/or modify | ||
362 | 6 | # it under the terms of the GNU General Public License as published by | ||
363 | 7 | # the Free Software Foundation; either version 2 of the License, or | ||
364 | 8 | # (at your option) any later version. | ||
365 | 9 | # | ||
366 | 10 | # This program is distributed in the hope that it will be useful, | ||
367 | 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
368 | 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
369 | 13 | # GNU General Public License for more details. | ||
370 | 14 | # | ||
371 | 15 | # You should have received a copy of the GNU General Public License | ||
372 | 16 | # along with this program; if not, write to the Free Software | ||
373 | 17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
374 | 18 | # | ||
375 | 19 | """ | ||
376 | 20 | Testing the package. | ||
377 | 21 | |||
378 | 22 | $Id$ | ||
379 | 23 | """ | ||
380 | 24 | |||
381 | 25 | import unittest | ||
382 | 26 | from zope.testing import doctest | ||
383 | 27 | |||
384 | 28 | |||
385 | 29 | def test_suite(): | ||
386 | 30 | return unittest.TestSuite(( | ||
387 | 31 | doctest.DocFileSuite('../README.txt', | ||
388 | 32 | optionflags=doctest.NORMALIZE_WHITESPACE), | ||
389 | 33 | )) | ||
390 | 34 | |||
391 | 35 | if __name__ == '__main__': | ||
392 | 36 | unittest.main(default='test_suite') | ||
393 | 0 | 37 | ||
394 | === added file 'src/schooltool/testing/tests/test_pdf.py' | |||
395 | --- src/schooltool/testing/tests/test_pdf.py 1970-01-01 00:00:00 +0000 | |||
396 | +++ src/schooltool/testing/tests/test_pdf.py 2009-03-30 12:24:08 +0000 | |||
397 | @@ -0,0 +1,203 @@ | |||
398 | 1 | # | ||
399 | 2 | # SchoolTool - common information systems platform for school administration | ||
400 | 3 | # Copyright (c) 2005 Shuttleworth Foundation | ||
401 | 4 | # | ||
402 | 5 | # This program is free software; you can redistribute it and/or modify | ||
403 | 6 | # it under the terms of the GNU General Public License as published by | ||
404 | 7 | # the Free Software Foundation; either version 2 of the License, or | ||
405 | 8 | # (at your option) any later version. | ||
406 | 9 | # | ||
407 | 10 | # This program is distributed in the hope that it will be useful, | ||
408 | 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
409 | 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
410 | 13 | # GNU General Public License for more details. | ||
411 | 14 | # | ||
412 | 15 | # You should have received a copy of the GNU General Public License | ||
413 | 16 | # along with this program; if not, write to the Free Software | ||
414 | 17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
415 | 18 | # | ||
416 | 19 | """ | ||
417 | 20 | Tests for pdf testing helpers. | ||
418 | 21 | |||
419 | 22 | $Id$ | ||
420 | 23 | """ | ||
421 | 24 | |||
422 | 25 | import unittest | ||
423 | 26 | from zope.testing import doctest | ||
424 | 27 | |||
425 | 28 | from reportlab.lib.styles import ParagraphStyle | ||
426 | 29 | from reportlab.lib import units | ||
427 | 30 | from reportlab import platypus | ||
428 | 31 | |||
429 | 32 | |||
430 | 33 | def buildTestStory(): | ||
431 | 34 | para_style = ParagraphStyle(name='Test', fontName='Times-Roman') | ||
432 | 35 | |||
433 | 36 | flowables = [] | ||
434 | 37 | flowables.append('Some\ntext') | ||
435 | 38 | |||
436 | 39 | flowables.append( | ||
437 | 40 | platypus.flowables.KeepInFrame( | ||
438 | 41 | units.inch*2, units.inch, content=[ | ||
439 | 42 | platypus.paragraph.Paragraph('Single line', para_style), | ||
440 | 43 | u'unicode text'])) | ||
441 | 44 | flowables.append( | ||
442 | 45 | platypus.xpreformatted.PythonPreformatted('print "foo"', | ||
443 | 46 | para_style, bulletText='*')) | ||
444 | 47 | flowables.append( | ||
445 | 48 | platypus.flowables.KeepTogether([ | ||
446 | 49 | platypus.paragraph.Paragraph( | ||
447 | 50 | 'Multi &\n<b>Line</b>', para_style), | ||
448 | 51 | platypus.xpreformatted.XPreformatted( | ||
449 | 52 | 'Text', para_style, bulletText='*'), | ||
450 | 53 | ], | ||
451 | 54 | maxHeight=units.inch)) | ||
452 | 55 | |||
453 | 56 | flowables.extend([ | ||
454 | 57 | platypus.flowables.HRFlowable(), | ||
455 | 58 | platypus.flowables.Image('logo.png', height=units.inch), | ||
456 | 59 | platypus.flowables.ParagraphAndImage( | ||
457 | 60 | platypus.paragraph.Paragraph('Text', para_style), | ||
458 | 61 | platypus.flowables.Image('file.png'), | ||
459 | 62 | xpad=units.inch), | ||
460 | 63 | ]) | ||
461 | 64 | |||
462 | 65 | flowables.extend([ | ||
463 | 66 | platypus.flowables.PageBreak(), | ||
464 | 67 | platypus.flowables.SlowPageBreak(), | ||
465 | 68 | platypus.flowables.CondPageBreak(height=units.inch*2), | ||
466 | 69 | platypus.flowables.Spacer(units.inch*3, units.inch), | ||
467 | 70 | ]) | ||
468 | 71 | |||
469 | 72 | flowables.append(platypus.flowables.AnchorFlowable('My anchor')) | ||
470 | 73 | |||
471 | 74 | # also add some uninteresting flowables | ||
472 | 75 | flowables.append(platypus.flowables.UseUpSpace()) | ||
473 | 76 | flowables.append(platypus.flowables.Macro('print "foo"')) | ||
474 | 77 | |||
475 | 78 | return flowables | ||
476 | 79 | |||
477 | 80 | |||
478 | 81 | def buildTableFlowable(): | ||
479 | 82 | para_style = ParagraphStyle(name='Test', fontName='Times-Roman') | ||
480 | 83 | |||
481 | 84 | data = [ | ||
482 | 85 | ['text', | ||
483 | 86 | platypus.paragraph.Paragraph('Text', para_style)], | ||
484 | 87 | [['several', 'items in a cell'], | ||
485 | 88 | platypus.flowables.Image('file.png')], | ||
486 | 89 | ] | ||
487 | 90 | return platypus.tables.Table(data) | ||
488 | 91 | |||
489 | 92 | |||
490 | 93 | def buildNestedTables(): | ||
491 | 94 | data = [ | ||
492 | 95 | ['A table with another table inside!'], | ||
493 | 96 | [buildTableFlowable()]] | ||
494 | 97 | return platypus.tables.LongTable(data) | ||
495 | 98 | |||
496 | 99 | |||
497 | 100 | def doctest_XML_building(): | ||
498 | 101 | r"""Tests for getStoryXML and printStoryXML. | ||
499 | 102 | |||
500 | 103 | >>> story = buildTestStory() | ||
501 | 104 | |||
502 | 105 | getStoryXML builds an XML element tree with some some basic flowable | ||
503 | 106 | parameters. | ||
504 | 107 | |||
505 | 108 | >>> from schooltool.testing.pdf import getStoryXML | ||
506 | 109 | >>> doc = getStoryXML(story) | ||
507 | 110 | |||
508 | 111 | >>> doc | ||
509 | 112 | <...ElementTree object ...> | ||
510 | 113 | |||
511 | 114 | printStoryXML builds and prints the XML tree. | ||
512 | 115 | |||
513 | 116 | >>> from schooltool.testing.pdf import printStoryXML | ||
514 | 117 | >>> printStoryXML(story) | ||
515 | 118 | <story> | ||
516 | 119 | Some | ||
517 | 120 | text | ||
518 | 121 | <KeepInFrame> | ||
519 | 122 | <Paragraph>Single line</Paragraph> | ||
520 | 123 | unicode text | ||
521 | 124 | </KeepInFrame> | ||
522 | 125 | <PythonPreformatted bulletText="*">print "foo"</PythonPreformatted> | ||
523 | 126 | <KeepTogether> | ||
524 | 127 | <Paragraph>Multi & Line</Paragraph> | ||
525 | 128 | <XPreformatted bulletText="*">Text</XPreformatted> | ||
526 | 129 | </KeepTogether> | ||
527 | 130 | <HRFlowable width="80%" lineWidth="1" | ||
528 | 131 | spaceBefore="1" spaceAfter="1" | ||
529 | 132 | hAlign="CENTER" vAlign="BOTTOM"/> | ||
530 | 133 | <Image filename="logo.png" width="None" height="72.0"/> | ||
531 | 134 | <ParagraphAndImage xpad="72.0" ypad="3"> | ||
532 | 135 | <Image filename="file.png" width="None" height="None"/> | ||
533 | 136 | <Paragraph>Text</Paragraph> | ||
534 | 137 | </ParagraphAndImage> | ||
535 | 138 | <PageBreak/> | ||
536 | 139 | <SlowPageBreak/> | ||
537 | 140 | <CondPageBreak height="144.0"/> | ||
538 | 141 | <Spacer width="216.0" height="72.0"/> | ||
539 | 142 | <AnchorFlowable name="My anchor"/> | ||
540 | 143 | </story> | ||
541 | 144 | |||
542 | 145 | Test printing of tables. | ||
543 | 146 | |||
544 | 147 | >>> printStoryXML(buildNestedTables()) | ||
545 | 148 | <story> | ||
546 | 149 | <LongTable> | ||
547 | 150 | <tr> | ||
548 | 151 | <td>A table with another table inside!</td> | ||
549 | 152 | </tr> | ||
550 | 153 | <tr> | ||
551 | 154 | <td><Table> | ||
552 | 155 | <tr> | ||
553 | 156 | <td>text</td> | ||
554 | 157 | <td><Paragraph>Text</Paragraph></td> | ||
555 | 158 | </tr> | ||
556 | 159 | <tr> | ||
557 | 160 | <td>several | ||
558 | 161 | items in a cell</td> | ||
559 | 162 | <td><Image filename="file.png" width="None" height="None"/></td> | ||
560 | 163 | </tr> | ||
561 | 164 | </Table></td> | ||
562 | 165 | </tr> | ||
563 | 166 | </LongTable> | ||
564 | 167 | </story> | ||
565 | 168 | |||
566 | 169 | """ | ||
567 | 170 | |||
568 | 171 | |||
569 | 172 | def doctest_XML_query_helpers(): | ||
570 | 173 | r"""Tests for queryStory and printQuery. | ||
571 | 174 | |||
572 | 175 | >>> story = buildTestStory() | ||
573 | 176 | |||
574 | 177 | queryStory builds the XML and performs xpath query on it. | ||
575 | 178 | |||
576 | 179 | >>> from schooltool.testing.pdf import queryStory | ||
577 | 180 | >>> queryStory('//Image', story) | ||
578 | 181 | ['<Image filename="logo.png" width="None" height="72.0"/>', | ||
579 | 182 | '<Image filename="file.png" width="None" height="None"/>'] | ||
580 | 183 | |||
581 | 184 | printQuery is a helper which also prints the results: | ||
582 | 185 | |||
583 | 186 | >>> from schooltool.testing.pdf import printQuery | ||
584 | 187 | >>> printQuery('//Image', story) | ||
585 | 188 | <Image filename="logo.png" width="None" height="72.0"/> | ||
586 | 189 | <Image filename="file.png" width="None" height="None"/> | ||
587 | 190 | |||
588 | 191 | """ | ||
589 | 192 | |||
590 | 193 | |||
591 | 194 | def test_suite(): | ||
592 | 195 | optionflags = (doctest.NORMALIZE_WHITESPACE | | ||
593 | 196 | doctest.ELLIPSIS | | ||
594 | 197 | doctest.REPORT_NDIFF) | ||
595 | 198 | return unittest.TestSuite(( | ||
596 | 199 | doctest.DocTestSuite(optionflags=optionflags), | ||
597 | 200 | )) | ||
598 | 201 | |||
599 | 202 | if __name__ == '__main__': | ||
600 | 203 | unittest.main(default='test_suite') | ||
601 | 0 | 204 | ||
602 | === added file 'src/schooltool/testing/tests/test_readme.py' | |||
603 | --- src/schooltool/testing/tests/test_readme.py 1970-01-01 00:00:00 +0000 | |||
604 | +++ src/schooltool/testing/tests/test_readme.py 2009-03-30 12:24:08 +0000 | |||
605 | @@ -0,0 +1,39 @@ | |||
606 | 1 | # | ||
607 | 2 | # SchoolTool - common information systems platform for school administration | ||
608 | 3 | # Copyright (c) 2005 Shuttleworth Foundation | ||
609 | 4 | # | ||
610 | 5 | # This program is free software; you can redistribute it and/or modify | ||
611 | 6 | # it under the terms of the GNU General Public License as published by | ||
612 | 7 | # the Free Software Foundation; either version 2 of the License, or | ||
613 | 8 | # (at your option) any later version. | ||
614 | 9 | # | ||
615 | 10 | # This program is distributed in the hope that it will be useful, | ||
616 | 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
617 | 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
618 | 13 | # GNU General Public License for more details. | ||
619 | 14 | # | ||
620 | 15 | # You should have received a copy of the GNU General Public License | ||
621 | 16 | # along with this program; if not, write to the Free Software | ||
622 | 17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
623 | 18 | # | ||
624 | 19 | """ | ||
625 | 20 | Test suite for README-style tests. | ||
626 | 21 | |||
627 | 22 | $Id$ | ||
628 | 23 | """ | ||
629 | 24 | |||
630 | 25 | import unittest | ||
631 | 26 | from zope.testing import doctest | ||
632 | 27 | |||
633 | 28 | |||
634 | 29 | def test_suite(): | ||
635 | 30 | optionflags = (doctest.NORMALIZE_WHITESPACE | | ||
636 | 31 | doctest.ELLIPSIS | | ||
637 | 32 | doctest.REPORT_NDIFF) | ||
638 | 33 | return unittest.TestSuite(( | ||
639 | 34 | doctest.DocFileSuite('../README.txt', | ||
640 | 35 | optionflags=optionflags), | ||
641 | 36 | )) | ||
642 | 37 | |||
643 | 38 | if __name__ == '__main__': | ||
644 | 39 | unittest.main(default='test_suite') |
For PDF reports: testing helpers for stories of Reportlab platypus flowables.