-
Notifications
You must be signed in to change notification settings - Fork 0
/
backwatertest.py
577 lines (485 loc) · 30.5 KB
/
backwatertest.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
backwatertest.py
Created by Jacob C. on 2008-02-26.
Copyright (c) 2010 Spaceship No Future. All rights reserved.
"""
import unittest
import spider
from spider.source import Source
from spider.weblog import Weblog
from spider.linklog import Linklog
from spider.commentlog import Commentlog
from spider.tumblelog import Tumblelog
from spider.photostream import Photostream
from spider.twitterstatus import TwitterStatus
import publish.sanitizer
import publish.shorten
import publish.typogrify
class SanityTestCases(unittest.TestCase):
# TODO: Sanity test URLs need to be placed in a data structure like the sources.yaml file
def setUp(self):
self.live_urls = (
'http://chompy.net/blogs/jacob/feeds/index.atom',
'http://chompy.net/blogs/pogo/atom.xml',
'http://chompy.net/blogs/nathalie/atom.xml',
'http://palcontent.blogspot.com/feeds/posts/default',
'http://hoolifan.blogspot.com/feeds/posts/default',
'http://bubblegumdamage.blogspot.com/feeds/posts/default',
'http://savagepencil.typepad.com/charlieletters/index.rdf',
'http://savagepencil.typepad.com/confessions/index.rdf',
'http://headcrab.org/feed/atom/',
'http://benkerishan.blogspot.com/feeds/posts/default',
'http://www.tbray.org/ongoing/ongoing.atom',
'http://wileywiggins.blogspot.com/feeds/posts/default',
'http://feeds.feedburner.com/greeninterfaces'
)
self.test_urls = (
'http://chompy.net/lab/backwater/tests/sanity/remakeremodel.xml',
'http://chompy.net/lab/backwater/tests/sanity/darkentries.xml',
'http://chompy.net/lab/backwater/tests/sanity/peenywally.xml',
'http://chompy.net/lab/backwater/tests/sanity/tigerpounces.xml',
'http://chompy.net/lab/backwater/tests/sanity/greencandle.xml',
'http://chompy.net/lab/backwater/tests/sanity/garbage.xml',
'http://chompy.net/lab/backwater/tests/sanity/bubblegumdamage.xml',
'http://chompy.net/lab/backwater/tests/sanity/charlieletters.xml',
'http://chompy.net/lab/backwater/tests/sanity/confessions.xml',
'http://chompy.net/lab/backwater/tests/sanity/headcrab.xml',
'http://chompy.net/lab/backwater/tests/sanity/arabic.xml',
'http://chompy.net/lab/backwater/tests/sanity/ongoing.xml',
'http://chompy.net/lab/backwater/tests/sanity/newsofthedead.xml'
)
class FeedTestCases(unittest.TestCase):
def setUp(self):
self.url = 'http://example.com/test'
self.base_url = 'http://chompy.net/lab/backwater/tests/sources/weblog/'
self.atom_url = self.base_url + 'atom.atom'
self.rss_url = self.base_url + 'rss.rss'
self.rdf_url = self.base_url + 'rdf.rdf'
self.no_title_url = self.base_url + 'no_title.atom'
self.no_summary_url = self.base_url + 'no_summary.atom'
self.no_content_url = self.base_url + 'no_content.atom'
self.author_details_url = self.base_url + 'author_details.atom'
self.no_author_details_url = self.base_url + 'no_author_details.atom'
self.multiple_alternate_links_url = self.base_url + 'multple_alternate_links.atom'
self.related_link_url = self.base_url + 'related_link_url.atom'
self.via_link_url = self.base_url + 'via_link_url.atom'
self.comments_url = self.base_url + 'comments_url.rss'
self.atom_source_url = self.base_url + 'atom_source_url.atom'
def testIsAtom(self):
"""An Atom feed can be detected."""
w = Weblog('test', 'testy', self.url, self.atom_url)
w.parse()
w.normalize()
for entry in w.entries:
entry.normalize()
assert w.atom == True
def testIsNotAtom(self):
"""A non-Atom feed can be detected."""
w = Weblog('test', 'testy', self.url, self.rss_url)
w.parse()
w.normalize()
for entry in w.entries:
entry.normalize()
assert w.atom == False
def testFeedWithMissingEntryLinks(self):
"""Feed items with entry.links missing can be parsed."""
w = Weblog('test', 'testy', self.url, self.rss_url)
w.parse()
class TumblelogTestCases(unittest.TestCase):
def setUp(self):
pass
class PhotoTestCases(unittest.TestCase):
def setUp(self):
pass
class TwitterTestCases(unittest.TestCase):
def setUp(self):
self.plain_ol_tweet = """I'm preparing a delicious sandwich!"""
self.tweet_with_hashtag = """This caprese has changed my life! #inspirationalsalads"""
self.tweet_with_username = """@mozzarella Are you buffalo or garden variety?"""
self.tweet_with_username_and_punctuation = """@NuerOb: I am like a pot roast, but better!"""
self.tweet_with_url = "What an outstanding website! http://chompy.net"
self.tweet_with_reply = "@lemmycaution What do you love above all?"
self.tweet_with_retweet = "RT @lemmycaution I refuse to become what you call normal."
self.tweet_with_the_works = ""
self.example_account = "setholdmixon"
def testLinkHashtag(self):
"""Twitter hashtags are automatically linked."""
expected = """This caprese has changed my life! <a href="http://twitter.com/search?q=%23inspirationalsalads">#inspirationalsalads</a>"""
result = TwitterStatus.link_hashtags(self.tweet_with_hashtag)
assert result == expected
def testLinkUsername(self):
"""Twitter usernames are automatically linked."""
expected = """@<a href="http://twitter.com/mozzarella/">mozzarella</a> Are you buffalo or garden variety?"""
result = TwitterStatus.link_users(self.tweet_with_username)
assert result == expected
def testLinkUsernameWithPunctuation(self):
"""A Twitter username with trailing punctuation can be linked."""
expected = """@<a href="http://twitter.com/NuerOb/">NuerOb</a>: I am like a pot roast, but better!"""
result = TwitterStatus.link_users(self.tweet_with_username)
assert result == expected
def testLinkUrl(self):
"""URLs within tweets are automatically linked."""
expected = """What an outstanding website! <a href="http://chompy.net">http://chompy.net</a>"""
# TODO: Finish this test case
def testIgnoreReply(self):
"""Twitter replies can be ignored."""
self.assertTrue(TwitterStatus.is_reply(self.tweet_with_reply))
def testIgnoreRetweet(self):
"""Twitter retweets, which are annoying, can be ignored."""
self.assertTrue(TwitterStatus.is_retweet(self.tweet_with_retweet))
def parseTwitterStatus(self):
"""A real-world Twitter status feed can be parsed."""
name = self.example_account
owner = self.example_account
url = "http://twitter.com/" + self.example_account
t = TwitterStatus(name, owner, url)
t.parse()
class StripperTestCases(unittest.TestCase):
def setUp(self):
self.basic_txt = """<h1>Change <em>alone</em> is unchanging.</h1>"""
self.plain_txt = "The dead body is useless even as manure."
self.txt_with_attrs = """Law gives the people a <a href="http://example.com/">single will</a> to obey."""
self.txt_with_minimized_attrs = """Law gives the people a <option selected>single will</option> to obey."""
self.txt_with_entities = """<blockquote><p>I’ve seen Plato's cups & tables, but not his <i>cupness</i> & <i>tableness</i>.</p></blockquote>"""
self.style_tag = """The <span style="font-family: 'Comic Sans';">same road</span> goes both up and down."""
self.script_tag = """Men are not intellligent. <script type="text/javascript">alert('Not enough and too much.');</script> The gods are intelligent."""
self.script_url = """The <a href="javascript:alert('boo');">untrained mind</a> shivers with excitement at everything it hears."""
self.self_closed_html_tag = """To God all is beautiful, good, and as it should be.<br> Man must see things as either good or bad."""
self.self_closed_xhtml_tag = """To God all is beautiful, good, and as it should be.<br /> Man must see things as either good or bad."""
self.nested_tags = """Having cut, <a href="http://example.com"><b>burned</b> and <font style="color: #CCC;">poisoned</font></a> the sick, the doctor then submits <strong>his bill</strong>."""
self.unbalanced_tags = """<h1>Extinguish <q>pride <b>as</q> quickly</b> as you would a fire."""
self.unknown_tags = """Law gives the people a <turkey gobble="http://example.com/">single will</turkey> to obey."""
def testStripTags(self):
"""HTML tags are stripped from text."""
result = publish.sanitizer.strip(self.basic_txt)
assert result == 'Change alone is unchanging.'
def testStripPlainText(self):
"""HTML stripper leaves plain text as is."""
result = publish.sanitizer.strip(self.plain_txt)
assert result == self.plain_txt
def testStripTagsWithAttributes(self):
"""HTML tags containing attributes are stripped."""
result = publish.sanitizer.strip(self.txt_with_attrs)
assert result == "Law gives the people a single will to obey."
def testStripTagsWithMinimizedAttributes(self):
"""HTML tags containing minimized attributes are stripped."""
result = publish.sanitizer.strip(self.txt_with_minimized_attrs)
assert result == "Law gives the people a single will to obey."
def testStripTagsWIthEntities(self):
"""HTML entities are converted to Unicode characters by the HTML stripper."""
result = publish.sanitizer.strip(self.txt_with_entities)
assert result == "I’ve seen Plato's cups & tables, but not his cupness & tableness."
def testStripStyleTags(self):
"""HTML <style> tags are stripped."""
result = publish.sanitizer.strip(self.style_tag)
assert result == "The same road goes both up and down."
def testStripScriptTags(self):
"""HTML <script> tags are stripped."""
result = publish.sanitizer.strip(self.script_tag)
assert result == "Men are not intellligent. alert('Not enough and too much.'); The gods are intelligent."
def testStripSelfClosedHtmlTags(self):
"""Self-closed tags such as <br> are stripped."""
result = publish.sanitizer.strip(self.self_closed_html_tag)
assert result == """To God all is beautiful, good, and as it should be. Man must see things as either good or bad."""
def testStripSelfClosedXhtmlTags(self):
"""Self-closed tags such as <br /> are stripped."""
result = publish.sanitizer.strip(self.self_closed_xhtml_tag)
assert result == """To God all is beautiful, good, and as it should be. Man must see things as either good or bad."""
def testStripNestedTags(self):
"""Nested HTML tags are stripped."""
result = publish.sanitizer.strip(self.nested_tags)
assert result == """Having cut, burned and poisoned the sick, the doctor then submits his bill."""
def testStripUnbalancedTags(self):
"""Unbalanced HTML tags are stripped."""
result = publish.sanitizer.strip(self.unbalanced_tags)
assert result == "Extinguish pride as quickly as you would a fire."
def testStripUnknownTags(self):
"""Unknown markup is stripped."""
result = publish.sanitizer.strip(self.unknown_tags)
assert result == """Law gives the people a single will to obey."""
class TagSubstitutionTestCases(unittest.TestCase):
def setUp(self):
self.one_paragraph = "<p>The falcon cannot hear the falconer.</p>"
self.two_paragraphs = "<p>A doll in the doll-maker's house</p><p>Looks at the cradle and bawls</p>"
self.mixed_blocks = """<p>Cuchulain has killed kings</p><h1>Kings and sons of kings</h1><p>Dragons out of the water</p>"""
self.with_newline = """<p>Witches that steal the milk</p>\n<p>Fomor that steal the children</p>"""
self.h1 = """<h1>Sailing to Byzantium</h1>"""
self.h1_with_attr = """<h1 id="ct_130213948">Celtic Twilight</h1>"""
self.h1_with_nested_anchor = """<h1><a href="http://example.com/">Easter 1918</a></h1>"""
def testHeadingToBold(self):
"""Block-level <h1> tags are replaced with inline <b> tags."""
result = publish.sanitizer.heading_to_bold(self.h1)
assert result == """<b>Sailing to Byzantium</b>"""
def testHeadingWithAttributesToBold(self):
"""<h1> tags with attributes are replaced with <b> tags."""
result = publish.sanitizer.heading_to_bold(self.h1_with_attr)
assert result == """<b>Celtic Twilight</b>"""
def testHeadingWithNestedAnchorToBold(self):
"""<h1> tags with nested anchors are replaced with <b> tags."""
result = publish.sanitizer.heading_to_bold(self.h1_with_nested_anchor)
assert result == """<b><a href="http://example.com/">Easter 1918</a></b>"""
def testBlocktoBrWithOneParagraph(self):
"""block_to_break() strips a lone <p> tag."""
result = publish.sanitizer.block_to_break(self.one_paragraph)
print result
assert result == """The falcon cannot hear the falconer."""
def testBlockToBreakWithTwoParagraphs(self):
"""block_to_break() strips two <p> tags and places two <br>s between them."""
result = publish.sanitizer.block_to_break(self.two_paragraphs)
print result
assert result == """A doll in the doll-maker's house<br /><br />Looks at the cradle and bawls"""
def testBlockToBreakWithMixedBlocks(self):
"""block_to_break() deals correctly with mixed block tags."""
result = publish.sanitizer.block_to_break(self.mixed_blocks)
print result
assert result == """Cuchulain has killed kings<br /><br />Kings and sons of kings<br /><br />Dragons out of the water"""
class SanitizeTestCases(unittest.TestCase):
def setUp(self):
# FIXME: The default whitelist is assumed.
# It would be better to specify the whitelist.
self.basic_txt = """<h1>Change <em>alone</em> is unchanging."""
self.plain_txt = "The dead body is useless even as manure."
self.txt_with_attrs = """Law gives the people a <a href="http://example.com/">single will</a> to obey."""
self.txt_with_entities = """<blockquote><p>I’ve seen Plato's cups & tables, but not his <i>cupness</i> & <i>tableness</i>.</p></blockquote>"""
self.style_tag = """The <span style="font-family: 'Comic Sans';">same road</span> goes both up and down."""
self.script_tag = """Men are not intellligent. <script type="text/javascript">alert('Not enough and too much.');</script> The gods are intelligent."""
self.script_url = """The <a href="javascript:alert('boo');">untrained mind</a> shivers with excitement at everything it hears."""
self.html_br = """To God all is beautiful, good, and as it should be.<br> Man must see things as either good or bad."""
self.html_hr = """To God all is beautiful, good, and as it should be.<hr> Man must see things as either good or bad."""
self.xhtml_br = """To God all is beautiful, good, and as it should be.<br /> Man must see things as either good or bad."""
self.xhtml_hr = """To God all is beautiful, good, and as it should be.<hr /> Man must see things as either good or bad."""
self.nested_tags = """Having cut, <a href="http://example.com"><b>burned</b> and <font style="color: #CCC;">poisoned</font></a> the sick, the doctor then submits <strong>his bill</strong>."""
self.whitelisted_tags_in_blacklisted_tags = """Having cut, <font style="color: red;">burned and <em>poisoned</em></font> the sick, the doctor then submits his bill."""
self.unbalanced_tags = """<h1>Extinguish <q>pride <b>as</q> quickly</b> as you would a fire."""
self.ampersands = """To God all is beautiful, good, & as it should be."""
self.unknown_tags = """Law gives the people a <turkey gobble="http://example.com/">single will</turkey> to obey."""
def testSanitizedTags(self):
"""HTML tags are sanitized using a whitelist."""
result = publish.sanitizer.sanitize(self.basic_txt)
assert result == 'Change <em>alone</em> is unchanging.'
def testSanitizePlainText(self):
"""HTML sanitizer leaves plain text as is."""
result = publish.sanitizer.sanitize(self.plain_txt)
assert result == self.plain_txt
def testSanitizeLinks(self):
"""Links with safe URLs are preserved by the sanitizer."""
result = publish.sanitizer.sanitize(self.txt_with_attrs)
assert result == """Law gives the people a <a href="http://example.com/">single will</a> to obey."""
def testSanitizeTagsWIthEntities(self):
"""HTML entities are preserved by the HTML sanitizer and not double-encoded."""
result = publish.sanitizer.sanitize(self.txt_with_entities)
assert result == """<blockquote><p>I’ve seen Plato's cups & tables, but not his <i>cupness</i> & <i>tableness</i>.</p></blockquote>"""
def testSanitizeStyleTags(self):
"""HTML <style> tags are stripped by the sanitizer."""
result = publish.sanitizer.sanitize(self.style_tag)
assert result == "The same road goes both up and down."
def testSanitizeScriptTags(self):
"""HTML <script> tags are stripped by the sanitizer."""
result = publish.sanitizer.sanitize(self.script_tag)
assert result == "Men are not intellligent. The gods are intelligent."
def testSanitizeHtmlBrs(self):
"""Self-closed tags such as <br> are converted to <br /> by the sanitizer."""
result = publish.sanitizer.sanitize(self.html_br)
assert result == """To God all is beautiful, good, and as it should be.<br /> Man must see things as either good or bad."""
def testSanitizeHtmlHrs(self):
"""Self-closed tags such as <hr> are removed by the sanitizer."""
result = publish.sanitizer.sanitize(self.html_hr)
assert result == """To God all is beautiful, good, and as it should be. Man must see things as either good or bad."""
def testSanitizeXhtmlBrs(self):
"""Self-closed tags such as <br /> are preserved by the sanitizer."""
result = publish.sanitizer.sanitize(self.xhtml_br)
assert result == """To God all is beautiful, good, and as it should be.<br /> Man must see things as either good or bad."""
def testSanitizeXhtmlHrs(self):
"""Self-closed tags such as <hr /> are removed by the sanitizer."""
result = publish.sanitizer.sanitize(self.xhtml_hr)
assert result == """To God all is beautiful, good, and as it should be. Man must see things as either good or bad."""
def testSanitizeNestedTags(self):
"""Nested HTML tags are sanitized."""
result = publish.sanitizer.sanitize(self.nested_tags)
assert result == """Having cut, <a href="http://example.com"><b>burned</b> and poisoned</a> the sick, the doctor then submits <strong>his bill</strong>."""
def testSanitizeWhitelistedTagsInBlacklistedTags(self):
"""Whitelisted tags nested in non-whitelisted tags are preserved."""
result = publish.sanitizer.sanitize(self.whitelisted_tags_in_blacklisted_tags)
assert result == """Having cut, burned and <em>poisoned</em> the sick, the doctor then submits his bill."""
def testSanitizeUnbalancedTags(self):
"""Unbalanced HTML tags are sanitized and balanced."""
result = publish.sanitizer.sanitize(self.unbalanced_tags)
assert result == """Extinguish <q>pride <b>as</b></q> quickly as you would a fire."""
def testSanitizeAmpersands(self):
"""Ampersands are not encoded by the sanitizer."""
result = publish.sanitizer.sanitize(self.ampersands)
assert result == self.ampersands
def testSanitizeUnknownTags(self):
"""Unknown markup is removed by the sanitizer."""
result = publish.sanitizer.sanitize(self.unknown_tags)
assert result == """Law gives the people a single will to obey."""
class ShortenTestCases(unittest.TestCase):
def setUp(self):
self.txt = "there are five new tomato plants, all in new places; where they were all on the west row last year, now they're all on the south, with one in the west. we also planted new eggplant, salad burnet, flax, basil, and artichoke. the artichoke is on the opposite corner as last year, and the eggplant has moved south. they say you have to plan for succession planting, but when you've got the right friends, it really makes these things far simpler."
self.short_txt = "Why do you do me like you do?"
self.really_short_txt = "I wanna tell you one thing."
def testCountWords(self):
"""The number of words in a string can be correctly counted."""
count = publish.shorten.wc(self.txt)
assert count == 81
def testShortenText(self):
"""A string can be truncated to an arbitrary number of words."""
result = publish.shorten.shorten(self.txt, 10)
assert result == 'there are five new tomato plants, all in new places;…'
def testShortenShortTest(self):
"""Text that is right at the word limit is not shortened."""
result = publish.shorten.shorten(self.short_txt, 8)
assert result == self.short_txt
def testShortenReallyShortTest(self):
"""Text that is under the word limit is not shortened."""
result = publish.shorten.shorten(self.really_short_txt, 7)
assert result == self.really_short_txt
class TypogrifyTestCases(unittest.TestCase):
def testTypogrify(self):
"""The typogrify() function prepares text for fancy CSS."""
result = publish.typogrify.typogrify('<h2>"Jayhawks" & KU fans act extremely obnoxiously</h2>')
assert result == '<h2><span class="dquo">“</span>Jayhawks” <span class="amp">&</span> <span class="caps">KU</span> fans act extremely obnoxiously</h2>'
def testItsPowerLevelIs9000(self):
"""Dakota's bizarre phrase "IT'S POWER LEVEL IS 9000" must survive Typogrify."""
result = publish.typogrify.typogrify("IT'S POWER LEVEL IS 9000")
assert result == """<span class="caps">IT</span>’S <span class="caps">POWER</span> <span class="caps">LEVEL</span> <span class="caps">IS</span> 9000"""
class TypogrifyAmpTestCases(unittest.TestCase):
def testWrapAmp(self):
"""Ampersands are entity-encoded and wrapped in the 'amp' class."""
txt = 'One & two'
result = publish.typogrify.amp(txt)
assert result == 'One <span class="amp">&</span> two'
def testWrapEncodedAmp(self):
"""Ampersands that are already entity-encoded are not double-encoded."""
txt = 'One & two'
result = publish.typogrify.amp(txt)
assert result == 'One <span class="amp">&</span> two'
def testWrapNumericEncodedAmp(self):
"""Ampersands that are already numeric entity-encoded are not double-encoded."""
txt = 'One & two'
result = publish.typogrify.amp(txt)
assert result == 'One <span class="amp">&</span> two'
def testWrapAmpWithNbsp(self):
"""Ampersands that are surrounded by ' ' are properly handled."""
txt = 'One & two'
result = publish.typogrify.amp(txt)
assert result == 'One <span class="amp">&</span> two'
def testAlreadyWrappedAmp(self):
"""Ampersands that have already been processed aren't double-processed."""
txt = 'One <span class="amp">&</span> two'
result = publish.typogrify.amp(txt)
assert result == 'One <span class="amp">&</span> two'
def testAmpEncodedInUrl(self):
"""Ampersands already encoded in a URL are preserved."""
txt = '“this” & <a href="/?that&test">that</a>'
result = publish.typogrify.amp(txt)
assert result == '“this” <span class="amp">&</span> <a href="/?that&test">that</a>'
def testAmpInAttribute(self):
"""Ampersands in attribute values are ignored."""
txt = '<link href="xyz.html" title="One & Two">xyz</link>'
result = publish.typogrify.amp(txt)
assert result == '<link href="xyz.html" title="One & Two">xyz</link>'
class TypogrifyCapsTestCases(unittest.TestCase):
def testWrapsCaps(self):
"""Capital letters are typogrified."""
result = publish.typogrify.caps("A message from KU")
assert result == 'A message from <span class="caps">KU</span>'
def testDontWrapPre(self):
"""Capital letters in a <pre> block are not typogrified."""
result = publish.typogrify.caps("<PRE>CAPS</pre> more CAPS")
assert result == '<PRE>CAPS</pre> more <span class="caps">CAPS</span>'
def testWrapCapsWithNumbers(self):
"""Capital letters with numbers are typogrified."""
result = publish.typogrify.caps("A message from 2KU2 with digits")
assert result == 'A message from <span class="caps">2KU2</span> with digits'
def testDottedCapsWithSpaces(self):
"""The spaces following dotted caps are not typogrified."""
result = publish.typogrify.caps("Dotted caps followed by spaces should never include them in the wrap D.O.T. like so.")
assert result == 'Dotted caps followed by spaces should never include them in the wrap <span class="caps">D.O.T.</span> like so.'
def testCapsNestedInTags(self):
"""Capital letters nested in other tags are typogrified."""
result = publish.typogrify.caps("<i>D.O.T.</i>HE34T<b>RFID</b>")
assert result == '<i><span class="caps">D.O.T.</span></i><span class="caps">HE34T</span><b><span class="caps">RFID</span></b>'
def testCapsPossessivesAndContractions(self):
"""Capital letters in possessives and contractions are typogrified."""
result = publish.typogrify.caps("JACKIE'S DRUNKEN BOXING CAN'T BEAT MY KUNG FU")
assert result == """<span class="caps">JACKIE'S</span> <span class="caps">DRUNKEN</span> <span class="caps">BOXING</span> <span class="caps">CAN'T</span> <span class="caps">BEAT</span> <span class="caps">MY</span> <span class="caps">KUNG</span> <span class="caps">FU</span>"""
class TypogrifyInitialQuotesTestCases(unittest.TestCase):
def testInitialDoubleQuotes(self):
"""Initial double quotes are typogrified."""
result = publish.typogrify.initial_quotes('"With primes"')
assert result == '<span class="dquo">"</span>With primes"'
def testInitialSingleQuotes(self):
"""Initial single quotes are typogrified."""
result = publish.typogrify.initial_quotes("'With single primes'")
assert result == """<span class="quo">'</span>With single primes'"""
def testInitialDoubleQuotesWithLink(self):
"""Initial double quotes in a link are typogrified."""
result = publish.typogrify.initial_quotes('<a href="#">"With primes and a link"</a>')
assert result == '<a href="#"><span class="dquo">"</span>With primes and a link"</a>'
def testInitialSmartQuotes(self):
"""Initial smart quotes are typogrified."""
result = publish.typogrify.initial_quotes('“With smartypanted quotes”')
assert result == '<span class="dquo">“</span>With smartypanted quotes”'
class TypogrifySmartypantsTestCases(unittest.TestCase):
def testSmartypants(self):
"""ASCII punctuation is converted to 'smart' punctuation."""
result = publish.typogrify.smartypants('The "Green" man')
assert result == 'The “Green” man'
def testItsPowerLevelIs9000(self):
"""Dakota's bizarre phrase "IT'S POWER LEVEL IS 9000" must survive SmartyPants."""
result = publish.typogrify.smartypants("IT'S POWER LEVEL IS 9000")
assert result == "IT’S POWER LEVEL IS 9000"
class TypogrifyWidontTestCases(unittest.TestCase):
def testWidont(self):
"""Textual widows are prevented."""
result = publish.typogrify.widont('A very simple test')
assert result == 'A very simple test'
def testWidontSingleWord(self):
"""Widont processing is skipped for single-word strings."""
result = publish.typogrify.widont('Test')
assert result == 'Test'
def testWidontInitialSpace(self):
"""Widont processing is skipped for single words preceded by a space."""
result = publish.typogrify.widont(' Test')
assert result == ' Test'
def testWidontSingleWordInTags(self):
"""Widont processing is skipped for single-word strings in markup."""
result = publish.typogrify.widont('<ul><li>Test</p></li><ul>')
assert result == '<ul><li>Test</p></li><ul>'
def testWidont04(self):
"""Describe what the test does here."""
result = publish.typogrify.widont('<ul><li> Test</p></li><ul>')
assert result == '<ul><li> Test</p></li><ul>'
def testWidont05(self):
"""Describe what the test does here."""
result = publish.typogrify.widont('<p>In a couple of paragraphs</p><p>paragraph two</p>')
assert result == '<p>In a couple of paragraphs</p><p>paragraph two</p>'
def testWidont06(self):
"""Describe what the test does here."""
result = publish.typogrify.widont('<h1><a href="#">In a link inside a heading</i> </a></h1>')
assert result == '<h1><a href="#">In a link inside a heading</i> </a></h1>'
def testWidont07(self):
"""Describe what the test does here."""
result = publish.typogrify.widont('<h1><a href="#">In a link</a> followed by other text</h1>')
assert result == '<h1><a href="#">In a link</a> followed by other text</h1>'
def testWidont08(self):
"""Describe what the test does here."""
result = publish.typogrify.widont('<h1><a href="#"></a></h1>')
assert result == '<h1><a href="#"></a></h1>'
def testWidont09(self):
"""Describe what the test does here."""
result = publish.typogrify.widont('<div>Divs get no love!</div>')
assert result == '<div>Divs get no love!</div>'
def testWidont10(self):
"""Describe what the test does here."""
result = publish.typogrify.widont('<pre>Neither do PREs</pre>')
assert result == '<pre>Neither do PREs</pre>'
def testWidont11(self):
"""Describe what the test does here."""
result = publish.typogrify.widont('<div><p>But divs with paragraphs do!</p></div>')
assert result == '<div><p>But divs with paragraphs do!</p></div>'
if __name__ == '__main__':
unittest.main()