Home | History | Annotate | Download | only in test
      1 #

      2 # Test suite for the textwrap module.

      3 #

      4 # Original tests written by Greg Ward <gward (at] python.net>.

      5 # Converted to PyUnit by Peter Hansen <peter (at] engcorp.com>.

      6 # Currently maintained by Greg Ward.

      7 #

      8 # $Id$

      9 #

     10 
     11 import unittest
     12 from test import test_support
     13 
     14 from textwrap import TextWrapper, wrap, fill, dedent
     15 
     16 
     17 class BaseTestCase(unittest.TestCase):
     18     '''Parent class with utility methods for textwrap tests.'''
     19 
     20     def show(self, textin):
     21         if isinstance(textin, list):
     22             result = []
     23             for i in range(len(textin)):
     24                 result.append("  %d: %r" % (i, textin[i]))
     25             result = '\n'.join(result)
     26         elif isinstance(textin, basestring):
     27             result = "  %s\n" % repr(textin)
     28         return result
     29 
     30 
     31     def check(self, result, expect):
     32         self.assertEqual(result, expect,
     33             'expected:\n%s\nbut got:\n%s' % (
     34                 self.show(expect), self.show(result)))
     35 
     36     def check_wrap(self, text, width, expect, **kwargs):
     37         result = wrap(text, width, **kwargs)
     38         self.check(result, expect)
     39 
     40     def check_split(self, text, expect):
     41         result = self.wrapper._split(text)
     42         self.assertEqual(result, expect,
     43                          "\nexpected %r\n"
     44                          "but got  %r" % (expect, result))
     45 
     46 
     47 class WrapTestCase(BaseTestCase):
     48 
     49     def setUp(self):
     50         self.wrapper = TextWrapper(width=45)
     51 
     52     def test_simple(self):
     53         # Simple case: just words, spaces, and a bit of punctuation

     54 
     55         text = "Hello there, how are you this fine day?  I'm glad to hear it!"
     56 
     57         self.check_wrap(text, 12,
     58                         ["Hello there,",
     59                          "how are you",
     60                          "this fine",
     61                          "day?  I'm",
     62                          "glad to hear",
     63                          "it!"])
     64         self.check_wrap(text, 42,
     65                         ["Hello there, how are you this fine day?",
     66                          "I'm glad to hear it!"])
     67         self.check_wrap(text, 80, [text])
     68 
     69 
     70     def test_whitespace(self):
     71         # Whitespace munging and end-of-sentence detection

     72 
     73         text = """\
     74 This is a paragraph that already has
     75 line breaks.  But some of its lines are much longer than the others,
     76 so it needs to be wrapped.
     77 Some lines are \ttabbed too.
     78 What a mess!
     79 """
     80 
     81         expect = ["This is a paragraph that already has line",
     82                   "breaks.  But some of its lines are much",
     83                   "longer than the others, so it needs to be",
     84                   "wrapped.  Some lines are  tabbed too.  What a",
     85                   "mess!"]
     86 
     87         wrapper = TextWrapper(45, fix_sentence_endings=True)
     88         result = wrapper.wrap(text)
     89         self.check(result, expect)
     90 
     91         result = wrapper.fill(text)
     92         self.check(result, '\n'.join(expect))
     93 
     94     def test_fix_sentence_endings(self):
     95         wrapper = TextWrapper(60, fix_sentence_endings=True)
     96 
     97         # SF #847346: ensure that fix_sentence_endings=True does the

     98         # right thing even on input short enough that it doesn't need to

     99         # be wrapped.

    100         text = "A short line. Note the single space."
    101         expect = ["A short line.  Note the single space."]
    102         self.check(wrapper.wrap(text), expect)
    103 
    104         # Test some of the hairy end cases that _fix_sentence_endings()

    105         # is supposed to handle (the easy stuff is tested in

    106         # test_whitespace() above).

    107         text = "Well, Doctor? What do you think?"
    108         expect = ["Well, Doctor?  What do you think?"]
    109         self.check(wrapper.wrap(text), expect)
    110 
    111         text = "Well, Doctor?\nWhat do you think?"
    112         self.check(wrapper.wrap(text), expect)
    113 
    114         text = 'I say, chaps! Anyone for "tennis?"\nHmmph!'
    115         expect = ['I say, chaps!  Anyone for "tennis?"  Hmmph!']
    116         self.check(wrapper.wrap(text), expect)
    117 
    118         wrapper.width = 20
    119         expect = ['I say, chaps!', 'Anyone for "tennis?"', 'Hmmph!']
    120         self.check(wrapper.wrap(text), expect)
    121 
    122         text = 'And she said, "Go to hell!"\nCan you believe that?'
    123         expect = ['And she said, "Go to',
    124                   'hell!"  Can you',
    125                   'believe that?']
    126         self.check(wrapper.wrap(text), expect)
    127 
    128         wrapper.width = 60
    129         expect = ['And she said, "Go to hell!"  Can you believe that?']
    130         self.check(wrapper.wrap(text), expect)
    131 
    132         text = 'File stdio.h is nice.'
    133         expect = ['File stdio.h is nice.']
    134         self.check(wrapper.wrap(text), expect)
    135 
    136     def test_wrap_short(self):
    137         # Wrapping to make short lines longer

    138 
    139         text = "This is a\nshort paragraph."
    140 
    141         self.check_wrap(text, 20, ["This is a short",
    142                                    "paragraph."])
    143         self.check_wrap(text, 40, ["This is a short paragraph."])
    144 
    145 
    146     def test_wrap_short_1line(self):
    147         # Test endcases

    148 
    149         text = "This is a short line."
    150 
    151         self.check_wrap(text, 30, ["This is a short line."])
    152         self.check_wrap(text, 30, ["(1) This is a short line."],
    153                         initial_indent="(1) ")
    154 
    155 
    156     def test_hyphenated(self):
    157         # Test breaking hyphenated words

    158 
    159         text = ("this-is-a-useful-feature-for-"
    160                 "reformatting-posts-from-tim-peters'ly")
    161 
    162         self.check_wrap(text, 40,
    163                         ["this-is-a-useful-feature-for-",
    164                          "reformatting-posts-from-tim-peters'ly"])
    165         self.check_wrap(text, 41,
    166                         ["this-is-a-useful-feature-for-",
    167                          "reformatting-posts-from-tim-peters'ly"])
    168         self.check_wrap(text, 42,
    169                         ["this-is-a-useful-feature-for-reformatting-",
    170                          "posts-from-tim-peters'ly"])
    171 
    172     def test_hyphenated_numbers(self):
    173         # Test that hyphenated numbers (eg. dates) are not broken like words.

    174         text = ("Python 1.0.0 was released on 1994-01-26.  Python 1.0.1 was\n"
    175                 "released on 1994-02-15.")
    176 
    177         self.check_wrap(text, 35, ['Python 1.0.0 was released on',
    178                                    '1994-01-26.  Python 1.0.1 was',
    179                                    'released on 1994-02-15.'])
    180         self.check_wrap(text, 40, ['Python 1.0.0 was released on 1994-01-26.',
    181                                    'Python 1.0.1 was released on 1994-02-15.'])
    182 
    183         text = "I do all my shopping at 7-11."
    184         self.check_wrap(text, 25, ["I do all my shopping at",
    185                                    "7-11."])
    186         self.check_wrap(text, 27, ["I do all my shopping at",
    187                                    "7-11."])
    188         self.check_wrap(text, 29, ["I do all my shopping at 7-11."])
    189 
    190     def test_em_dash(self):
    191         # Test text with em-dashes

    192         text = "Em-dashes should be written -- thus."
    193         self.check_wrap(text, 25,
    194                         ["Em-dashes should be",
    195                          "written -- thus."])
    196 
    197         # Probe the boundaries of the properly written em-dash,

    198         # ie. " -- ".

    199         self.check_wrap(text, 29,
    200                         ["Em-dashes should be written",
    201                          "-- thus."])
    202         expect = ["Em-dashes should be written --",
    203                   "thus."]
    204         self.check_wrap(text, 30, expect)
    205         self.check_wrap(text, 35, expect)
    206         self.check_wrap(text, 36,
    207                         ["Em-dashes should be written -- thus."])
    208 
    209         # The improperly written em-dash is handled too, because

    210         # it's adjacent to non-whitespace on both sides.

    211         text = "You can also do--this or even---this."
    212         expect = ["You can also do",
    213                   "--this or even",
    214                   "---this."]
    215         self.check_wrap(text, 15, expect)
    216         self.check_wrap(text, 16, expect)
    217         expect = ["You can also do--",
    218                   "this or even---",
    219                   "this."]
    220         self.check_wrap(text, 17, expect)
    221         self.check_wrap(text, 19, expect)
    222         expect = ["You can also do--this or even",
    223                   "---this."]
    224         self.check_wrap(text, 29, expect)
    225         self.check_wrap(text, 31, expect)
    226         expect = ["You can also do--this or even---",
    227                   "this."]
    228         self.check_wrap(text, 32, expect)
    229         self.check_wrap(text, 35, expect)
    230 
    231         # All of the above behaviour could be deduced by probing the

    232         # _split() method.

    233         text = "Here's an -- em-dash and--here's another---and another!"
    234         expect = ["Here's", " ", "an", " ", "--", " ", "em-", "dash", " ",
    235                   "and", "--", "here's", " ", "another", "---",
    236                   "and", " ", "another!"]
    237         self.check_split(text, expect)
    238 
    239         text = "and then--bam!--he was gone"
    240         expect = ["and", " ", "then", "--", "bam!", "--",
    241                   "he", " ", "was", " ", "gone"]
    242         self.check_split(text, expect)
    243 
    244 
    245     def test_unix_options (self):
    246         # Test that Unix-style command-line options are wrapped correctly.

    247         # Both Optik (OptionParser) and Docutils rely on this behaviour!

    248 
    249         text = "You should use the -n option, or --dry-run in its long form."
    250         self.check_wrap(text, 20,
    251                         ["You should use the",
    252                          "-n option, or --dry-",
    253                          "run in its long",
    254                          "form."])
    255         self.check_wrap(text, 21,
    256                         ["You should use the -n",
    257                          "option, or --dry-run",
    258                          "in its long form."])
    259         expect = ["You should use the -n option, or",
    260                   "--dry-run in its long form."]
    261         self.check_wrap(text, 32, expect)
    262         self.check_wrap(text, 34, expect)
    263         self.check_wrap(text, 35, expect)
    264         self.check_wrap(text, 38, expect)
    265         expect = ["You should use the -n option, or --dry-",
    266                   "run in its long form."]
    267         self.check_wrap(text, 39, expect)
    268         self.check_wrap(text, 41, expect)
    269         expect = ["You should use the -n option, or --dry-run",
    270                   "in its long form."]
    271         self.check_wrap(text, 42, expect)
    272 
    273         # Again, all of the above can be deduced from _split().

    274         text = "the -n option, or --dry-run or --dryrun"
    275         expect = ["the", " ", "-n", " ", "option,", " ", "or", " ",
    276                   "--dry-", "run", " ", "or", " ", "--dryrun"]
    277         self.check_split(text, expect)
    278 
    279     def test_funky_hyphens (self):
    280         # Screwy edge cases cooked up by David Goodger.  All reported

    281         # in SF bug #596434.

    282         self.check_split("what the--hey!", ["what", " ", "the", "--", "hey!"])
    283         self.check_split("what the--", ["what", " ", "the--"])
    284         self.check_split("what the--.", ["what", " ", "the--."])
    285         self.check_split("--text--.", ["--text--."])
    286 
    287         # When I first read bug #596434, this is what I thought David

    288         # was talking about.  I was wrong; these have always worked

    289         # fine.  The real problem is tested in test_funky_parens()

    290         # below...

    291         self.check_split("--option", ["--option"])
    292         self.check_split("--option-opt", ["--option-", "opt"])
    293         self.check_split("foo --option-opt bar",
    294                          ["foo", " ", "--option-", "opt", " ", "bar"])
    295 
    296     def test_punct_hyphens(self):
    297         # Oh bother, SF #965425 found another problem with hyphens --

    298         # hyphenated words in single quotes weren't handled correctly.

    299         # In fact, the bug is that *any* punctuation around a hyphenated

    300         # word was handled incorrectly, except for a leading "--", which

    301         # was special-cased for Optik and Docutils.  So test a variety

    302         # of styles of punctuation around a hyphenated word.

    303         # (Actually this is based on an Optik bug report, #813077).

    304         self.check_split("the 'wibble-wobble' widget",
    305                          ['the', ' ', "'wibble-", "wobble'", ' ', 'widget'])
    306         self.check_split('the "wibble-wobble" widget',
    307                          ['the', ' ', '"wibble-', 'wobble"', ' ', 'widget'])
    308         self.check_split("the (wibble-wobble) widget",
    309                          ['the', ' ', "(wibble-", "wobble)", ' ', 'widget'])
    310         self.check_split("the ['wibble-wobble'] widget",
    311                          ['the', ' ', "['wibble-", "wobble']", ' ', 'widget'])
    312 
    313     def test_funky_parens (self):
    314         # Second part of SF bug #596434: long option strings inside

    315         # parentheses.

    316         self.check_split("foo (--option) bar",
    317                          ["foo", " ", "(--option)", " ", "bar"])
    318 
    319         # Related stuff -- make sure parens work in simpler contexts.

    320         self.check_split("foo (bar) baz",
    321                          ["foo", " ", "(bar)", " ", "baz"])
    322         self.check_split("blah (ding dong), wubba",
    323                          ["blah", " ", "(ding", " ", "dong),",
    324                           " ", "wubba"])
    325 
    326     def test_initial_whitespace(self):
    327         # SF bug #622849 reported inconsistent handling of leading

    328         # whitespace; let's test that a bit, shall we?

    329         text = " This is a sentence with leading whitespace."
    330         self.check_wrap(text, 50,
    331                         [" This is a sentence with leading whitespace."])
    332         self.check_wrap(text, 30,
    333                         [" This is a sentence with", "leading whitespace."])
    334 
    335     def test_no_drop_whitespace(self):
    336         # SF patch #1581073

    337         text = " This is a    sentence with     much whitespace."
    338         self.check_wrap(text, 10,
    339                         [" This is a", "    ", "sentence ",
    340                          "with     ", "much white", "space."],
    341                         drop_whitespace=False)
    342 
    343     if test_support.have_unicode:
    344         def test_unicode(self):
    345             # *Very* simple test of wrapping Unicode strings.  I'm sure

    346             # there's more to it than this, but let's at least make

    347             # sure textwrap doesn't crash on Unicode input!

    348             text = u"Hello there, how are you today?"
    349             self.check_wrap(text, 50, [u"Hello there, how are you today?"])
    350             self.check_wrap(text, 20, [u"Hello there, how are", "you today?"])
    351             olines = self.wrapper.wrap(text)
    352             self.assertIsInstance(olines, list)
    353             self.assertIsInstance(olines[0], unicode)
    354             otext = self.wrapper.fill(text)
    355             self.assertIsInstance(otext, unicode)
    356 
    357         def test_no_split_at_umlaut(self):
    358             text = u"Die Empf\xe4nger-Auswahl"
    359             self.check_wrap(text, 13, [u"Die", u"Empf\xe4nger-", u"Auswahl"])
    360 
    361         def test_umlaut_followed_by_dash(self):
    362             text = u"aa \xe4\xe4-\xe4\xe4"
    363             self.check_wrap(text, 7, [u"aa \xe4\xe4-", u"\xe4\xe4"])
    364 
    365     def test_split(self):
    366         # Ensure that the standard _split() method works as advertised

    367         # in the comments

    368 
    369         text = "Hello there -- you goof-ball, use the -b option!"
    370 
    371         result = self.wrapper._split(text)
    372         self.check(result,
    373              ["Hello", " ", "there", " ", "--", " ", "you", " ", "goof-",
    374               "ball,", " ", "use", " ", "the", " ", "-b", " ",  "option!"])
    375 
    376     def test_break_on_hyphens(self):
    377         # Ensure that the break_on_hyphens attributes work

    378         text = "yaba daba-doo"
    379         self.check_wrap(text, 10, ["yaba daba-", "doo"],
    380                         break_on_hyphens=True)
    381         self.check_wrap(text, 10, ["yaba", "daba-doo"],
    382                         break_on_hyphens=False)
    383 
    384     def test_bad_width(self):
    385         # Ensure that width <= 0 is caught.

    386         text = "Whatever, it doesn't matter."
    387         self.assertRaises(ValueError, wrap, text, 0)
    388         self.assertRaises(ValueError, wrap, text, -1)
    389 
    390 
    391 class LongWordTestCase (BaseTestCase):
    392     def setUp(self):
    393         self.wrapper = TextWrapper()
    394         self.text = '''\
    395 Did you say "supercalifragilisticexpialidocious?"
    396 How *do* you spell that odd word, anyways?
    397 '''
    398 
    399     def test_break_long(self):
    400         # Wrap text with long words and lots of punctuation

    401 
    402         self.check_wrap(self.text, 30,
    403                         ['Did you say "supercalifragilis',
    404                          'ticexpialidocious?" How *do*',
    405                          'you spell that odd word,',
    406                          'anyways?'])
    407         self.check_wrap(self.text, 50,
    408                         ['Did you say "supercalifragilisticexpialidocious?"',
    409                          'How *do* you spell that odd word, anyways?'])
    410 
    411         # SF bug 797650.  Prevent an infinite loop by making sure that at

    412         # least one character gets split off on every pass.

    413         self.check_wrap('-'*10+'hello', 10,
    414                         ['----------',
    415                          '               h',
    416                          '               e',
    417                          '               l',
    418                          '               l',
    419                          '               o'],
    420                         subsequent_indent = ' '*15)
    421 
    422         # bug 1146.  Prevent a long word to be wrongly wrapped when the

    423         # preceding word is exactly one character shorter than the width

    424         self.check_wrap(self.text, 12,
    425                         ['Did you say ',
    426                          '"supercalifr',
    427                          'agilisticexp',
    428                          'ialidocious?',
    429                          '" How *do*',
    430                          'you spell',
    431                          'that odd',
    432                          'word,',
    433                          'anyways?'])
    434 
    435     def test_nobreak_long(self):
    436         # Test with break_long_words disabled

    437         self.wrapper.break_long_words = 0
    438         self.wrapper.width = 30
    439         expect = ['Did you say',
    440                   '"supercalifragilisticexpialidocious?"',
    441                   'How *do* you spell that odd',
    442                   'word, anyways?'
    443                   ]
    444         result = self.wrapper.wrap(self.text)
    445         self.check(result, expect)
    446 
    447         # Same thing with kwargs passed to standalone wrap() function.

    448         result = wrap(self.text, width=30, break_long_words=0)
    449         self.check(result, expect)
    450 
    451 
    452 class IndentTestCases(BaseTestCase):
    453 
    454     # called before each test method

    455     def setUp(self):
    456         self.text = '''\
    457 This paragraph will be filled, first without any indentation,
    458 and then with some (including a hanging indent).'''
    459 
    460 
    461     def test_fill(self):
    462         # Test the fill() method

    463 
    464         expect = '''\
    465 This paragraph will be filled, first
    466 without any indentation, and then with
    467 some (including a hanging indent).'''
    468 
    469         result = fill(self.text, 40)
    470         self.check(result, expect)
    471 
    472 
    473     def test_initial_indent(self):
    474         # Test initial_indent parameter

    475 
    476         expect = ["     This paragraph will be filled,",
    477                   "first without any indentation, and then",
    478                   "with some (including a hanging indent)."]
    479         result = wrap(self.text, 40, initial_indent="     ")
    480         self.check(result, expect)
    481 
    482         expect = "\n".join(expect)
    483         result = fill(self.text, 40, initial_indent="     ")
    484         self.check(result, expect)
    485 
    486 
    487     def test_subsequent_indent(self):
    488         # Test subsequent_indent parameter

    489 
    490         expect = '''\
    491   * This paragraph will be filled, first
    492     without any indentation, and then
    493     with some (including a hanging
    494     indent).'''
    495 
    496         result = fill(self.text, 40,
    497                       initial_indent="  * ", subsequent_indent="    ")
    498         self.check(result, expect)
    499 
    500 
    501 # Despite the similar names, DedentTestCase is *not* the inverse

    502 # of IndentTestCase!

    503 class DedentTestCase(unittest.TestCase):
    504 
    505     def assertUnchanged(self, text):
    506         """assert that dedent() has no effect on 'text'"""
    507         self.assertEqual(text, dedent(text))
    508 
    509     def test_dedent_nomargin(self):
    510         # No lines indented.

    511         text = "Hello there.\nHow are you?\nOh good, I'm glad."
    512         self.assertUnchanged(text)
    513 
    514         # Similar, with a blank line.

    515         text = "Hello there.\n\nBoo!"
    516         self.assertUnchanged(text)
    517 
    518         # Some lines indented, but overall margin is still zero.

    519         text = "Hello there.\n  This is indented."
    520         self.assertUnchanged(text)
    521 
    522         # Again, add a blank line.

    523         text = "Hello there.\n\n  Boo!\n"
    524         self.assertUnchanged(text)
    525 
    526     def test_dedent_even(self):
    527         # All lines indented by two spaces.

    528         text = "  Hello there.\n  How are ya?\n  Oh good."
    529         expect = "Hello there.\nHow are ya?\nOh good."
    530         self.assertEqual(expect, dedent(text))
    531 
    532         # Same, with blank lines.

    533         text = "  Hello there.\n\n  How are ya?\n  Oh good.\n"
    534         expect = "Hello there.\n\nHow are ya?\nOh good.\n"
    535         self.assertEqual(expect, dedent(text))
    536 
    537         # Now indent one of the blank lines.

    538         text = "  Hello there.\n  \n  How are ya?\n  Oh good.\n"
    539         expect = "Hello there.\n\nHow are ya?\nOh good.\n"
    540         self.assertEqual(expect, dedent(text))
    541 
    542     def test_dedent_uneven(self):
    543         # Lines indented unevenly.

    544         text = '''\
    545         def foo():
    546             while 1:
    547                 return foo
    548         '''
    549         expect = '''\
    550 def foo():
    551     while 1:
    552         return foo
    553 '''
    554         self.assertEqual(expect, dedent(text))
    555 
    556         # Uneven indentation with a blank line.

    557         text = "  Foo\n    Bar\n\n   Baz\n"
    558         expect = "Foo\n  Bar\n\n Baz\n"
    559         self.assertEqual(expect, dedent(text))
    560 
    561         # Uneven indentation with a whitespace-only line.

    562         text = "  Foo\n    Bar\n \n   Baz\n"
    563         expect = "Foo\n  Bar\n\n Baz\n"
    564         self.assertEqual(expect, dedent(text))
    565 
    566     # dedent() should not mangle internal tabs

    567     def test_dedent_preserve_internal_tabs(self):
    568         text = "  hello\tthere\n  how are\tyou?"
    569         expect = "hello\tthere\nhow are\tyou?"
    570         self.assertEqual(expect, dedent(text))
    571 
    572         # make sure that it preserves tabs when it's not making any

    573         # changes at all

    574         self.assertEqual(expect, dedent(expect))
    575 
    576     # dedent() should not mangle tabs in the margin (i.e.

    577     # tabs and spaces both count as margin, but are *not*

    578     # considered equivalent)

    579     def test_dedent_preserve_margin_tabs(self):
    580         text = "  hello there\n\thow are you?"
    581         self.assertUnchanged(text)
    582 
    583         # same effect even if we have 8 spaces

    584         text = "        hello there\n\thow are you?"
    585         self.assertUnchanged(text)
    586 
    587         # dedent() only removes whitespace that can be uniformly removed!

    588         text = "\thello there\n\thow are you?"
    589         expect = "hello there\nhow are you?"
    590         self.assertEqual(expect, dedent(text))
    591 
    592         text = "  \thello there\n  \thow are you?"
    593         self.assertEqual(expect, dedent(text))
    594 
    595         text = "  \t  hello there\n  \t  how are you?"
    596         self.assertEqual(expect, dedent(text))
    597 
    598         text = "  \thello there\n  \t  how are you?"
    599         expect = "hello there\n  how are you?"
    600         self.assertEqual(expect, dedent(text))
    601 
    602 
    603 def test_main():
    604     test_support.run_unittest(WrapTestCase,
    605                               LongWordTestCase,
    606                               IndentTestCases,
    607                               DedentTestCase)
    608 
    609 if __name__ == '__main__':
    610     test_main()
    611