Ticket #14276: 14276.patch

File 14276.patch, 5.7 KB (added by roed, 9 years ago)
  • doc/en/developer/conventions.rst

    # HG changeset patch
    # User David Roe <roed.math@gmail.com>
    # Date 1363323961 21600
    # Node ID f147e60a82181792d3b8b59e90958b7c66dd50ff
    # Parent  e6706131e8949d0248e0ebb8df7232c3ff62a4e8
    Add a "# require failure" flag for doctests.
    
    diff --git a/doc/en/developer/conventions.rst b/doc/en/developer/conventions.rst
    a b  
    914914``todo: not implemented``, one can use the results of such a search to
    915915direct further development on Sage.
    916916
     917- Alternatively, you can mark a known bug as ``require failure``.
     918  This way if the test ever starts working (due to some change
     919  elsewhere in Sage), the test will fail.  The ``require failure`` tag
     920  may then be removed, and a later regression would be revealed.  For
     921  example::
     922
     923      sage: 1 + 1 # require failure: if this is ever 17 we want to know!
     924      17
     925
    917926- Some tests (hashing for example) behave differently on 32-bit and
    918927  64-bit platforms.  You can mark a line (generally the output) with
    919928  either ``# 32-bit`` or ``# 64-bit`` and the testing framework will
  • sage/doctest/forker.py

    diff --git a/sage/doctest/forker.py b/sage/doctest/forker.py
    a b  
    470470                if check(example.want, got, self.optionflags):
    471471                    outcome = SUCCESS
    472472
     473            # If we wanted failure then an exception can still succeed
     474            elif hasattr(example.want, 'require_failure') and example.want.require_failure:
     475                if check(example.want, got, self.optionflags):
     476                    outcome = SUCCESS
     477
    473478            # The example raised an exception: check if it was expected.
    474479            else:
    475480                exc_info = sys.exc_info()
  • sage/doctest/parsing.py

    diff --git a/sage/doctest/parsing.py b/sage/doctest/parsing.py
    a b  
    2929find_sage_prompt = re.compile(r"^(\s*)sage: ", re.M)
    3030find_sage_continuation = re.compile(r"^(\s*)\.\.\.\.:", re.M)
    3131random_marker = re.compile('.*random', re.I)
     32expect_failure_marker = re.compile('.*require failure', re.I)
    3233tolerance_pattern = re.compile(r'\b((?:abs(?:olute)?)|(?:rel(?:ative)?))? *?tol(?:erance)?\b( +[0-9.e+-]+)?')
    3334backslash_replacer = re.compile(r"""(\s*)sage:(.*)\\\ *
    3435\ *(((\.){4}:)|((\.){3}))?\ *""")
     
    144145                want = MarkedOutput(want).update(abs_tol=epsilon)
    145146            else:
    146147                raise RuntimeError
     148        if expect_failure_marker.search(comment):
     149            if not isinstance(want, MarkedOutput):
     150                want = MarkedOutput(want)
     151            want.update(require_failure=True)
    147152    return want
    148153
    149154def pre_hash(s):
     
    217222        0.0500000000000000
    218223    """
    219224    random = False
     225    require_failure = False
    220226    rel_tol = 0
    221227    abs_tol = 0
    222228    tol = 0
     
    662668            -0.5
    663669            sage: print "1.000009"   # abs tol 1e-5
    664670            1.0
     671
     672        Check the ``require failure`` option::
     673
     674            sage: 1 + 1 # require failure
     675            17
     676            sage: 1 / 0 # require failure
     677            Infinity
    665678        """
     679        ok = None
    666680        if isinstance(want, MarkedOutput):
    667681            if want.random:
    668682                return True
     
    676690                want_values = [float(g[0]) for g in float_regex.findall(want)]
    677691                got_values = [float(g[0]) for g in float_regex.findall(got)]
    678692                if len(want_values) != len(got_values):
    679                     return False
     693                    ok = False
    680694                if not doctest.OutputChecker.check_output(self,
    681695                        float_regex.sub('*', want), float_regex.sub('*', got), optionflags):
    682                     return False
    683                 return all(check_tol(*ab) for ab in zip(want_values, got_values))
    684         ok = doctest.OutputChecker.check_output(self, want, got, optionflags)
    685         #sys.stderr.write(str(ok) + " want: " + repr(want) + " got: " + repr(got) + "\n")
    686         return ok
     696                    ok = False
     697                else:
     698                    ok = all(check_tol(*ab) for ab in zip(want_values, got_values))
     699        if ok is None:
     700            ok = doctest.OutputChecker.check_output(self, want, got, optionflags)
     701        if isinstance(want, MarkedOutput) and want.require_failure:
     702            return not ok
     703        else:
     704            return ok
    687705
    688706    def output_difference(self, example, got, optionflags):
    689707        r"""
     
    850868                else:
    851869                    diff += "Tolerance exceeded in %s of %s\n"%(len(fails), len(want_values))
    852870                    diff += "\n".join(fails[:3]) + "\n"
     871        elif isinstance(want, MarkedOutput) and want.require_failure:
     872            if got:
     873                return 'Expected failure, but answer was correct.\nGot:\n%s'%(doctest._indent(got))
     874            else:
     875                return 'Expected failure, but answer was correct.\nGot nothing\n'
    853876        return diff
  • sage/doctest/reporting.py

    diff --git a/sage/doctest/reporting.py b/sage/doctest/reporting.py
    a b  
    401401                            pass
    402402                        else:
    403403                            if self.controller.options.optional is not True: # if True we test all optional tags
     404                                untested = optionals.pop("not tested",0) + optionals.pop("not implemented",0)
    404405                                tags = sorted(optionals.keys())
    405                                 untested = optionals.pop("not tested",0) + optionals.pop("not implemented",0)
    406406                                seen_other = False
    407407                                for tag in tags:
    408408                                    nskipped = optionals[tag]