From 1cf3aa6e6615dcddc58e42d4fb214f9e0d90d22c Mon Sep 17 00:00:00 2001 From: Tim Peters Date: Thu, 19 Aug 2004 06:49:33 +0000 Subject: ELLIPSIS implementation: an ellipsis couldn't match nothing if it appeared at the end of a line. Repaired that. Also noted that it's too easy to provoke this implementation into requiring exponential time, and especially when a test fails. I'll replace the implementation with an always-efficient one later. --- Lib/doctest.py | 12 ++++++++---- Lib/test/test_doctest.py | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/Lib/doctest.py b/Lib/doctest.py index c033b0d..f7b29d3 100644 --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -1468,7 +1468,7 @@ class OutputChecker: # This flag causes doctest to ignore any differences in the # contents of whitespace strings. Note that this can be used # in conjunction with the ELLISPIS flag. - if (optionflags & NORMALIZE_WHITESPACE): + if optionflags & NORMALIZE_WHITESPACE: got = ' '.join(got.split()) want = ' '.join(want.split()) if got == want: @@ -1477,10 +1477,14 @@ class OutputChecker: # The ELLIPSIS flag says to let the sequence "..." in `want` # match any substring in `got`. We implement this by # transforming `want` into a regular expression. - if (optionflags & ELLIPSIS): + if optionflags & ELLIPSIS: + # Remove \n from ...\n, else the newline will be required, + # and (for example) ... on a line by itself can't match + # nothing gracefully. + want_re = want.replace(ELLIPSIS_MARKER + '\n', ELLIPSIS_MARKER) # Escape any special regexp characters - want_re = re.escape(want) - # Replace ellipsis markers ('...') with .* + want_re = re.escape(want_re) + # Replace escaped ellipsis markers ('\.\.\.') with .* want_re = want_re.replace(re.escape(ELLIPSIS_MARKER), '.*') # Require that it matches the entire string; and set the # re.DOTALL flag (with '(?s)'). diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py index dec9110..d49e6cf 100644 --- a/Lib/test/test_doctest.py +++ b/Lib/test/test_doctest.py @@ -780,6 +780,29 @@ output to match any substring in the actual output: >>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) (0, 1) +... should also match nothing gracefully: +XXX This can be provoked into requiring exponential time by adding more +XXX ellipses; the implementation should change. It's much easier to +XXX provoke exponential time with expected output that doesn't match, +XXX BTW (then multiple regexp .* thingies each try all possiblities, +XXX multiplicatively, without hope of success). That's the real danger, +XXX that a failing test will appear to be hung. + + >>> for i in range(100): + ... print i**2 #doctest: +ELLIPSIS + 0 + ... + 1 + ... + 36 + ... + ... + 49 + 64 + ...... + 9801 + ... + The UNIFIED_DIFF flag causes failures that involve multi-line expected and actual outputs to be displayed using a unified diff: -- cgit v0.12