Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Some disttrial tests which previously depended on specific implementation details of the local/worker protocol are now less dependent on those details.
- Loading branch information
Showing
8 changed files
with
483 additions
and
201 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
""" | ||
Tests for L{twisted.trial._dist.test.matchers}. | ||
""" | ||
|
||
from typing import Callable, Sequence, Tuple, Type | ||
|
||
from hamcrest import anything, assert_that, contains, contains_string, equal_to, not_ | ||
from hamcrest.core.matcher import Matcher | ||
from hamcrest.core.string_description import StringDescription | ||
from hypothesis import given | ||
from hypothesis.strategies import ( | ||
binary, | ||
booleans, | ||
integers, | ||
just, | ||
lists, | ||
one_of, | ||
sampled_from, | ||
text, | ||
tuples, | ||
) | ||
|
||
from twisted.python.failure import Failure | ||
from twisted.trial.unittest import SynchronousTestCase | ||
from .matchers import HasSum, IsSequenceOf, S, isFailure, similarFrame | ||
|
||
Summer = Callable[[Sequence[S]], S] | ||
concatInt = sum | ||
concatStr = "".join | ||
concatBytes = b"".join | ||
|
||
|
||
class HasSumTests(SynchronousTestCase): | ||
""" | ||
Tests for L{HasSum}. | ||
""" | ||
|
||
summables = one_of( | ||
tuples(lists(integers()), just(concatInt)), | ||
tuples(lists(text()), just(concatStr)), | ||
tuples(lists(binary()), just(concatBytes)), | ||
) | ||
|
||
@given(summables) | ||
def test_matches(self, summable: Tuple[Sequence[S], Summer[S]]) -> None: | ||
""" | ||
L{HasSum} matches a sequence if the elements sum to a value matched by | ||
the parameterized matcher. | ||
:param summable: A tuple of a sequence of values to try to match and a | ||
function which can compute the correct sum for that sequence. | ||
""" | ||
seq, sumFunc = summable | ||
expected = sumFunc(seq) | ||
zero = sumFunc([]) | ||
matcher = HasSum(equal_to(expected), zero) | ||
|
||
description = StringDescription() | ||
assert_that(matcher.matches(seq, description), equal_to(True)) | ||
assert_that(str(description), equal_to("")) | ||
|
||
@given(summables) | ||
def test_mismatches( | ||
self, | ||
summable: Tuple[ | ||
Sequence[S], | ||
Summer[S], | ||
], | ||
) -> None: | ||
""" | ||
L{HasSum} does not match a sequence if the elements do not sum to a | ||
value matched by the parameterized matcher. | ||
:param summable: See L{test_matches}. | ||
""" | ||
seq, sumFunc = summable | ||
zero = sumFunc([]) | ||
# A matcher that never matches. | ||
sumMatcher: Matcher[S] = not_(anything()) | ||
matcher = HasSum(sumMatcher, zero) | ||
|
||
actualDescription = StringDescription() | ||
assert_that(matcher.matches(seq, actualDescription), equal_to(False)) | ||
|
||
sumMatcherDescription = StringDescription() | ||
sumMatcherDescription.append_description_of(sumMatcher) | ||
actualStr = str(actualDescription) | ||
assert_that(actualStr, contains_string("a sequence with sum")) | ||
assert_that(actualStr, contains_string(str(sumMatcherDescription))) | ||
|
||
|
||
class IsSequenceOfTests(SynchronousTestCase): | ||
""" | ||
Tests for L{IsSequenceOf}. | ||
""" | ||
|
||
sequences = lists(booleans()) | ||
|
||
@given(integers(min_value=0, max_value=1000)) | ||
def test_matches(self, numItems: int) -> None: | ||
""" | ||
L{IsSequenceOf} matches a sequence if all of the elements are | ||
matched by the parameterized matcher. | ||
:param numItems: The length of a sequence to try to match. | ||
""" | ||
seq = [True] * numItems | ||
matcher = IsSequenceOf(equal_to(True)) | ||
|
||
actualDescription = StringDescription() | ||
assert_that(matcher.matches(seq, actualDescription), equal_to(True)) | ||
assert_that(str(actualDescription), equal_to("")) | ||
|
||
@given(integers(min_value=0, max_value=1000), integers(min_value=0, max_value=1000)) | ||
def test_mismatches(self, numBefore: int, numAfter: int) -> None: | ||
""" | ||
L{IsSequenceOf} does not match a sequence if any of the elements | ||
are not matched by the parameterized matcher. | ||
:param numBefore: In the sequence to try to match, the number of | ||
elements expected to match before an expected mismatch. | ||
:param numAfter: In the sequence to try to match, the number of | ||
elements expected expected to match after an expected mismatch. | ||
""" | ||
# Hide the non-matching value somewhere in the sequence. | ||
seq = [True] * numBefore + [False] + [True] * numAfter | ||
matcher = IsSequenceOf(equal_to(True)) | ||
|
||
actualDescription = StringDescription() | ||
assert_that(matcher.matches(seq, actualDescription), equal_to(False)) | ||
actualStr = str(actualDescription) | ||
assert_that(actualStr, contains_string("a sequence containing only")) | ||
assert_that( | ||
actualStr, contains_string(f"not sequence with element #{numBefore}") | ||
) | ||
|
||
|
||
class IsFailureTests(SynchronousTestCase): | ||
""" | ||
Tests for L{isFailure}. | ||
""" | ||
|
||
@given(sampled_from([ValueError, ZeroDivisionError, RuntimeError])) | ||
def test_matches(self, excType: Type[BaseException]) -> None: | ||
""" | ||
L{isFailure} matches instances of L{Failure} with matching | ||
attributes. | ||
:param excType: An exception type to wrap in a L{Failure} to be | ||
matched against. | ||
""" | ||
matcher = isFailure(type=equal_to(excType)) | ||
failure = Failure(excType()) | ||
assert_that(matcher.matches(failure), equal_to(True)) | ||
|
||
@given(sampled_from([ValueError, ZeroDivisionError, RuntimeError])) | ||
def test_mismatches(self, excType: Type[BaseException]) -> None: | ||
""" | ||
L{isFailure} does not match instances of L{Failure} with | ||
attributes that don't match. | ||
:param excType: An exception type to wrap in a L{Failure} to be | ||
matched against. | ||
""" | ||
matcher = isFailure(type=equal_to(excType), other=not_(anything())) | ||
failure = Failure(excType()) | ||
assert_that(matcher.matches(failure), equal_to(False)) | ||
|
||
def test_frames(self): | ||
""" | ||
The L{similarFrame} matcher matches elements of the C{frames} list | ||
of a L{Failure}. | ||
""" | ||
try: | ||
raise ValueError("Oh no") | ||
except BaseException: | ||
f = Failure() | ||
|
||
actualDescription = StringDescription() | ||
matcher = isFailure( | ||
frames=contains(similarFrame("test_frames", "test_matchers")) | ||
) | ||
assert_that( | ||
matcher.matches(f, actualDescription), | ||
equal_to(True), | ||
actualDescription, | ||
) |
Oops, something went wrong.