• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#
2# Test suite for the textwrap module.
3#
4# Original tests written by Greg Ward <gward@python.net>.
5# Converted to PyUnit by Peter Hansen <peter@engcorp.com>.
6# Currently maintained by Greg Ward.
7#
8# $Id$
9#
10
11import unittest
12
13from textwrap import TextWrapper, wrap, fill, dedent, indent, shorten
14
15
16class BaseTestCase(unittest.TestCase):
17    '''Parent class with utility methods for textwrap tests.'''
18
19    def show(self, textin):
20        if isinstance(textin, list):
21            result = []
22            for i in range(len(textin)):
23                result.append("  %d: %r" % (i, textin[i]))
24            result = "\n".join(result) if result else "  no lines"
25        elif isinstance(textin, str):
26            result = "  %s\n" % repr(textin)
27        return result
28
29
30    def check(self, result, expect):
31        self.assertEqual(result, expect,
32            'expected:\n%s\nbut got:\n%s' % (
33                self.show(expect), self.show(result)))
34
35    def check_wrap(self, text, width, expect, **kwargs):
36        result = wrap(text, width, **kwargs)
37        self.check(result, expect)
38
39    def check_split(self, text, expect):
40        result = self.wrapper._split(text)
41        self.assertEqual(result, expect,
42                         "\nexpected %r\n"
43                         "but got  %r" % (expect, result))
44
45
46class WrapTestCase(BaseTestCase):
47
48    def setUp(self):
49        self.wrapper = TextWrapper(width=45)
50
51    def test_simple(self):
52        # Simple case: just words, spaces, and a bit of punctuation
53
54        text = "Hello there, how are you this fine day?  I'm glad to hear it!"
55
56        self.check_wrap(text, 12,
57                        ["Hello there,",
58                         "how are you",
59                         "this fine",
60                         "day?  I'm",
61                         "glad to hear",
62                         "it!"])
63        self.check_wrap(text, 42,
64                        ["Hello there, how are you this fine day?",
65                         "I'm glad to hear it!"])
66        self.check_wrap(text, 80, [text])
67
68    def test_empty_string(self):
69        # Check that wrapping the empty string returns an empty list.
70        self.check_wrap("", 6, [])
71        self.check_wrap("", 6, [], drop_whitespace=False)
72
73    def test_empty_string_with_initial_indent(self):
74        # Check that the empty string is not indented.
75        self.check_wrap("", 6, [], initial_indent="++")
76        self.check_wrap("", 6, [], initial_indent="++", drop_whitespace=False)
77
78    def test_whitespace(self):
79        # Whitespace munging and end-of-sentence detection
80
81        text = """\
82This is a paragraph that already has
83line breaks.  But some of its lines are much longer than the others,
84so it needs to be wrapped.
85Some lines are \ttabbed too.
86What a mess!
87"""
88
89        expect = ["This is a paragraph that already has line",
90                  "breaks.  But some of its lines are much",
91                  "longer than the others, so it needs to be",
92                  "wrapped.  Some lines are  tabbed too.  What a",
93                  "mess!"]
94
95        wrapper = TextWrapper(45, fix_sentence_endings=True)
96        result = wrapper.wrap(text)
97        self.check(result, expect)
98
99        result = wrapper.fill(text)
100        self.check(result, '\n'.join(expect))
101
102        text = "\tTest\tdefault\t\ttabsize."
103        expect = ["        Test    default         tabsize."]
104        self.check_wrap(text, 80, expect)
105
106        text = "\tTest\tcustom\t\ttabsize."
107        expect = ["    Test    custom      tabsize."]
108        self.check_wrap(text, 80, expect, tabsize=4)
109
110    def test_fix_sentence_endings(self):
111        wrapper = TextWrapper(60, fix_sentence_endings=True)
112
113        # SF #847346: ensure that fix_sentence_endings=True does the
114        # right thing even on input short enough that it doesn't need to
115        # be wrapped.
116        text = "A short line. Note the single space."
117        expect = ["A short line.  Note the single space."]
118        self.check(wrapper.wrap(text), expect)
119
120        # Test some of the hairy end cases that _fix_sentence_endings()
121        # is supposed to handle (the easy stuff is tested in
122        # test_whitespace() above).
123        text = "Well, Doctor? What do you think?"
124        expect = ["Well, Doctor?  What do you think?"]
125        self.check(wrapper.wrap(text), expect)
126
127        text = "Well, Doctor?\nWhat do you think?"
128        self.check(wrapper.wrap(text), expect)
129
130        text = 'I say, chaps! Anyone for "tennis?"\nHmmph!'
131        expect = ['I say, chaps!  Anyone for "tennis?"  Hmmph!']
132        self.check(wrapper.wrap(text), expect)
133
134        wrapper.width = 20
135        expect = ['I say, chaps!', 'Anyone for "tennis?"', 'Hmmph!']
136        self.check(wrapper.wrap(text), expect)
137
138        text = 'And she said, "Go to hell!"\nCan you believe that?'
139        expect = ['And she said, "Go to',
140                  'hell!"  Can you',
141                  'believe that?']
142        self.check(wrapper.wrap(text), expect)
143
144        wrapper.width = 60
145        expect = ['And she said, "Go to hell!"  Can you believe that?']
146        self.check(wrapper.wrap(text), expect)
147
148        text = 'File stdio.h is nice.'
149        expect = ['File stdio.h is nice.']
150        self.check(wrapper.wrap(text), expect)
151
152    def test_wrap_short(self):
153        # Wrapping to make short lines longer
154
155        text = "This is a\nshort paragraph."
156
157        self.check_wrap(text, 20, ["This is a short",
158                                   "paragraph."])
159        self.check_wrap(text, 40, ["This is a short paragraph."])
160
161
162    def test_wrap_short_1line(self):
163        # Test endcases
164
165        text = "This is a short line."
166
167        self.check_wrap(text, 30, ["This is a short line."])
168        self.check_wrap(text, 30, ["(1) This is a short line."],
169                        initial_indent="(1) ")
170
171
172    def test_hyphenated(self):
173        # Test breaking hyphenated words
174
175        text = ("this-is-a-useful-feature-for-"
176                "reformatting-posts-from-tim-peters'ly")
177
178        self.check_wrap(text, 40,
179                        ["this-is-a-useful-feature-for-",
180                         "reformatting-posts-from-tim-peters'ly"])
181        self.check_wrap(text, 41,
182                        ["this-is-a-useful-feature-for-",
183                         "reformatting-posts-from-tim-peters'ly"])
184        self.check_wrap(text, 42,
185                        ["this-is-a-useful-feature-for-reformatting-",
186                         "posts-from-tim-peters'ly"])
187        # The test tests current behavior but is not testing parts of the API.
188        expect = ("this-|is-|a-|useful-|feature-|for-|"
189                  "reformatting-|posts-|from-|tim-|peters'ly").split('|')
190        self.check_wrap(text, 1, expect, break_long_words=False)
191        self.check_split(text, expect)
192
193        self.check_split('e-mail', ['e-mail'])
194        self.check_split('Jelly-O', ['Jelly-O'])
195        # The test tests current behavior but is not testing parts of the API.
196        self.check_split('half-a-crown', 'half-|a-|crown'.split('|'))
197
198    def test_hyphenated_numbers(self):
199        # Test that hyphenated numbers (eg. dates) are not broken like words.
200        text = ("Python 1.0.0 was released on 1994-01-26.  Python 1.0.1 was\n"
201                "released on 1994-02-15.")
202
203        self.check_wrap(text, 30, ['Python 1.0.0 was released on',
204                                   '1994-01-26.  Python 1.0.1 was',
205                                   'released on 1994-02-15.'])
206        self.check_wrap(text, 40, ['Python 1.0.0 was released on 1994-01-26.',
207                                   'Python 1.0.1 was released on 1994-02-15.'])
208        self.check_wrap(text, 1, text.split(), break_long_words=False)
209
210        text = "I do all my shopping at 7-11."
211        self.check_wrap(text, 25, ["I do all my shopping at",
212                                   "7-11."])
213        self.check_wrap(text, 27, ["I do all my shopping at",
214                                   "7-11."])
215        self.check_wrap(text, 29, ["I do all my shopping at 7-11."])
216        self.check_wrap(text, 1, text.split(), break_long_words=False)
217
218    def test_em_dash(self):
219        # Test text with em-dashes
220        text = "Em-dashes should be written -- thus."
221        self.check_wrap(text, 25,
222                        ["Em-dashes should be",
223                         "written -- thus."])
224
225        # Probe the boundaries of the properly written em-dash,
226        # ie. " -- ".
227        self.check_wrap(text, 29,
228                        ["Em-dashes should be written",
229                         "-- thus."])
230        expect = ["Em-dashes should be written --",
231                  "thus."]
232        self.check_wrap(text, 30, expect)
233        self.check_wrap(text, 35, expect)
234        self.check_wrap(text, 36,
235                        ["Em-dashes should be written -- thus."])
236
237        # The improperly written em-dash is handled too, because
238        # it's adjacent to non-whitespace on both sides.
239        text = "You can also do--this or even---this."
240        expect = ["You can also do",
241                  "--this or even",
242                  "---this."]
243        self.check_wrap(text, 15, expect)
244        self.check_wrap(text, 16, expect)
245        expect = ["You can also do--",
246                  "this or even---",
247                  "this."]
248        self.check_wrap(text, 17, expect)
249        self.check_wrap(text, 19, expect)
250        expect = ["You can also do--this or even",
251                  "---this."]
252        self.check_wrap(text, 29, expect)
253        self.check_wrap(text, 31, expect)
254        expect = ["You can also do--this or even---",
255                  "this."]
256        self.check_wrap(text, 32, expect)
257        self.check_wrap(text, 35, expect)
258
259        # All of the above behaviour could be deduced by probing the
260        # _split() method.
261        text = "Here's an -- em-dash and--here's another---and another!"
262        expect = ["Here's", " ", "an", " ", "--", " ", "em-", "dash", " ",
263                  "and", "--", "here's", " ", "another", "---",
264                  "and", " ", "another!"]
265        self.check_split(text, expect)
266
267        text = "and then--bam!--he was gone"
268        expect = ["and", " ", "then", "--", "bam!", "--",
269                  "he", " ", "was", " ", "gone"]
270        self.check_split(text, expect)
271
272
273    def test_unix_options (self):
274        # Test that Unix-style command-line options are wrapped correctly.
275        # Both Optik (OptionParser) and Docutils rely on this behaviour!
276
277        text = "You should use the -n option, or --dry-run in its long form."
278        self.check_wrap(text, 20,
279                        ["You should use the",
280                         "-n option, or --dry-",
281                         "run in its long",
282                         "form."])
283        self.check_wrap(text, 21,
284                        ["You should use the -n",
285                         "option, or --dry-run",
286                         "in its long form."])
287        expect = ["You should use the -n option, or",
288                  "--dry-run in its long form."]
289        self.check_wrap(text, 32, expect)
290        self.check_wrap(text, 34, expect)
291        self.check_wrap(text, 35, expect)
292        self.check_wrap(text, 38, expect)
293        expect = ["You should use the -n option, or --dry-",
294                  "run in its long form."]
295        self.check_wrap(text, 39, expect)
296        self.check_wrap(text, 41, expect)
297        expect = ["You should use the -n option, or --dry-run",
298                  "in its long form."]
299        self.check_wrap(text, 42, expect)
300
301        # Again, all of the above can be deduced from _split().
302        text = "the -n option, or --dry-run or --dryrun"
303        expect = ["the", " ", "-n", " ", "option,", " ", "or", " ",
304                  "--dry-", "run", " ", "or", " ", "--dryrun"]
305        self.check_split(text, expect)
306
307    def test_funky_hyphens (self):
308        # Screwy edge cases cooked up by David Goodger.  All reported
309        # in SF bug #596434.
310        self.check_split("what the--hey!", ["what", " ", "the", "--", "hey!"])
311        self.check_split("what the--", ["what", " ", "the--"])
312        self.check_split("what the--.", ["what", " ", "the--."])
313        self.check_split("--text--.", ["--text--."])
314
315        # When I first read bug #596434, this is what I thought David
316        # was talking about.  I was wrong; these have always worked
317        # fine.  The real problem is tested in test_funky_parens()
318        # below...
319        self.check_split("--option", ["--option"])
320        self.check_split("--option-opt", ["--option-", "opt"])
321        self.check_split("foo --option-opt bar",
322                         ["foo", " ", "--option-", "opt", " ", "bar"])
323
324    def test_punct_hyphens(self):
325        # Oh bother, SF #965425 found another problem with hyphens --
326        # hyphenated words in single quotes weren't handled correctly.
327        # In fact, the bug is that *any* punctuation around a hyphenated
328        # word was handled incorrectly, except for a leading "--", which
329        # was special-cased for Optik and Docutils.  So test a variety
330        # of styles of punctuation around a hyphenated word.
331        # (Actually this is based on an Optik bug report, #813077).
332        self.check_split("the 'wibble-wobble' widget",
333                         ['the', ' ', "'wibble-", "wobble'", ' ', 'widget'])
334        self.check_split('the "wibble-wobble" widget',
335                         ['the', ' ', '"wibble-', 'wobble"', ' ', 'widget'])
336        self.check_split("the (wibble-wobble) widget",
337                         ['the', ' ', "(wibble-", "wobble)", ' ', 'widget'])
338        self.check_split("the ['wibble-wobble'] widget",
339                         ['the', ' ', "['wibble-", "wobble']", ' ', 'widget'])
340
341        # The test tests current behavior but is not testing parts of the API.
342        self.check_split("what-d'you-call-it.",
343                         "what-d'you-|call-|it.".split('|'))
344
345    def test_funky_parens (self):
346        # Second part of SF bug #596434: long option strings inside
347        # parentheses.
348        self.check_split("foo (--option) bar",
349                         ["foo", " ", "(--option)", " ", "bar"])
350
351        # Related stuff -- make sure parens work in simpler contexts.
352        self.check_split("foo (bar) baz",
353                         ["foo", " ", "(bar)", " ", "baz"])
354        self.check_split("blah (ding dong), wubba",
355                         ["blah", " ", "(ding", " ", "dong),",
356                          " ", "wubba"])
357
358    def test_drop_whitespace_false(self):
359        # Check that drop_whitespace=False preserves whitespace.
360        # SF patch #1581073
361        text = " This is a    sentence with     much whitespace."
362        self.check_wrap(text, 10,
363                        [" This is a", "    ", "sentence ",
364                         "with     ", "much white", "space."],
365                        drop_whitespace=False)
366
367    def test_drop_whitespace_false_whitespace_only(self):
368        # Check that drop_whitespace=False preserves a whitespace-only string.
369        self.check_wrap("   ", 6, ["   "], drop_whitespace=False)
370
371    def test_drop_whitespace_false_whitespace_only_with_indent(self):
372        # Check that a whitespace-only string gets indented (when
373        # drop_whitespace is False).
374        self.check_wrap("   ", 6, ["     "], drop_whitespace=False,
375                        initial_indent="  ")
376
377    def test_drop_whitespace_whitespace_only(self):
378        # Check drop_whitespace on a whitespace-only string.
379        self.check_wrap("  ", 6, [])
380
381    def test_drop_whitespace_leading_whitespace(self):
382        # Check that drop_whitespace does not drop leading whitespace (if
383        # followed by non-whitespace).
384        # SF bug #622849 reported inconsistent handling of leading
385        # whitespace; let's test that a bit, shall we?
386        text = " This is a sentence with leading whitespace."
387        self.check_wrap(text, 50,
388                        [" This is a sentence with leading whitespace."])
389        self.check_wrap(text, 30,
390                        [" This is a sentence with", "leading whitespace."])
391
392    def test_drop_whitespace_whitespace_line(self):
393        # Check that drop_whitespace skips the whole line if a non-leading
394        # line consists only of whitespace.
395        text = "abcd    efgh"
396        # Include the result for drop_whitespace=False for comparison.
397        self.check_wrap(text, 6, ["abcd", "    ", "efgh"],
398                        drop_whitespace=False)
399        self.check_wrap(text, 6, ["abcd", "efgh"])
400
401    def test_drop_whitespace_whitespace_only_with_indent(self):
402        # Check that initial_indent is not applied to a whitespace-only
403        # string.  This checks a special case of the fact that dropping
404        # whitespace occurs before indenting.
405        self.check_wrap("  ", 6, [], initial_indent="++")
406
407    def test_drop_whitespace_whitespace_indent(self):
408        # Check that drop_whitespace does not drop whitespace indents.
409        # This checks a special case of the fact that dropping whitespace
410        # occurs before indenting.
411        self.check_wrap("abcd efgh", 6, ["  abcd", "  efgh"],
412                        initial_indent="  ", subsequent_indent="  ")
413
414    def test_split(self):
415        # Ensure that the standard _split() method works as advertised
416        # in the comments
417
418        text = "Hello there -- you goof-ball, use the -b option!"
419
420        result = self.wrapper._split(text)
421        self.check(result,
422             ["Hello", " ", "there", " ", "--", " ", "you", " ", "goof-",
423              "ball,", " ", "use", " ", "the", " ", "-b", " ",  "option!"])
424
425    def test_break_on_hyphens(self):
426        # Ensure that the break_on_hyphens attributes work
427        text = "yaba daba-doo"
428        self.check_wrap(text, 10, ["yaba daba-", "doo"],
429                        break_on_hyphens=True)
430        self.check_wrap(text, 10, ["yaba", "daba-doo"],
431                        break_on_hyphens=False)
432
433    def test_bad_width(self):
434        # Ensure that width <= 0 is caught.
435        text = "Whatever, it doesn't matter."
436        self.assertRaises(ValueError, wrap, text, 0)
437        self.assertRaises(ValueError, wrap, text, -1)
438
439    def test_no_split_at_umlaut(self):
440        text = "Die Empf\xe4nger-Auswahl"
441        self.check_wrap(text, 13, ["Die", "Empf\xe4nger-", "Auswahl"])
442
443    def test_umlaut_followed_by_dash(self):
444        text = "aa \xe4\xe4-\xe4\xe4"
445        self.check_wrap(text, 7, ["aa \xe4\xe4-", "\xe4\xe4"])
446
447    def test_non_breaking_space(self):
448        text = 'This is a sentence with non-breaking\N{NO-BREAK SPACE}space.'
449
450        self.check_wrap(text, 20,
451                        ['This is a sentence',
452                         'with non-',
453                         'breaking\N{NO-BREAK SPACE}space.'],
454                        break_on_hyphens=True)
455
456        self.check_wrap(text, 20,
457                        ['This is a sentence',
458                         'with',
459                         'non-breaking\N{NO-BREAK SPACE}space.'],
460                        break_on_hyphens=False)
461
462    def test_narrow_non_breaking_space(self):
463        text = ('This is a sentence with non-breaking'
464                '\N{NARROW NO-BREAK SPACE}space.')
465
466        self.check_wrap(text, 20,
467                        ['This is a sentence',
468                         'with non-',
469                         'breaking\N{NARROW NO-BREAK SPACE}space.'],
470                        break_on_hyphens=True)
471
472        self.check_wrap(text, 20,
473                        ['This is a sentence',
474                         'with',
475                         'non-breaking\N{NARROW NO-BREAK SPACE}space.'],
476                        break_on_hyphens=False)
477
478
479class MaxLinesTestCase(BaseTestCase):
480    text = "Hello there, how are you this fine day?  I'm glad to hear it!"
481
482    def test_simple(self):
483        self.check_wrap(self.text, 12,
484                        ["Hello [...]"],
485                        max_lines=0)
486        self.check_wrap(self.text, 12,
487                        ["Hello [...]"],
488                        max_lines=1)
489        self.check_wrap(self.text, 12,
490                        ["Hello there,",
491                         "how [...]"],
492                        max_lines=2)
493        self.check_wrap(self.text, 13,
494                        ["Hello there,",
495                         "how are [...]"],
496                        max_lines=2)
497        self.check_wrap(self.text, 80, [self.text], max_lines=1)
498        self.check_wrap(self.text, 12,
499                        ["Hello there,",
500                         "how are you",
501                         "this fine",
502                         "day?  I'm",
503                         "glad to hear",
504                         "it!"],
505                        max_lines=6)
506
507    def test_spaces(self):
508        # strip spaces before placeholder
509        self.check_wrap(self.text, 12,
510                        ["Hello there,",
511                         "how are you",
512                         "this fine",
513                         "day? [...]"],
514                        max_lines=4)
515        # placeholder at the start of line
516        self.check_wrap(self.text, 6,
517                        ["Hello",
518                         "[...]"],
519                        max_lines=2)
520        # final spaces
521        self.check_wrap(self.text + ' ' * 10, 12,
522                        ["Hello there,",
523                         "how are you",
524                         "this fine",
525                         "day?  I'm",
526                         "glad to hear",
527                         "it!"],
528                        max_lines=6)
529
530    def test_placeholder(self):
531        self.check_wrap(self.text, 12,
532                        ["Hello..."],
533                        max_lines=1,
534                        placeholder='...')
535        self.check_wrap(self.text, 12,
536                        ["Hello there,",
537                         "how are..."],
538                        max_lines=2,
539                        placeholder='...')
540        # long placeholder and indentation
541        with self.assertRaises(ValueError):
542            wrap(self.text, 16, initial_indent='    ',
543                 max_lines=1, placeholder=' [truncated]...')
544        with self.assertRaises(ValueError):
545            wrap(self.text, 16, subsequent_indent='    ',
546                 max_lines=2, placeholder=' [truncated]...')
547        self.check_wrap(self.text, 16,
548                        ["    Hello there,",
549                         "  [truncated]..."],
550                        max_lines=2,
551                        initial_indent='    ',
552                        subsequent_indent='  ',
553                        placeholder=' [truncated]...')
554        self.check_wrap(self.text, 16,
555                        ["  [truncated]..."],
556                        max_lines=1,
557                        initial_indent='  ',
558                        subsequent_indent='    ',
559                        placeholder=' [truncated]...')
560        self.check_wrap(self.text, 80, [self.text], placeholder='.' * 1000)
561
562    def test_placeholder_backtrack(self):
563        # Test special case when max_lines insufficient, but what
564        # would be last wrapped line so long the placeholder cannot
565        # be added there without violence. So, textwrap backtracks,
566        # adding placeholder to the penultimate line.
567        text = 'Good grief Python features are advancing quickly!'
568        self.check_wrap(text, 12,
569                        ['Good grief', 'Python*****'],
570                        max_lines=3,
571                        placeholder='*****')
572
573
574class LongWordTestCase (BaseTestCase):
575    def setUp(self):
576        self.wrapper = TextWrapper()
577        self.text = '''\
578Did you say "supercalifragilisticexpialidocious?"
579How *do* you spell that odd word, anyways?
580'''
581
582    def test_break_long(self):
583        # Wrap text with long words and lots of punctuation
584
585        self.check_wrap(self.text, 30,
586                        ['Did you say "supercalifragilis',
587                         'ticexpialidocious?" How *do*',
588                         'you spell that odd word,',
589                         'anyways?'])
590        self.check_wrap(self.text, 50,
591                        ['Did you say "supercalifragilisticexpialidocious?"',
592                         'How *do* you spell that odd word, anyways?'])
593
594        # SF bug 797650.  Prevent an infinite loop by making sure that at
595        # least one character gets split off on every pass.
596        self.check_wrap('-'*10+'hello', 10,
597                        ['----------',
598                         '               h',
599                         '               e',
600                         '               l',
601                         '               l',
602                         '               o'],
603                        subsequent_indent = ' '*15)
604
605        # bug 1146.  Prevent a long word to be wrongly wrapped when the
606        # preceding word is exactly one character shorter than the width
607        self.check_wrap(self.text, 12,
608                        ['Did you say ',
609                         '"supercalifr',
610                         'agilisticexp',
611                         'ialidocious?',
612                         '" How *do*',
613                         'you spell',
614                         'that odd',
615                         'word,',
616                         'anyways?'])
617
618    def test_nobreak_long(self):
619        # Test with break_long_words disabled
620        self.wrapper.break_long_words = 0
621        self.wrapper.width = 30
622        expect = ['Did you say',
623                  '"supercalifragilisticexpialidocious?"',
624                  'How *do* you spell that odd',
625                  'word, anyways?'
626                  ]
627        result = self.wrapper.wrap(self.text)
628        self.check(result, expect)
629
630        # Same thing with kwargs passed to standalone wrap() function.
631        result = wrap(self.text, width=30, break_long_words=0)
632        self.check(result, expect)
633
634    def test_max_lines_long(self):
635        self.check_wrap(self.text, 12,
636                        ['Did you say ',
637                         '"supercalifr',
638                         'agilisticexp',
639                         '[...]'],
640                        max_lines=4)
641
642
643class LongWordWithHyphensTestCase(BaseTestCase):
644    def setUp(self):
645        self.wrapper = TextWrapper()
646        self.text1 = '''\
647We used enyzme 2-succinyl-6-hydroxy-2,4-cyclohexadiene-1-carboxylate synthase.
648'''
649        self.text2 = '''\
6501234567890-1234567890--this_is_a_very_long_option_indeed-good-bye"
651'''
652
653    def test_break_long_words_on_hyphen(self):
654        expected = ['We used enyzme 2-succinyl-6-hydroxy-2,4-',
655                    'cyclohexadiene-1-carboxylate synthase.']
656        self.check_wrap(self.text1, 50, expected)
657
658        expected = ['We used', 'enyzme 2-', 'succinyl-', '6-hydroxy-', '2,4-',
659                    'cyclohexad', 'iene-1-', 'carboxylat', 'e', 'synthase.']
660        self.check_wrap(self.text1, 10, expected)
661
662        expected = ['1234567890',  '-123456789', '0--this_is', '_a_very_lo',
663                    'ng_option_', 'indeed-', 'good-bye"']
664        self.check_wrap(self.text2, 10, expected)
665
666    def test_break_long_words_not_on_hyphen(self):
667        expected = ['We used enyzme 2-succinyl-6-hydroxy-2,4-cyclohexad',
668                    'iene-1-carboxylate synthase.']
669        self.check_wrap(self.text1, 50, expected, break_on_hyphens=False)
670
671        expected = ['We used', 'enyzme 2-s', 'uccinyl-6-', 'hydroxy-2,',
672                    '4-cyclohex', 'adiene-1-c', 'arboxylate', 'synthase.']
673        self.check_wrap(self.text1, 10, expected, break_on_hyphens=False)
674
675        expected = ['1234567890',  '-123456789', '0--this_is', '_a_very_lo',
676                    'ng_option_', 'indeed-', 'good-bye"']
677        self.check_wrap(self.text2, 10, expected)
678
679    def test_break_on_hyphen_but_not_long_words(self):
680        expected = ['We used enyzme',
681                    '2-succinyl-6-hydroxy-2,4-cyclohexadiene-1-carboxylate',
682                    'synthase.']
683
684        self.check_wrap(self.text1, 50, expected, break_long_words=False)
685
686        expected = ['We used', 'enyzme',
687                    '2-succinyl-6-hydroxy-2,4-cyclohexadiene-1-carboxylate',
688                    'synthase.']
689        self.check_wrap(self.text1, 10, expected, break_long_words=False)
690
691        expected = ['1234567890',  '-123456789', '0--this_is', '_a_very_lo',
692                    'ng_option_', 'indeed-', 'good-bye"']
693        self.check_wrap(self.text2, 10, expected)
694
695
696    def test_do_not_break_long_words_or_on_hyphens(self):
697        expected = ['We used enyzme',
698                    '2-succinyl-6-hydroxy-2,4-cyclohexadiene-1-carboxylate',
699                    'synthase.']
700        self.check_wrap(self.text1, 50, expected,
701                        break_long_words=False,
702                        break_on_hyphens=False)
703
704        expected = ['We used', 'enyzme',
705                    '2-succinyl-6-hydroxy-2,4-cyclohexadiene-1-carboxylate',
706                    'synthase.']
707        self.check_wrap(self.text1, 10, expected,
708                        break_long_words=False,
709                        break_on_hyphens=False)
710
711        expected = ['1234567890',  '-123456789', '0--this_is', '_a_very_lo',
712                    'ng_option_', 'indeed-', 'good-bye"']
713        self.check_wrap(self.text2, 10, expected)
714
715class IndentTestCases(BaseTestCase):
716
717    # called before each test method
718    def setUp(self):
719        self.text = '''\
720This paragraph will be filled, first without any indentation,
721and then with some (including a hanging indent).'''
722
723
724    def test_fill(self):
725        # Test the fill() method
726
727        expect = '''\
728This paragraph will be filled, first
729without any indentation, and then with
730some (including a hanging indent).'''
731
732        result = fill(self.text, 40)
733        self.check(result, expect)
734
735
736    def test_initial_indent(self):
737        # Test initial_indent parameter
738
739        expect = ["     This paragraph will be filled,",
740                  "first without any indentation, and then",
741                  "with some (including a hanging indent)."]
742        result = wrap(self.text, 40, initial_indent="     ")
743        self.check(result, expect)
744
745        expect = "\n".join(expect)
746        result = fill(self.text, 40, initial_indent="     ")
747        self.check(result, expect)
748
749
750    def test_subsequent_indent(self):
751        # Test subsequent_indent parameter
752
753        expect = '''\
754  * This paragraph will be filled, first
755    without any indentation, and then
756    with some (including a hanging
757    indent).'''
758
759        result = fill(self.text, 40,
760                      initial_indent="  * ", subsequent_indent="    ")
761        self.check(result, expect)
762
763
764# Despite the similar names, DedentTestCase is *not* the inverse
765# of IndentTestCase!
766class DedentTestCase(unittest.TestCase):
767
768    def assertUnchanged(self, text):
769        """assert that dedent() has no effect on 'text'"""
770        self.assertEqual(text, dedent(text))
771
772    def test_dedent_nomargin(self):
773        # No lines indented.
774        text = "Hello there.\nHow are you?\nOh good, I'm glad."
775        self.assertUnchanged(text)
776
777        # Similar, with a blank line.
778        text = "Hello there.\n\nBoo!"
779        self.assertUnchanged(text)
780
781        # Some lines indented, but overall margin is still zero.
782        text = "Hello there.\n  This is indented."
783        self.assertUnchanged(text)
784
785        # Again, add a blank line.
786        text = "Hello there.\n\n  Boo!\n"
787        self.assertUnchanged(text)
788
789    def test_dedent_even(self):
790        # All lines indented by two spaces.
791        text = "  Hello there.\n  How are ya?\n  Oh good."
792        expect = "Hello there.\nHow are ya?\nOh good."
793        self.assertEqual(expect, dedent(text))
794
795        # Same, with blank lines.
796        text = "  Hello there.\n\n  How are ya?\n  Oh good.\n"
797        expect = "Hello there.\n\nHow are ya?\nOh good.\n"
798        self.assertEqual(expect, dedent(text))
799
800        # Now indent one of the blank lines.
801        text = "  Hello there.\n  \n  How are ya?\n  Oh good.\n"
802        expect = "Hello there.\n\nHow are ya?\nOh good.\n"
803        self.assertEqual(expect, dedent(text))
804
805    def test_dedent_uneven(self):
806        # Lines indented unevenly.
807        text = '''\
808        def foo():
809            while 1:
810                return foo
811        '''
812        expect = '''\
813def foo():
814    while 1:
815        return foo
816'''
817        self.assertEqual(expect, dedent(text))
818
819        # Uneven indentation with a blank line.
820        text = "  Foo\n    Bar\n\n   Baz\n"
821        expect = "Foo\n  Bar\n\n Baz\n"
822        self.assertEqual(expect, dedent(text))
823
824        # Uneven indentation with a whitespace-only line.
825        text = "  Foo\n    Bar\n \n   Baz\n"
826        expect = "Foo\n  Bar\n\n Baz\n"
827        self.assertEqual(expect, dedent(text))
828
829    def test_dedent_declining(self):
830        # Uneven indentation with declining indent level.
831        text = "     Foo\n    Bar\n"  # 5 spaces, then 4
832        expect = " Foo\nBar\n"
833        self.assertEqual(expect, dedent(text))
834
835        # Declining indent level with blank line.
836        text = "     Foo\n\n    Bar\n"  # 5 spaces, blank, then 4
837        expect = " Foo\n\nBar\n"
838        self.assertEqual(expect, dedent(text))
839
840        # Declining indent level with whitespace only line.
841        text = "     Foo\n    \n    Bar\n"  # 5 spaces, then 4, then 4
842        expect = " Foo\n\nBar\n"
843        self.assertEqual(expect, dedent(text))
844
845    # dedent() should not mangle internal tabs
846    def test_dedent_preserve_internal_tabs(self):
847        text = "  hello\tthere\n  how are\tyou?"
848        expect = "hello\tthere\nhow are\tyou?"
849        self.assertEqual(expect, dedent(text))
850
851        # make sure that it preserves tabs when it's not making any
852        # changes at all
853        self.assertEqual(expect, dedent(expect))
854
855    # dedent() should not mangle tabs in the margin (i.e.
856    # tabs and spaces both count as margin, but are *not*
857    # considered equivalent)
858    def test_dedent_preserve_margin_tabs(self):
859        text = "  hello there\n\thow are you?"
860        self.assertUnchanged(text)
861
862        # same effect even if we have 8 spaces
863        text = "        hello there\n\thow are you?"
864        self.assertUnchanged(text)
865
866        # dedent() only removes whitespace that can be uniformly removed!
867        text = "\thello there\n\thow are you?"
868        expect = "hello there\nhow are you?"
869        self.assertEqual(expect, dedent(text))
870
871        text = "  \thello there\n  \thow are you?"
872        self.assertEqual(expect, dedent(text))
873
874        text = "  \t  hello there\n  \t  how are you?"
875        self.assertEqual(expect, dedent(text))
876
877        text = "  \thello there\n  \t  how are you?"
878        expect = "hello there\n  how are you?"
879        self.assertEqual(expect, dedent(text))
880
881        # test margin is smaller than smallest indent
882        text = "  \thello there\n   \thow are you?\n \tI'm fine, thanks"
883        expect = " \thello there\n  \thow are you?\n\tI'm fine, thanks"
884        self.assertEqual(expect, dedent(text))
885
886
887# Test textwrap.indent
888class IndentTestCase(unittest.TestCase):
889    # The examples used for tests. If any of these change, the expected
890    # results in the various test cases must also be updated.
891    # The roundtrip cases are separate, because textwrap.dedent doesn't
892    # handle Windows line endings
893    ROUNDTRIP_CASES = (
894      # Basic test case
895      "Hi.\nThis is a test.\nTesting.",
896      # Include a blank line
897      "Hi.\nThis is a test.\n\nTesting.",
898      # Include leading and trailing blank lines
899      "\nHi.\nThis is a test.\nTesting.\n",
900    )
901    CASES = ROUNDTRIP_CASES + (
902      # Use Windows line endings
903      "Hi.\r\nThis is a test.\r\nTesting.\r\n",
904      # Pathological case
905      "\nHi.\r\nThis is a test.\n\r\nTesting.\r\n\n",
906    )
907
908    def test_indent_nomargin_default(self):
909        # indent should do nothing if 'prefix' is empty.
910        for text in self.CASES:
911            self.assertEqual(indent(text, ''), text)
912
913    def test_indent_nomargin_explicit_default(self):
914        # The same as test_indent_nomargin, but explicitly requesting
915        # the default behaviour by passing None as the predicate
916        for text in self.CASES:
917            self.assertEqual(indent(text, '', None), text)
918
919    def test_indent_nomargin_all_lines(self):
920        # The same as test_indent_nomargin, but using the optional
921        # predicate argument
922        predicate = lambda line: True
923        for text in self.CASES:
924            self.assertEqual(indent(text, '', predicate), text)
925
926    def test_indent_no_lines(self):
927        # Explicitly skip indenting any lines
928        predicate = lambda line: False
929        for text in self.CASES:
930            self.assertEqual(indent(text, '    ', predicate), text)
931
932    def test_roundtrip_spaces(self):
933        # A whitespace prefix should roundtrip with dedent
934        for text in self.ROUNDTRIP_CASES:
935            self.assertEqual(dedent(indent(text, '    ')), text)
936
937    def test_roundtrip_tabs(self):
938        # A whitespace prefix should roundtrip with dedent
939        for text in self.ROUNDTRIP_CASES:
940            self.assertEqual(dedent(indent(text, '\t\t')), text)
941
942    def test_roundtrip_mixed(self):
943        # A whitespace prefix should roundtrip with dedent
944        for text in self.ROUNDTRIP_CASES:
945            self.assertEqual(dedent(indent(text, ' \t  \t ')), text)
946
947    def test_indent_default(self):
948        # Test default indenting of lines that are not whitespace only
949        prefix = '  '
950        expected = (
951          # Basic test case
952          "  Hi.\n  This is a test.\n  Testing.",
953          # Include a blank line
954          "  Hi.\n  This is a test.\n\n  Testing.",
955          # Include leading and trailing blank lines
956          "\n  Hi.\n  This is a test.\n  Testing.\n",
957          # Use Windows line endings
958          "  Hi.\r\n  This is a test.\r\n  Testing.\r\n",
959          # Pathological case
960          "\n  Hi.\r\n  This is a test.\n\r\n  Testing.\r\n\n",
961        )
962        for text, expect in zip(self.CASES, expected):
963            self.assertEqual(indent(text, prefix), expect)
964
965    def test_indent_explicit_default(self):
966        # Test default indenting of lines that are not whitespace only
967        prefix = '  '
968        expected = (
969          # Basic test case
970          "  Hi.\n  This is a test.\n  Testing.",
971          # Include a blank line
972          "  Hi.\n  This is a test.\n\n  Testing.",
973          # Include leading and trailing blank lines
974          "\n  Hi.\n  This is a test.\n  Testing.\n",
975          # Use Windows line endings
976          "  Hi.\r\n  This is a test.\r\n  Testing.\r\n",
977          # Pathological case
978          "\n  Hi.\r\n  This is a test.\n\r\n  Testing.\r\n\n",
979        )
980        for text, expect in zip(self.CASES, expected):
981            self.assertEqual(indent(text, prefix, None), expect)
982
983    def test_indent_all_lines(self):
984        # Add 'prefix' to all lines, including whitespace-only ones.
985        prefix = '  '
986        expected = (
987          # Basic test case
988          "  Hi.\n  This is a test.\n  Testing.",
989          # Include a blank line
990          "  Hi.\n  This is a test.\n  \n  Testing.",
991          # Include leading and trailing blank lines
992          "  \n  Hi.\n  This is a test.\n  Testing.\n",
993          # Use Windows line endings
994          "  Hi.\r\n  This is a test.\r\n  Testing.\r\n",
995          # Pathological case
996          "  \n  Hi.\r\n  This is a test.\n  \r\n  Testing.\r\n  \n",
997        )
998        predicate = lambda line: True
999        for text, expect in zip(self.CASES, expected):
1000            self.assertEqual(indent(text, prefix, predicate), expect)
1001
1002    def test_indent_empty_lines(self):
1003        # Add 'prefix' solely to whitespace-only lines.
1004        prefix = '  '
1005        expected = (
1006          # Basic test case
1007          "Hi.\nThis is a test.\nTesting.",
1008          # Include a blank line
1009          "Hi.\nThis is a test.\n  \nTesting.",
1010          # Include leading and trailing blank lines
1011          "  \nHi.\nThis is a test.\nTesting.\n",
1012          # Use Windows line endings
1013          "Hi.\r\nThis is a test.\r\nTesting.\r\n",
1014          # Pathological case
1015          "  \nHi.\r\nThis is a test.\n  \r\nTesting.\r\n  \n",
1016        )
1017        predicate = lambda line: not line.strip()
1018        for text, expect in zip(self.CASES, expected):
1019            self.assertEqual(indent(text, prefix, predicate), expect)
1020
1021
1022class ShortenTestCase(BaseTestCase):
1023
1024    def check_shorten(self, text, width, expect, **kwargs):
1025        result = shorten(text, width, **kwargs)
1026        self.check(result, expect)
1027
1028    def test_simple(self):
1029        # Simple case: just words, spaces, and a bit of punctuation
1030        text = "Hello there, how are you this fine day? I'm glad to hear it!"
1031
1032        self.check_shorten(text, 18, "Hello there, [...]")
1033        self.check_shorten(text, len(text), text)
1034        self.check_shorten(text, len(text) - 1,
1035            "Hello there, how are you this fine day? "
1036            "I'm glad to [...]")
1037
1038    def test_placeholder(self):
1039        text = "Hello there, how are you this fine day? I'm glad to hear it!"
1040
1041        self.check_shorten(text, 17, "Hello there,$$", placeholder='$$')
1042        self.check_shorten(text, 18, "Hello there, how$$", placeholder='$$')
1043        self.check_shorten(text, 18, "Hello there, $$", placeholder=' $$')
1044        self.check_shorten(text, len(text), text, placeholder='$$')
1045        self.check_shorten(text, len(text) - 1,
1046            "Hello there, how are you this fine day? "
1047            "I'm glad to hear$$", placeholder='$$')
1048
1049    def test_empty_string(self):
1050        self.check_shorten("", 6, "")
1051
1052    def test_whitespace(self):
1053        # Whitespace collapsing
1054        text = """
1055            This is a  paragraph that  already has
1056            line breaks and \t tabs too."""
1057        self.check_shorten(text, 62,
1058                             "This is a paragraph that already has line "
1059                             "breaks and tabs too.")
1060        self.check_shorten(text, 61,
1061                             "This is a paragraph that already has line "
1062                             "breaks and [...]")
1063
1064        self.check_shorten("hello      world!  ", 12, "hello world!")
1065        self.check_shorten("hello      world!  ", 11, "hello [...]")
1066        # The leading space is trimmed from the placeholder
1067        # (it would be ugly otherwise).
1068        self.check_shorten("hello      world!  ", 10, "[...]")
1069
1070    def test_width_too_small_for_placeholder(self):
1071        shorten("x" * 20, width=8, placeholder="(......)")
1072        with self.assertRaises(ValueError):
1073            shorten("x" * 20, width=8, placeholder="(.......)")
1074
1075    def test_first_word_too_long_but_placeholder_fits(self):
1076        self.check_shorten("Helloo", 5, "[...]")
1077
1078
1079if __name__ == '__main__':
1080    unittest.main()
1081