Repository navigation
Conversation
7f30bad to
61e55a2
Compare
|
Thanks for finding this. I actually thought I had observed that case during those previous changes, but I must be mis-remembering. Either that, or there's an open issue I can't find ;) I'll have to look in to the hypothesis stuff...looking at it without understanding hypothesis it is completely opaque to me what exactly it is testing. As for the encoded word bug, please separate that out into a new issue. If/how to fix it should be a separate discussion. I prefer not to add "expected failure" tests. |
61e55a2 to
1cb3b3b
Compare
|
Done: the expected failure is removed from this PR and filed separately as #160148, with the test included in the issue text for reference. The branch now has only the infinite loop fix, its regression test, and the round-trip property (plus a comment pointing at #160148 for why the strategy avoids encoded-word look-alikes). On the Hypothesis test: it generates subjects from a small set of pieces (words, whitespace runs, RFC 5322 specials, 2/3/4-byte characters, |
…sis stubs Hypothesis lets a test pin a known-failing input with `@example(...).xfail(reason=..., raises=...)`, which is the natural way to record a bug found by a property test without taking the input out of the strategy or writing a separate expectedFailure test. The stub `example` is a plain decorator function, so any test using `.xfail()` or `.via()` failed to import when Hypothesis is not installed. This turns the stub into a class with those two methods. An expected failure is strict, as in Hypothesis: when the examples are replayed the test must raise one of the `raises` exceptions for that input, and an unexpected pass fails the test. `.via()` is a no-op, as it is upstream.
…he line When an encoded word does not fit in the remaining space of a line, _fold_as_ew shrinks the chunk being encoded one character at a time until it fits. Nothing stops it from shrinking the chunk to nothing, and an empty chunk makes no progress: the loop appends an empty encoded word and a new continuation line forever. This is reachable whenever a single character's encoded form is wider than a fresh continuation line, e.g. any character outside the BMP with max_line_length=20 (the q-encoded word is 24 characters). The two earlier fixes in this area (bpo-33529, bpo-36564) handled lines too short for the RFC 2047 chrome, but not lines too short for the chrome plus one character. This keeps at least one character in the chunk, so the loop always advances and the line runs over max_line_length instead. That matches what _refold_parse_tree already does when it cannot fold a part at all, and avoids raising for widths that work for every other input. The regression test pins the exact output, as the earlier two did. The Hypothesis property checks that folding any unstructured value at any width either raises HeaderParseError (only possible at widths of 13 or fewer, where no encoded word fits) or reparses to the same value modulo leading whitespace, which the parser drops.
…ok-alikes The round trip property cannot cover text that is itself a well-formed encoded word, because such text is written out unencoded and decodes to something else on reparse. That is now tracked separately as pythongh-160148, so point at it from the strategy rather than carrying an expected failure here.
…the round trip The folding round-trip strategy cannot produce a well-formed encoded word, because such text is written out verbatim and decoded on reparse (pythongh-160148), and until now the only record of that in the test was a comment. With example.xfail() in the stubs (pythongh-160356), three such subjects are now expected-failure examples on the round-trip test, so the test fails again once pythongh-160148 is resolved and the carve-out can go.
1cb3b3b to
c3d690e
Compare
|
@bitdancer After #160356, it's possible to simply add expected failures directly inline on the test, so I've added back in the expected failure for #160148 since that's cleaner than trying to explicitly carve it out of the test as a separate test of its own. (GH doesn't allow stacks from forks, so this PR has #160356 as a base, annoyingly, but when that is merged this will look more normal). |
Stacked on #160356 (
example.xfail()in the stubs); only the top three commits are new here.When an encoded word does not fit in the remaining space of a line,
_fold_as_ewshrinks the chunk being encoded one character at a time until it fits. Nothing stops it from shrinking the chunk to nothing, and an empty chunk makes no progress: the loop appends an empty encoded word and a new continuation line forever.This is reachable whenever a single character's encoded form is wider than a fresh continuation line, e.g. any character outside the BMP at
max_line_length=20(the q-encoded word is 24 characters). The two earlier fixes in this area (bpo-33529, bpo-36564) handled lines too short for the RFC 2047 chrome, but not lines too short for the chrome plus one character.The fix keeps at least one character in the chunk, so the loop always advances and the line runs over
max_line_lengthinstead. That matches what_refold_parse_treealready does when it cannot fold a part at all, and avoids raising for widths that work for every other input.Tests, next to the two earlier infinite-loop regressions in
test_policy.py:None) either raisesHeaderParseError(only possible at widths of 13 or fewer, where no encoded word fits) or reparses to the same value modulo leading whitespace, which the parser drops. 100 examples take about 0.2 s; the explicit examples replay under the stubs.@example(...).xfail(reason="gh-160148"), which is strict in both modes, so the test fails again once that is resolved.